blob: d5248a55e7add97334d47e2695fa1d9d9b390348 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.roots.ui.configuration.projectRoot;
import com.intellij.facet.*;
import com.intellij.facet.impl.invalid.InvalidFacetManager;
import com.intellij.facet.impl.invalid.InvalidFacetType;
import com.intellij.facet.impl.ui.facetType.FacetTypeEditor;
import com.intellij.facet.ui.FacetEditor;
import com.intellij.facet.ui.MultipleFacetSettingsEditor;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable;
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.FacetProjectStructureElement;
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
import com.intellij.openapi.ui.DetailsComponent;
import com.intellij.openapi.ui.NamedConfigurable;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.TreeCellRenderer;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.*;
import java.util.List;
/**
* @author nik
*/
public class FacetStructureConfigurable extends BaseStructureConfigurable {
private final ModuleManager myModuleManager;
private final Map<FacetType<?, ?>, FacetTypeEditor> myFacetTypeEditors = new HashMap<FacetType<?,?>, FacetTypeEditor>();
private MultipleFacetSettingsEditor myCurrentMultipleSettingsEditor;
@NonNls private static final String NO_FRAMEWORKS_NODE = "No facets are configured";
private boolean myTreeWasInitialized;
public FacetStructureConfigurable(final Project project, ModuleManager moduleManager) {
super(project);
myModuleManager = moduleManager;
}
@Override
protected String getComponentStateKey() {
return "FacetStructureConfigurable.UI";
}
public static FacetStructureConfigurable getInstance(final @NotNull Project project) {
return ServiceManager.getService(project, FacetStructureConfigurable.class);
}
public boolean isVisible() {
return FacetTypeRegistry.getInstance().getFacetTypes().length > 0 || !InvalidFacetManager.getInstance(myProject).getInvalidFacets().isEmpty();
}
@Override
protected void initTree() {
super.initTree();
if (!myTreeWasInitialized) {
myTreeWasInitialized = true;
final FacetsTreeCellRenderer separatorRenderer = new FacetsTreeCellRenderer();
final TreeCellRenderer oldRenderer = myTree.getCellRenderer();
myTree.setCellRenderer(new TreeCellRenderer() {
@Override
public Component getTreeCellRendererComponent(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
if (value instanceof MyNode && ((MyNode)value).getConfigurable() instanceof FrameworkDetectionConfigurable) {
return separatorRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
}
return oldRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
}
});
myTree.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
revalidateTree();
}
@Override
public void componentMoved(ComponentEvent e) {
revalidateTree();
}
@Override
public void componentShown(ComponentEvent e) {
revalidateTree();
}
});
}
}
private void revalidateTree() {
FilteringTreeBuilder.revalidateTree(myTree);
}
@Override
protected void loadTree() {
myTree.setRootVisible(false);
myTree.setShowsRootHandles(false);
boolean hasFacetTypeNodes = false;
for (FacetType<?,?> facetType : FacetTypeRegistry.getInstance().getFacetTypes()) {
if (ProjectFacetManager.getInstance(myProject).hasFacets(facetType.getId())) {
hasFacetTypeNodes = true;
addFacetTypeNode(facetType);
}
}
if (!InvalidFacetManager.getInstance(myProject).getInvalidFacets().isEmpty()) {
hasFacetTypeNodes = true;
addFacetTypeNode(InvalidFacetType.getInstance());
}
if (!hasFacetTypeNodes) {
addNode(new MyNode(new TextConfigurable<String>(NO_FRAMEWORKS_NODE, NO_FRAMEWORKS_NODE, "Facets", "Press '+' button to add a new facet",
null)), myRoot);
}
addNode(new MyNode(new FrameworkDetectionConfigurable(myProject)), myRoot);
}
@Override
protected Comparator<MyNode> getNodeComparator() {
return new Comparator<MyNode>() {
@Override
public int compare(MyNode node1, MyNode node2) {
final NamedConfigurable c1 = node1.getConfigurable();
final NamedConfigurable c2 = node2.getConfigurable();
if (c1 instanceof FrameworkDetectionConfigurable && !(c2 instanceof FrameworkDetectionConfigurable)) return 1;
if (!(c1 instanceof FrameworkDetectionConfigurable) && c2 instanceof FrameworkDetectionConfigurable) return -1;
return StringUtil.naturalCompare(node1.getDisplayName(), node2.getDisplayName());
}
};
}
private MyNode addFacetTypeNode(FacetType<?, ?> facetType) {
final MyNode noFrameworksNode = findNodeByObject(myRoot, NO_FRAMEWORKS_NODE);
if (noFrameworksNode != null) {
removePaths(TreeUtil.getPathFromRoot(noFrameworksNode));
}
FacetTypeConfigurable facetTypeConfigurable = new FacetTypeConfigurable(this, facetType);
MyNode facetTypeNode = new MyNode(facetTypeConfigurable);
addNode(facetTypeNode, myRoot);
for (Module module : myModuleManager.getModules()) {
Collection<? extends Facet> facets = FacetManager.getInstance(module).getFacetsByType(facetType.getId());
FacetEditorFacadeImpl editorFacade = ModuleStructureConfigurable.getInstance(myProject).getFacetEditorFacade();
for (Facet facet : facets) {
addFacetNode(facetTypeNode, facet, editorFacade);
}
}
return facetTypeNode;
}
@NotNull
@Override
protected Collection<? extends ProjectStructureElement> getProjectStructureElements() {
List<ProjectStructureElement> elements = new ArrayList<ProjectStructureElement>();
for (Module module : myModuleManager.getModules()) {
Facet[] facets = FacetManager.getInstance(module).getAllFacets();
for (Facet facet : facets) {
elements.add(new FacetProjectStructureElement(myContext, facet));
}
}
return elements;
}
public MyNode getOrCreateFacetTypeNode(FacetType facetType) {
final MyNode node = findNodeByObject(myRoot, facetType);
if (node != null) {
return node;
}
return addFacetTypeNode(facetType);
}
public void addFacetNode(@NotNull MyNode facetTypeNode, @NotNull Facet facet, @NotNull FacetEditorFacadeImpl editorFacade) {
FacetConfigurable facetConfigurable = editorFacade.getOrCreateConfigurable(facet);
addNode(new FacetConfigurableNode(facetConfigurable), facetTypeNode);
myContext.getDaemonAnalyzer().queueUpdate(new FacetProjectStructureElement(myContext, facet));
}
@Nullable
public FacetTypeEditor getFacetTypeEditor(@NotNull FacetType<?, ?> facetType) {
return myFacetTypeEditors.get(facetType);
}
public FacetTypeEditor getOrCreateFacetTypeEditor(@NotNull FacetType<?, ?> facetType) {
FacetTypeEditor editor = myFacetTypeEditors.get(facetType);
if (editor == null) {
editor = new FacetTypeEditor(myProject, myContext, facetType);
editor.reset();
myFacetTypeEditors.put(facetType, editor);
}
return editor;
}
@Override
public void reset() {
myFacetTypeEditors.clear();
super.reset();
TreeUtil.expandAll(myTree);
}
@Override
public void apply() throws ConfigurationException {
super.apply();
for (FacetTypeEditor editor : myFacetTypeEditors.values()) {
editor.apply();
}
}
@Override
public boolean isModified() {
return super.isModified() || isEditorsModified();
}
private boolean isEditorsModified() {
for (FacetTypeEditor editor : myFacetTypeEditors.values()) {
if (editor.isModified()) {
return true;
}
}
return false;
}
@Override
public void disposeUIResources() {
super.disposeUIResources();
for (FacetTypeEditor editor : myFacetTypeEditors.values()) {
editor.disposeUIResources();
}
myFacetTypeEditors.clear();
}
@Override
@NotNull
protected ArrayList<AnAction> createActions(final boolean fromPopup) {
ArrayList<AnAction> actions = new ArrayList<AnAction>();
actions.add(new AbstractAddGroup("Add") {
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
return AddFacetOfTypeAction.createAddFacetActions(FacetStructureConfigurable.this);
}
});
if (fromPopup) {
actions.add(new MyNavigateAction());
}
actions.add(new MyRemoveAction());
if (fromPopup || !(Registry.is("ide.new.project.settings"))) {
actions.add(Separator.getInstance());
addCollapseExpandActions(actions);
}
return actions;
}
@Override
protected List<Facet> removeFacet(final Facet facet) {
List<Facet> removed = super.removeFacet(facet);
ModuleStructureConfigurable.getInstance(myProject).removeFacetNodes(removed);
for (Facet removedFacet : removed) {
myContext.getDaemonAnalyzer().removeElement(new FacetProjectStructureElement(myContext, removedFacet));
}
return removed;
}
@Override
protected boolean updateMultiSelection(final List<NamedConfigurable> selectedConfigurables) {
return updateMultiSelection(selectedConfigurables, getDetailsComponent());
}
public boolean updateMultiSelection(final List<NamedConfigurable> selectedConfigurables, final DetailsComponent detailsComponent) {
FacetType selectedFacetType = null;
List<FacetEditor> facetEditors = new ArrayList<FacetEditor>();
for (NamedConfigurable selectedConfigurable : selectedConfigurables) {
if (selectedConfigurable instanceof FacetConfigurable) {
FacetConfigurable facetConfigurable = (FacetConfigurable)selectedConfigurable;
FacetType facetType = facetConfigurable.getEditableObject().getType();
if (selectedFacetType != null && selectedFacetType != facetType) {
return false;
}
selectedFacetType = facetType;
facetEditors.add(facetConfigurable.getEditor());
}
}
if (facetEditors.size() <= 1 || selectedFacetType == null) {
return false;
}
FacetEditor[] selectedEditors = facetEditors.toArray(new FacetEditor[facetEditors.size()]);
MultipleFacetSettingsEditor editor = selectedFacetType.createMultipleConfigurationsEditor(myProject, selectedEditors);
if (editor == null) {
return false;
}
setSelectedNode(null);
myCurrentMultipleSettingsEditor = editor;
detailsComponent.setText(ProjectBundle.message("multiple.facets.banner.0.1.facets", selectedEditors.length,
selectedFacetType.getPresentableName()));
detailsComponent.setContent(editor.createComponent());
return true;
}
@Override
protected void updateSelection(@Nullable final NamedConfigurable configurable) {
disposeMultipleSettingsEditor();
if (configurable instanceof FacetTypeConfigurable) {
((FacetTypeConfigurable)configurable).updateComponent();
}
super.updateSelection(configurable);
}
public void disposeMultipleSettingsEditor() {
if (myCurrentMultipleSettingsEditor != null) {
myCurrentMultipleSettingsEditor.disposeUIResources();
myCurrentMultipleSettingsEditor = null;
}
}
@Override
@Nullable
protected AbstractAddGroup createAddAction() {
return null;
}
@Override
protected void processRemovedItems() {
}
@Override
protected boolean wasObjectStored(final Object editableObject) {
return false;
}
@Override
public String getDisplayName() {
return ProjectBundle.message("project.facets.display.name");
}
@Override
public String getHelpTopic() {
final Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(DataManager.getInstance().getDataContext());
if (myTree.equals(component)) {
final NamedConfigurable selectedConfigurable = getSelectedConfigurable();
if (selectedConfigurable instanceof FacetTypeConfigurable) {
final FacetType facetType = ((FacetTypeConfigurable)selectedConfigurable).getEditableObject();
final String topic = facetType.getHelpTopic();
if (topic != null) {
return topic;
}
}
}
if (myCurrentMultipleSettingsEditor != null) {
final String topic = myCurrentMultipleSettingsEditor.getHelpTopic();
if (topic != null) {
return topic;
}
}
String topic = super.getHelpTopic();
if (topic != null) {
return topic;
}
return "reference.settingsdialog.project.structure.facet";
}
@Override
@NotNull
public String getId() {
return "project.facets";
}
@Override
public Runnable enableSearch(final String option) {
return null;
}
@Override
public void dispose() {
}
private class FacetConfigurableNode extends MyNode {
public FacetConfigurableNode(final FacetConfigurable facetConfigurable) {
super(facetConfigurable);
}
@Override
@NotNull
public String getDisplayName() {
FacetConfigurable facetConfigurable = (FacetConfigurable)getConfigurable();
String moduleName = myContext.getRealName(facetConfigurable.getEditableObject().getModule());
return facetConfigurable.getDisplayName() + " (" + moduleName + ")";
}
}
private class MyNavigateAction extends AnAction implements DumbAware {
private MyNavigateAction() {
super(ProjectBundle.message("action.name.facet.navigate"));
registerCustomShortcutSet(CommonShortcuts.getEditSource(), myTree);
}
@Override
public void update(final AnActionEvent e) {
NamedConfigurable selected = getSelectedConfigurable();
e.getPresentation().setEnabled(selected instanceof FacetConfigurable);
}
@Override
public void actionPerformed(final AnActionEvent e) {
NamedConfigurable selected = getSelectedConfigurable();
if (selected instanceof FacetConfigurable) {
ProjectStructureConfigurable.getInstance(myProject).select(((FacetConfigurable)selected).getEditableObject(), true);
}
}
}
}