From 9d0148ef0b2368c02e44185531a6bc8526ffba0e Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 14 Oct 2009 09:49:05 +0400 Subject: [PATCH] find usages & validation in project structure reworked --- .../packaging/ui/ArtifactEditorContext.java | 2 +- .../roots/ui/configuration/ClasspathPanel.java | 30 +- .../ui/configuration/ModuleJdkConfigurable.java | 5 +- .../ui/configuration/ModulesConfigurator.java | 3 +- .../ui/configuration/ProjectJdkConfigurable.java | 11 +- .../ui/configuration/ProjectJdksConfigurable.java | 4 +- .../ProjectStructureConfigurable.java | 26 +- .../artifacts/ArtifactConfigurable.java | 16 +- .../artifacts/ArtifactEditorContextImpl.java | 41 +- .../artifacts/ArtifactEditorImpl.java | 9 +- .../artifacts/ArtifactProjectStructureElement.java | 102 ++++ .../artifacts/ArtifactsStructureConfigurable.java | 18 +- .../ArtifactsStructureConfigurableContext.java | 2 +- .../ArtifactsStructureConfigurableContextImpl.java | 5 +- .../ui/configuration/artifacts/LayoutTree.java | 22 +- .../artifacts/LayoutTreeComponent.java | 99 ++-- .../configuration/artifacts/UsageInArtifact.java | 70 +++ .../actions/ArtifactEditorFindUsagesAction.java | 11 +- .../artifacts/actions/ExtractArtifactAction.java | 19 +- .../artifacts/actions/InlineArtifactAction.java | 31 +- .../artifacts/actions/MoveElementAction.java | 18 +- .../actions/RenamePackagingElementAction.java | 3 +- .../artifacts/nodes/PackagingElementNode.java | 14 + ...urceItemIntoParentAndLinkViaManifestAction.java | 33 +- .../projectRoot/BaseLibrariesConfigurable.java | 43 +- .../projectRoot/BaseStructureConfigurable.java | 140 +++-- .../FindUsagesInProjectStructureActionBase.java | 85 +-- .../configuration/projectRoot/JdkConfigurable.java | 16 +- .../projectRoot/JdkListConfigurable.java | 25 +- .../projectRoot/LibraryConfigurable.java | 18 +- .../projectRoot/ModuleConfigurable.java | 15 +- .../projectRoot/ModuleStructureConfigurable.java | 29 +- .../ProjectStructureElementConfigurable.java | 36 ++ .../projectRoot/StructureConfigurableContext.java | 655 +++++---------------- .../daemon/LibraryProjectStructureElement.java | 78 +++ .../daemon/ModuleProjectStructureElement.java | 108 ++++ .../daemon/ProjectStructureDaemonAnalyzer.java | 243 ++++++++ .../daemon/ProjectStructureElement.java | 29 + .../daemon/ProjectStructureElementUsage.java | 24 + .../daemon/ProjectStructureProblemDescription.java | 39 ++ .../daemon/ProjectStructureProblemsHolder.java | 57 ++ .../daemon/SdkProjectStructureElement.java | 55 ++ .../projectRoot/daemon/UsageInModuleClasspath.java | 86 +++ .../openapi/ui/MasterDetailsComponent.java | 8 +- .../src/messages/ProjectBundle.properties | 2 +- 45 files changed, 1589 insertions(+), 796 deletions(-) create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProjectStructureElement.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/UsageInArtifact.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectStructureElementConfigurable.java rewrite java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/StructureConfigurableContext.java (70%) create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/LibraryProjectStructureElement.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElement.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElementUsage.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemDescription.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemsHolder.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/SdkProjectStructureElement.java create mode 100644 java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/UsageInModuleClasspath.java diff --git a/java/compiler/openapi/src/com/intellij/packaging/ui/ArtifactEditorContext.java b/java/compiler/openapi/src/com/intellij/packaging/ui/ArtifactEditorContext.java index a4f3691013..0e4457319a 100644 --- a/java/compiler/openapi/src/com/intellij/packaging/ui/ArtifactEditorContext.java +++ b/java/compiler/openapi/src/com/intellij/packaging/ui/ArtifactEditorContext.java @@ -45,7 +45,7 @@ public interface ArtifactEditorContext extends PackagingElementResolvingContext CompositePackagingElement getRootElement(@NotNull Artifact artifact); - void ensureRootIsWritable(@NotNull Artifact artifact); + void editLayout(@NotNull Artifact artifact, Runnable runnable); ArtifactEditor getOrCreateEditor(Artifact originalArtifact); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathPanel.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathPanel.java index 1119075c48..13776cfca8 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathPanel.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathPanel.java @@ -38,6 +38,10 @@ import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryTableEdi import com.intellij.openapi.roots.ui.configuration.projectRoot.FindUsagesInProjectStructureActionBase; import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.SdkProjectStructureElement; import com.intellij.openapi.roots.ui.util.CellAppearance; import com.intellij.openapi.roots.ui.util.OrderEntryCellAppearanceUtils; import com.intellij.openapi.ui.Messages; @@ -330,12 +334,13 @@ public class ClasspathPanel extends JPanel { if (orderEntry == null) { continue; } - ModuleStructureConfigurable.getInstance(myProject).getContext().clearCaches(orderEntry); myRootModel.removeOrderEntry(orderEntry); } final int[] selectedRows = myEntryTable.getSelectedRows(); myModel.fireTableDataChanged(); TableUtil.selectRows(myEntryTable, selectedRows); + final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(myProject).getContext(); + context.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(context, myRootModel.getModule())); } }); @@ -480,7 +485,6 @@ public class ClasspathPanel extends JPanel { final TableItem tableItem = createTableItem(item); if ( tableItem != null ) { myModel.addItem(tableItem); - rootConfigurable.getContext().clearCaches(tableItem.getEntry()); } } myModel.fireTableDataChanged(); @@ -489,6 +493,8 @@ public class ClasspathPanel extends JPanel { selectionModel.setSelectionInterval(myModel.getRowCount() - chosen.size(), myModel.getRowCount() - 1); TableUtil.scrollSelectionToVisible(myEntryTable); + final StructureConfigurableContext context = rootConfigurable.getContext(); + context.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(context, myRootModel.getModule())); } finally { if (dialog instanceof ChooseNamedLibraryAction.MyChooserDialog) { @@ -1151,7 +1157,6 @@ public class ClasspathPanel extends JPanel { chosen.removeAll(getAlreadyAddedLibraries()); final Module module = myRootModel.getModule(); final Project project = module.getProject(); - ModuleStructureConfigurable.getInstance(project).getContext().clearCaches(module, chosen); return chosen; } @@ -1175,29 +1180,38 @@ public class ClasspathPanel extends JPanel { } protected boolean isEnabled() { - return getSelectedObject() != null; + return getSelectedElement() != null; } - protected Object getSelectedObject() { + protected ProjectStructureElement getSelectedElement() { int row = myEntryTable.getSelectedRow(); if (0 <= row && row < myModel.getRowCount()) { TableItem item = myModel.getItemAt(row); if (item instanceof LibItem) { LibraryOrderEntry orderEntry = ((LibItem)item).getEntry(); if (orderEntry != null) { - return orderEntry.getLibrary(); + final Library library = orderEntry.getLibrary(); + if (library != null) { + return new LibraryProjectStructureElement(getContext(), library); + } } } else if (item instanceof ModuleItem) { ModuleOrderEntry orderEntry = ((ModuleItem)item).getEntry(); if (orderEntry != null) { - return orderEntry.getModule(); + final Module module = orderEntry.getModule(); + if (module != null) { + return new ModuleProjectStructureElement(getContext(), module); + } } } else if (item instanceof JdkItem) { JdkOrderEntry orderEntry = ((JdkItem)item).getEntry(); if (orderEntry != null) { - return orderEntry.getJdk(); + final Sdk jdk = orderEntry.getJdk(); + if (jdk != null) { + return new SdkProjectStructureElement(getContext(), jdk); + } } } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java index d307f33781..17d23aa979 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java @@ -25,6 +25,8 @@ import com.intellij.openapi.projectRoots.SdkModel; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectJdksModel; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Computable; @@ -155,7 +157,8 @@ public class ModuleJdkConfigurable implements Disposable { private void clearCaches(final Sdk oldJdk, final Sdk selectedModuleJdk) { final Module module = myRootModel.getModule(); final Project project = module.getProject(); - ModuleStructureConfigurable.getInstance(project).getContext().clearCaches(module, oldJdk, selectedModuleJdk); + final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(project).getContext(); + context.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(context, module)); } public void reset() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java index f3e75948a4..536f82414b 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java @@ -40,6 +40,7 @@ import com.intellij.openapi.roots.ui.configuration.actions.ModuleDeleteProvider; import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectJdksModel; import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; @@ -487,7 +488,7 @@ public class ModulesConfigurator implements ModulesProvider, ModuleEditor.Change if (module == moduleEditor.getModule() && Comparing.strEqual(moduleEditor.getName(), oldName)) { moduleEditor.setModuleName(name); moduleEditor.updateCompilerOutputPathChanged(ProjectStructureConfigurable.getInstance(myProject).getProjectConfig().getCompilerOutputUrl(), name); - myContext.invalidateModuleName(moduleEditor.getModule()); + myContext.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(myContext, module), true, false); return; } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java index 476378c560..bb39ec3efd 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java @@ -26,6 +26,8 @@ import com.intellij.openapi.projectRoots.SdkModel; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectJdksModel; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import org.jetbrains.annotations.Nullable; @@ -91,7 +93,7 @@ public class ProjectJdkConfigurable implements UnnamedConfigurable { myCbProjectJdk.setSelectedJdk(jdk); } else { myCbProjectJdk.setInvalidJdk(sdkName); - clearCaches(null); + clearCaches(); } } else { myCbProjectJdk.setSelectedJdk(null); @@ -108,7 +110,7 @@ public class ProjectJdkConfigurable implements UnnamedConfigurable { if (myFreeze) return; final Sdk oldJdk = myJdksModel.getProjectJdk(); myJdksModel.setProjectJdk(myCbProjectJdk.getSelectedJdk()); - clearCaches(oldJdk); + clearCaches(); } }); myJdkPanel.add(new JLabel(ProjectBundle.message("module.libraries.target.jdk.project.radio")), new GridBagConstraints(0, 0, 3, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 4, 0), 0, 0)); @@ -123,11 +125,12 @@ public class ProjectJdkConfigurable implements UnnamedConfigurable { }); } - private void clearCaches(final Sdk oldJdk) { + private void clearCaches() { final ModuleStructureConfigurable rootConfigurable = ModuleStructureConfigurable.getInstance(myProject); Module[] modules = rootConfigurable.getModules(); for (Module module : modules) { - rootConfigurable.getContext().clearCaches(module, oldJdk, getSelectedProjectJdk()); + final StructureConfigurableContext context = rootConfigurable.getContext(); + context.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(context, module)); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java index be5fc211c5..f9c1c0c88f 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java @@ -89,7 +89,7 @@ public class ProjectJdksConfigurable extends MasterDetailsComponent implements C myRoot.removeAllChildren(); final HashMap sdks = myProjectJdksModel.getProjectJdks(); for (Sdk sdk : sdks.keySet()) { - final JdkConfigurable configurable = new JdkConfigurable((ProjectJdkImpl)sdks.get(sdk), myProjectJdksModel, TREE_UPDATER, myHistory); + final JdkConfigurable configurable = new JdkConfigurable((ProjectJdkImpl)sdks.get(sdk), myProjectJdksModel, TREE_UPDATER, myHistory, myProject); addNode(new MyNode(configurable), myRoot); } selectJdk(myProjectJdksModel.getProjectJdk()); //restore selection @@ -153,7 +153,7 @@ public class ProjectJdksConfigurable extends MasterDetailsComponent implements C group.getTemplatePresentation().setIcon(Icons.ADD_ICON); myProjectJdksModel.createAddActions(group, myTree, new Consumer() { public void consume(final Sdk projectJdk) { - addNode(new MyNode(new JdkConfigurable(((ProjectJdkImpl)projectJdk), myProjectJdksModel, TREE_UPDATER, myHistory), false), myRoot); + addNode(new MyNode(new JdkConfigurable(((ProjectJdkImpl)projectJdk), myProjectJdksModel, TREE_UPDATER, myHistory, myProject), false), myRoot); selectNodeInTree(findNodeByObject(myRoot, projectJdk)); } }); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java index 0fadc04ec9..cab3a388b3 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java @@ -111,12 +111,13 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se myArtifactsStructureConfigurable = artifactsStructureConfigurable; myModuleConfigurator = new ModulesConfigurator(myProject, myProjectJdksModel); - myContext = new StructureConfigurableContext(myProject, myModuleManager, myModuleConfigurator); + myContext = new StructureConfigurableContext(myProject, myModuleConfigurator); myModuleConfigurator.setContext(myContext); myProjectLibrariesConfig = projectLibrariesConfigurable; myGlobalLibrariesConfig = globalLibrariesConfigurable; myModulesConfig = moduleStructureConfigurable; + myProjectLibrariesConfig.init(myContext); myGlobalLibrariesConfig.init(myContext); myModulesConfig.init(myContext); @@ -226,8 +227,10 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se } private void addJdkListConfig() { - myJdkListConfig = JdkListConfigurable.getInstance(myProject); - myJdkListConfig.init(myContext); + if (myJdkListConfig == null) { + myJdkListConfig = JdkListConfigurable.getInstance(myProject); + myJdkListConfig.init(myContext); + } addConfigurable(myJdkListConfig); } @@ -265,18 +268,13 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se } //cleanup - myContext.myUpdateDependenciesAlarm.cancelAllRequests(); - myContext.myUpdateDependenciesAlarm.addRequest(new Runnable(){ + myContext.getDaemonAnalyzer().clearCaches(); + SwingUtilities.invokeLater(new Runnable(){ public void run() { - SwingUtilities.invokeLater(new Runnable(){ - public void run() { - if (myWasUiDisposed) return; - reset(); - } - }); + if (myWasUiDisposed) return; + reset(); } - }, 0); - + }); } public void reset() { @@ -323,7 +321,7 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se myUiState.proportion = mySplitter.getProportion(); saveSideProportion(); - + myContext.getDaemonAnalyzer().stop(); for (Configurable each : myName2Config) { each.disposeUIResources(); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactConfigurable.java index fffce6e846..2bf7cbb8db 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactConfigurable.java @@ -17,8 +17,10 @@ package com.intellij.openapi.roots.ui.configuration.artifacts; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.ProjectBundle; +import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectStructureElementConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; import com.intellij.openapi.ui.ComboBox; -import com.intellij.openapi.ui.NamedConfigurable; import com.intellij.openapi.util.Comparing; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.artifacts.ArtifactType; @@ -34,17 +36,20 @@ import java.awt.event.ActionListener; /** * @author nik */ -public class ArtifactConfigurable extends NamedConfigurable { +public class ArtifactConfigurable extends ProjectStructureElementConfigurable { private final Artifact myOriginalArtifact; private final ArtifactsStructureConfigurableContext myArtifactsStructureContext; private final ArtifactEditorImpl myEditor; private boolean myIsInUpdateName; + private ProjectStructureElement myProjectStructureElement; - public ArtifactConfigurable(Artifact originalArtifact, ArtifactsStructureConfigurableContextImpl artifactsStructureContext, final Runnable updateTree) { + public ArtifactConfigurable(Artifact originalArtifact, ArtifactsStructureConfigurableContextImpl artifactsStructureContext, final Runnable updateTree, + StructureConfigurableContext context) { super(true, updateTree); myOriginalArtifact = originalArtifact; myArtifactsStructureContext = artifactsStructureContext; myEditor = artifactsStructureContext.getOrCreateEditor(originalArtifact); + myProjectStructureElement = new ArtifactProjectStructureElement(context, myArtifactsStructureContext, myOriginalArtifact); } public void setDisplayName(String name) { @@ -56,6 +61,11 @@ public class ArtifactConfigurable extends NamedConfigurable { } @Override + public ProjectStructureElement getProjectStructureElement() { + return myProjectStructureElement; + } + + @Override public void updateName() { myIsInUpdateName = true; try { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java index b0b833772b..199c3b5da0 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java @@ -15,14 +15,21 @@ */ package com.intellij.openapi.roots.ui.configuration.artifacts; +import com.intellij.facet.Facet; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootModel; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.impl.ModuleLibraryOrderEntryImpl; +import com.intellij.openapi.roots.impl.libraries.LibraryImpl; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.roots.ui.configuration.FacetsProvider; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; -import com.intellij.openapi.roots.ui.configuration.packaging.ChooseLibrariesDialog; import com.intellij.openapi.roots.ui.configuration.libraryEditor.ChooseModulesDialog; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.ui.configuration.packaging.ChooseLibrariesDialog; +import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.artifacts.ArtifactModel; import com.intellij.packaging.artifacts.ArtifactType; @@ -31,11 +38,10 @@ import com.intellij.packaging.elements.CompositePackagingElement; import com.intellij.packaging.ui.ArtifactEditor; import com.intellij.packaging.ui.ArtifactEditorContext; import com.intellij.packaging.ui.ManifestFileConfiguration; -import com.intellij.facet.Facet; import org.jetbrains.annotations.NotNull; -import java.util.List; import java.util.Collections; +import java.util.List; /** * @author nik @@ -69,8 +75,8 @@ public class ArtifactEditorContextImpl implements ArtifactEditorContext { return myParent.getRootElement(artifact); } - public void ensureRootIsWritable(@NotNull Artifact artifact) { - myParent.ensureRootIsWritable(artifact); + public void editLayout(@NotNull Artifact artifact, Runnable runnable) { + myParent.editLayout(artifact, runnable); } public ArtifactEditor getOrCreateEditor(Artifact artifact) { @@ -90,7 +96,26 @@ public class ArtifactEditorContextImpl implements ArtifactEditorContext { } public void selectLibrary(@NotNull Library library) { - ProjectStructureConfigurable.getInstance(getProject()).selectProjectOrGlobalLibrary(library, true); + final LibraryTable table = library.getTable(); + if (table != null) { + ProjectStructureConfigurable.getInstance(getProject()).selectProjectOrGlobalLibrary(library, true); + } + else { + final Module module = ((LibraryImpl)library).getModule(); + if (module != null) { + final ModuleRootModel rootModel = myParent.getModulesProvider().getRootModel(module); + final String libraryName = library.getName(); + for (OrderEntry entry : rootModel.getOrderEntries()) { + if (entry instanceof ModuleLibraryOrderEntryImpl) { + final ModuleLibraryOrderEntryImpl libraryEntry = (ModuleLibraryOrderEntryImpl)entry; + if (libraryName.equals(libraryEntry.getLibraryName())) { + ModuleStructureConfigurable.getInstance(getProject()).selectOrderEntry(module, libraryEntry); + return; + } + } + } + } + } } public List chooseArtifacts(final List artifacts, final String title) { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java index 6d41cfa37a..ffa8666b9b 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java @@ -339,7 +339,7 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { return myLayoutTreeComponent; } - public void updateOutputPath(@NotNull String oldArtifactName, @NotNull String newArtifactName) { + public void updateOutputPath(@NotNull String oldArtifactName, @NotNull final String newArtifactName) { final String oldDefaultPath = ArtifactUtil.getDefaultArtifactOutputPath(oldArtifactName, myProject); if (Comparing.equal(oldDefaultPath, getConfiguredOutputPath())) { setOutputPath(ArtifactUtil.getDefaultArtifactOutputPath(newArtifactName, myProject)); @@ -349,8 +349,11 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { final String fileName = FileUtil.getNameWithoutExtension(name); final String extension = FileUtil.getExtension(name); if (fileName.equals(oldArtifactName) && extension.length() > 0) { - myLayoutTreeComponent.ensureRootIsWritable(); - ((ArchivePackagingElement)getRootElement()).setArchiveFileName(newArtifactName + "." + extension); + myLayoutTreeComponent.editLayout(new Runnable() { + public void run() { + ((ArchivePackagingElement)getRootElement()).setArchiveFileName(newArtifactName + "." + extension); + } + }); myLayoutTreeComponent.updateTreeNodesPresentation(); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProjectStructureElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProjectStructureElement.java new file mode 100644 index 0000000000..02cd94f775 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProjectStructureElement.java @@ -0,0 +1,102 @@ +/* + * Copyright 2000-2009 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.artifacts; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.*; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.elements.CompositePackagingElement; +import com.intellij.packaging.elements.PackagingElement; +import com.intellij.packaging.impl.artifacts.ArtifactUtil; +import com.intellij.packaging.impl.artifacts.PackagingElementProcessor; +import com.intellij.packaging.impl.elements.LibraryPackagingElement; +import com.intellij.packaging.impl.elements.ModuleOutputPackagingElement; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author nik + */ +public class ArtifactProjectStructureElement extends ProjectStructureElement { + private final ArtifactsStructureConfigurableContext myArtifactsStructureContext; + private final Artifact myOriginalArtifact; + + public ArtifactProjectStructureElement(StructureConfigurableContext context, + ArtifactsStructureConfigurableContext artifactsStructureContext, Artifact originalArtifact) { + super(context); + myArtifactsStructureContext = artifactsStructureContext; + myOriginalArtifact = originalArtifact; + } + + @Override + public void check(ProjectStructureProblemsHolder problemsHolder) { + } + + @Override + public List getUsagesInElement() { + final Artifact artifact = myArtifactsStructureContext.getArtifactModel().getArtifactByOriginal(myOriginalArtifact); + final List usages = new ArrayList(); + ArtifactUtil.processPackagingElements(myArtifactsStructureContext.getRootElement(artifact), null, new PackagingElementProcessor>() { + @Override + public boolean process(@NotNull List> parents, @NotNull PackagingElement packagingElement) { + if (packagingElement instanceof ModuleOutputPackagingElement) { + final Module module = ((ModuleOutputPackagingElement)packagingElement).findModule(myArtifactsStructureContext); + if (module != null) { + usages.add(new UsageInArtifact(myOriginalArtifact, myArtifactsStructureContext, new ModuleProjectStructureElement(myContext, module), + ArtifactProjectStructureElement.this, getPathFromRoot(parents, "/"), packagingElement)); + } + } + else if (packagingElement instanceof LibraryPackagingElement) { + final Library library = ((LibraryPackagingElement)packagingElement).findLibrary(myArtifactsStructureContext); + if (library != null) { + usages.add(new UsageInArtifact(myOriginalArtifact, myArtifactsStructureContext, new LibraryProjectStructureElement(myContext, library), + ArtifactProjectStructureElement.this, getPathFromRoot(parents, "/"), packagingElement)); + } + } + return true; + } + }, myArtifactsStructureContext, false, artifact.getArtifactType()); + return usages; + } + + @Override + public String toString() { + return "artifact:" + myOriginalArtifact.getName(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ArtifactProjectStructureElement)) return false; + + return myOriginalArtifact.equals(((ArtifactProjectStructureElement)o).myOriginalArtifact); + + } + + @Override + public int hashCode() { + return myOriginalArtifact.hashCode(); + } + + @Override + public boolean highlightIfUnused() { + return false; + } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java index 1736da57e7..d8f17d68a4 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java @@ -27,6 +27,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.ui.configuration.projectRoot.BaseStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; import com.intellij.packaging.artifacts.*; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; @@ -34,6 +35,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; /** * @author nik @@ -58,6 +62,7 @@ public class ArtifactsStructureConfigurable extends BaseStructureConfigurable { public void artifactAdded(@NotNull Artifact artifact) { final MyNode node = addArtifactNode(artifact); selectNodeInTree(node); + myContext.getDaemonAnalyzer().queueUpdate(new ArtifactProjectStructureElement(myContext, myPackagingEditorContext, artifact)); } }); } @@ -75,8 +80,18 @@ public class ArtifactsStructureConfigurable extends BaseStructureConfigurable { } } + @NotNull + @Override + protected Collection getProjectStructureElements() { + final List elements = new ArrayList(); + for (Artifact artifact : myPackagingEditorContext.getArtifactModel().getArtifacts()) { + elements.add(new ArtifactProjectStructureElement(myContext, myPackagingEditorContext, artifact)); + } + return elements; + } + private MyNode addArtifactNode(final Artifact artifact) { - final MyNode node = new MyNode(new ArtifactConfigurable(artifact, myPackagingEditorContext, TREE_UPDATER)); + final MyNode node = new MyNode(new ArtifactConfigurable(artifact, myPackagingEditorContext, TREE_UPDATER, myContext)); addNode(node, myRoot); return node; } @@ -160,6 +175,7 @@ public class ArtifactsStructureConfigurable extends BaseStructureConfigurable { @Override protected void removeArtifact(Artifact artifact) { myPackagingEditorContext.getModifiableArtifactModel().removeArtifact(artifact); + myContext.getDaemonAnalyzer().removeElement(new ArtifactProjectStructureElement(myContext, myPackagingEditorContext, artifact)); } protected void processRemovedItems() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContext.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContext.java index ab890f31f7..5dfe4c10a5 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContext.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContext.java @@ -36,7 +36,7 @@ public interface ArtifactsStructureConfigurableContext extends PackagingElementR CompositePackagingElement getRootElement(@NotNull Artifact artifact); - void ensureRootIsWritable(@NotNull Artifact artifact); + void editLayout(@NotNull Artifact artifact, Runnable action); ArtifactEditor getOrCreateEditor(Artifact artifact); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContextImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContextImpl.java index 6a9b9d577f..5f1a7344fc 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContextImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContextImpl.java @@ -86,13 +86,14 @@ class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureCon return root; } - public void ensureRootIsWritable(@NotNull Artifact artifact) { + public void editLayout(@NotNull Artifact artifact, Runnable action) { artifact = getOriginalArtifact(artifact); final ModifiableArtifact modifiableArtifact = getModifiableArtifactModel().getOrCreateModifiableArtifact(artifact); if (modifiableArtifact.getRootElement() == artifact.getRootElement()) { modifiableArtifact.setRootElement(getRootElement(artifact)); } - + action.run(); + myContext.getDaemonAnalyzer().queueUpdate(new ArtifactProjectStructureElement(myContext, this, artifact)); } public ArtifactEditorImpl getOrCreateEditor(Artifact artifact) { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTree.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTree.java index 91f07e8a0e..167ae1250f 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTree.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTree.java @@ -23,8 +23,10 @@ import com.intellij.ide.dnd.aware.DnDAwareTree; import com.intellij.ide.util.treeView.AbstractTreeBuilder; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.ProjectBundle; +import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.CompositePackagingElementNode; import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.PackagingElementNode; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.packaging.elements.PackagingElement; import com.intellij.packaging.elements.RenameablePackagingElement; import com.intellij.ui.TreeSpeedSearch; @@ -156,6 +158,19 @@ public class LayoutTree extends SimpleDnDAwareTree implements AdvancedDnDSource } } + @Nullable + public PackagingElementNode findCompositeNodeByPath(String parentPath) { + PackagingElementNode node = getRootPackagingNode(); + for (String name : StringUtil.split(parentPath, "/")) { + final CompositePackagingElementNode child = node.findCompositeChild(name); + if (child == null) { + return null; + } + node = child; + } + return node; + } + private class LayoutTreeCellEditor extends DefaultCellEditor { public LayoutTreeCellEditor() { super(new JTextField()); @@ -189,7 +204,12 @@ public class LayoutTree extends SimpleDnDAwareTree implements AdvancedDnDSource } final boolean stopped = super.stopCellEditing(); if (stopped && currentElement != null) { - currentElement.rename(newValue); + final RenameablePackagingElement finalCurrentElement = currentElement; + myArtifactsEditor.getLayoutTreeComponent().editLayout(new Runnable() { + public void run() { + finalCurrentElement.rename(newValue); + } + }); myArtifactsEditor.queueValidation(); myArtifactsEditor.getLayoutTreeComponent().updatePropertiesPanel(true); addSubtreeToUpdate((DefaultMutableTreeNode)path.getLastPathComponent()); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTreeComponent.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTreeComponent.java index ec46749f31..86bf0d68dd 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTreeComponent.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTreeComponent.java @@ -19,10 +19,7 @@ import com.intellij.ide.dnd.DnDEvent; import com.intellij.ide.dnd.DnDManager; import com.intellij.ide.dnd.DnDTarget; import com.intellij.openapi.Disposable; -import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.PackagingElementNode; -import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.PackagingNodeSource; -import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.PackagingTreeNodeFactory; -import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.ArtifactRootNode; +import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.*; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; @@ -37,6 +34,7 @@ import com.intellij.packaging.ui.PackagingElementPropertiesPanel; import com.intellij.packaging.ui.PackagingSourceItem; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.awt.RelativeRectangle; +import com.intellij.ui.treeStructure.SimpleNode; import com.intellij.ui.treeStructure.SimpleTreeBuilder; import com.intellij.ui.treeStructure.SimpleTreeStructure; import com.intellij.ui.treeStructure.WeightBasedComparator; @@ -157,14 +155,17 @@ public class LayoutTreeComponent implements DnDTarget, Disposable { final PackagingElement element = parentNode.getElementIfSingle(); if (!checkCanAdd(type, element, parentNode)) return; - ensureRootIsWritable(); - CompositePackagingElement parent = element instanceof CompositePackagingElement ? (CompositePackagingElement)element + final CompositePackagingElement parent = element instanceof CompositePackagingElement ? (CompositePackagingElement)element : getArtifact().getRootElement(); final List> children = type.chooseAndCreate(myContext, getArtifact(), parent); - for (PackagingElement child : children) { - parent.addOrFindChild(child); - } + editLayout(new Runnable() { + public void run() { + for (PackagingElement child : children) { + parent.addOrFindChild(child); + } + } + }); updateAndSelect(parentNode, children); } @@ -210,16 +211,37 @@ public class LayoutTreeComponent implements DnDTarget, Disposable { }); } - public void ensureRootIsWritable() { - myContext.ensureRootIsWritable(myOriginalArtifact); + public void selectNode(@NotNull String parentPath, @NotNull PackagingElement element) { + final PackagingElementNode parent = myTree.findCompositeNodeByPath(parentPath); + if (parent == null) return; + + for (SimpleNode node : parent.getChildren()) { + if (node instanceof PackagingElementNode) { + final List> elements = ((PackagingElementNode)node).getPackagingElements(); + for (PackagingElement packagingElement : elements) { + if (packagingElement.isEqualTo(element)) { + myBuilder.select(node); + return; + } + } + } + } + } + + public void editLayout(Runnable action) { + myContext.editLayout(myOriginalArtifact, action); } public void removeSelectedElements() { final LayoutTreeSelection selection = myTree.getSelection(); if (!checkCanRemove(selection.getNodes())) return; - ensureRootIsWritable(); - removeNodes(selection.getNodes()); + editLayout(new Runnable() { + public void run() { + removeNodes(selection.getNodes()); + } + }); + myArtifactsEditor.rebuildTries(); } @@ -321,13 +343,16 @@ public class LayoutTreeComponent implements DnDTarget, Disposable { if (!checkCanAdd(null, targetElement, targetNode)) { return; } - ensureRootIsWritable(); - draggingObject.beforeDrop(); - List> toSelect = new ArrayList>(); - for (PackagingElement element : draggingObject.createPackagingElements(myContext)) { - toSelect.add(element); - targetElement.addOrFindChild(element); - } + final List> toSelect = new ArrayList>(); + editLayout(new Runnable() { + public void run() { + draggingObject.beforeDrop(); + for (PackagingElement element : draggingObject.createPackagingElements(myContext)) { + toSelect.add(element); + targetElement.addOrFindChild(element); + } + } + }); updateAndSelect(targetNode, toSelect); myArtifactsEditor.getSourceItemsTree().rebuildTree(); } @@ -352,7 +377,7 @@ public class LayoutTreeComponent implements DnDTarget, Disposable { public void updateDraggedImage(Image image, Point dropPoint, Point imageOffset) { } - public void rename(TreePath path) { + public void startRenaming(TreePath path) { myTree.startEditingAtPath(path); } @@ -379,20 +404,23 @@ public class LayoutTreeComponent implements DnDTarget, Disposable { mySelectedElementInfo.showPropertiesPanel(); } - public void putIntoDefaultLocations(@NotNull List items) { - ensureRootIsWritable(); - + public void putIntoDefaultLocations(@NotNull final List items) { + final List> toSelect = new ArrayList>(); final CompositePackagingElement rootElement = getArtifact().getRootElement(); final ArtifactType artifactType = getArtifact().getArtifactType(); - List> toSelect = new ArrayList>(); - for (PackagingSourceItem item : items) { - final String path = artifactType.getDefaultPathFor(item); - if (path != null) { - final CompositePackagingElement directory = PackagingElementFactory.getInstance().getOrCreateDirectory(rootElement, path); - final List> elements = item.createElements(myContext); - toSelect.addAll(directory.addOrFindChildren(elements)); + editLayout(new Runnable() { + public void run() { + for (PackagingSourceItem item : items) { + final String path = artifactType.getDefaultPathFor(item); + if (path != null) { + final CompositePackagingElement directory = PackagingElementFactory.getInstance().getOrCreateDirectory(rootElement, path); + final List> elements = item.createElements(myContext); + toSelect.addAll(directory.addOrFindChildren(elements)); + } + } } - } + }); + myArtifactsEditor.getSourceItemsTree().rebuildTree(); updateAndSelect(myTree.getRootPackagingNode(), toSelect); } @@ -432,8 +460,11 @@ public class LayoutTreeComponent implements DnDTarget, Disposable { public void save() { if (myCurrentPanel != null && myCurrentPanel.isModified()) { - ensureRootIsWritable(); - myCurrentPanel.apply(); + editLayout(new Runnable() { + public void run() { + myCurrentPanel.apply(); + } + }); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/UsageInArtifact.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/UsageInArtifact.java new file mode 100644 index 0000000000..69a16cabab --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/UsageInArtifact.java @@ -0,0 +1,70 @@ +package com.intellij.openapi.roots.ui.configuration.artifacts; + +import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElementUsage; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.elements.PackagingElement; + +import javax.swing.*; + +/** + * @author nik + */ +public class UsageInArtifact extends ProjectStructureElementUsage { + private Artifact myOriginalArtifact; + private final ArtifactsStructureConfigurableContext myContext; + private ProjectStructureElement mySourceElement; + private ProjectStructureElement myContainingElement; + private final String myParentPath; + private final PackagingElement myPackagingElement; + + public UsageInArtifact(Artifact originalArtifact, ArtifactsStructureConfigurableContext context, ProjectStructureElement sourceElement, + ArtifactProjectStructureElement containingElement, + String parentPath, PackagingElement packagingElement) { + myOriginalArtifact = originalArtifact; + myContext = context; + mySourceElement = sourceElement; + myContainingElement = containingElement; + myParentPath = parentPath; + myPackagingElement = packagingElement; + } + + @Override + public ProjectStructureElement getSourceElement() { + return mySourceElement; + } + + @Override + public ProjectStructureElement getContainingElement() { + return myContainingElement; + } + + @Override + public void navigate() { + final Artifact artifact = myContext.getArtifactModel().getArtifactByOriginal(myOriginalArtifact); + final ArtifactEditorEx artifactEditor = (ArtifactEditorEx)myContext.getOrCreateEditor(artifact); + artifactEditor.getLayoutTreeComponent().selectNode(myParentPath, myPackagingElement); + ProjectStructureConfigurable.getInstance(myContext.getProject()).select(myOriginalArtifact, true); + } + + @Override + public String getPresentableName() { + return myOriginalArtifact.getName(); + } + + @Override + public int hashCode() { + return myOriginalArtifact.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof UsageInArtifact && ((UsageInArtifact)obj).myOriginalArtifact.equals(myOriginalArtifact); + } + + @Override + public Icon getIcon() { + return myOriginalArtifact.getArtifactType().getIcon(); + } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ArtifactEditorFindUsagesAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ArtifactEditorFindUsagesAction.java index a64adbdf70..55f0b8c075 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ArtifactEditorFindUsagesAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ArtifactEditorFindUsagesAction.java @@ -15,10 +15,11 @@ */ package com.intellij.openapi.roots.ui.configuration.artifacts.actions; -import com.intellij.openapi.roots.ui.configuration.projectRoot.FindUsagesInProjectStructureActionBase; -import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.PackagingElementNode; -import com.intellij.openapi.roots.ui.configuration.artifacts.LayoutTreeComponent; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.artifacts.LayoutTreeComponent; +import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.PackagingElementNode; +import com.intellij.openapi.roots.ui.configuration.projectRoot.FindUsagesInProjectStructureActionBase; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; import com.intellij.ui.awt.RelativePoint; import java.awt.*; @@ -39,9 +40,9 @@ public class ArtifactEditorFindUsagesAction extends FindUsagesInProjectStructure return node != null && node.getElementPresentation().getSourceObject() != null; } - protected Object getSelectedObject() { + protected ProjectStructureElement getSelectedElement() { PackagingElementNode node = myLayoutTreeComponent.getSelection().getNodeIfSingle(); - return node != null ? node.getElementPresentation().getSourceObject() : null; + return node != null ? (ProjectStructureElement)node.getElementPresentation().getSourceObject() : null; } protected RelativePoint getPointToShowResults() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ExtractArtifactAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ExtractArtifactAction.java index 96f79460dd..7c701ede4c 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ExtractArtifactAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ExtractArtifactAction.java @@ -64,17 +64,20 @@ public class ExtractArtifactAction extends DumbAwareAction { final String name = Messages.showInputDialog(myEditor.getMainComponent(), ProjectBundle.message("label.text.specify.artifact.name"), ProjectBundle.message("dialog.title.extract.artifact"), null); if (name != null) { - treeComponent.ensureRootIsWritable(); final Project project = myEditor.getContext().getProject(); //todo[nik] select type? final ModifiableArtifact artifact = myEditor.getContext().getModifiableArtifactModel().addArtifact(name, PlainArtifactType.getInstance()); - for (PackagingElement element : selectedElements) { - artifact.getRootElement().addOrFindChild(ArtifactUtil.copyWithChildren(element, project)); - } - for (PackagingElement element : selectedElements) { - parent.removeChild(element); - } - parent.addOrFindChild(new ArtifactPackagingElement(project, ArtifactPointerManager.getInstance(project).create(artifact))); + treeComponent.editLayout(new Runnable() { + public void run() { + for (PackagingElement element : selectedElements) { + artifact.getRootElement().addOrFindChild(ArtifactUtil.copyWithChildren(element, project)); + } + for (PackagingElement element : selectedElements) { + parent.removeChild(element); + } + parent.addOrFindChild(new ArtifactPackagingElement(project, ArtifactPointerManager.getInstance(project).create(artifact))); + } + }); treeComponent.rebuildTree(); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/InlineArtifactAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/InlineArtifactAction.java index 757131a848..7a69521191 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/InlineArtifactAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/InlineArtifactAction.java @@ -56,28 +56,31 @@ public class InlineArtifactAction extends DumbAwareAction { final PackagingElementNode node = selection.getNodeIfSingle(); if (node == null || !(element instanceof ArtifactPackagingElement)) return; - CompositePackagingElement parent = node.getParentElement(element); + final CompositePackagingElement parent = node.getParentElement(element); if (parent == null) { return; } if (!treeComponent.checkCanRemove(selection.getNodes())) return; if (!treeComponent.checkCanAdd(null, parent, node)) return; - treeComponent.ensureRootIsWritable(); - parent.removeChild(element); - final ArtifactEditorContext context = myEditor.getContext(); - final Artifact artifact = ((ArtifactPackagingElement)element).findArtifact(context); - if (artifact != null) { - final CompositePackagingElement rootElement = artifact.getRootElement(); - if (rootElement instanceof ArtifactRootElement) { - for (PackagingElement child : rootElement.getChildren()) { - parent.addOrFindChild(ArtifactUtil.copyWithChildren(child, context.getProject())); + treeComponent.editLayout(new Runnable() { + public void run() { + parent.removeChild(element); + final ArtifactEditorContext context = myEditor.getContext(); + final Artifact artifact = ((ArtifactPackagingElement)element).findArtifact(context); + if (artifact != null) { + final CompositePackagingElement rootElement = artifact.getRootElement(); + if (rootElement instanceof ArtifactRootElement) { + for (PackagingElement child : rootElement.getChildren()) { + parent.addOrFindChild(ArtifactUtil.copyWithChildren(child, context.getProject())); + } + } + else { + parent.addOrFindChild(ArtifactUtil.copyWithChildren(rootElement, context.getProject())); + } } } - else { - parent.addOrFindChild(ArtifactUtil.copyWithChildren(rootElement, context.getProject())); - } - } + }); treeComponent.rebuildTree(); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/MoveElementAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/MoveElementAction.java index e7f6033d7d..948b2f5bf3 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/MoveElementAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/MoveElementAction.java @@ -24,6 +24,7 @@ import com.intellij.packaging.elements.CompositePackagingElement; import com.intellij.packaging.elements.PackagingElement; import javax.swing.*; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -80,11 +81,18 @@ public class MoveElementAction extends DumbAwareAction { if (myLayoutTreeComponent.checkCanRemove(Collections.singletonList(node)) && myLayoutTreeComponent.checkCanAdd(null, parentElement, parent)) { - myLayoutTreeComponent.ensureRootIsWritable(); - final int index = parentElement.getChildren().indexOf(element); - final PackagingElement moved = parentElement.moveChild(index, myDirection); - if (moved != null) { - myLayoutTreeComponent.updateAndSelect(parent, Collections.singletonList(moved)); + final List> toSelect = new ArrayList>(); + myLayoutTreeComponent.editLayout(new Runnable() { + public void run() { + final int index = parentElement.getChildren().indexOf(element); + final PackagingElement moved = parentElement.moveChild(index, myDirection); + if (moved != null) { + toSelect.add(moved); + } + } + }); + if (!toSelect.isEmpty()) { + myLayoutTreeComponent.updateAndSelect(parent, toSelect); } } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/RenamePackagingElementAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/RenamePackagingElementAction.java index ecdf36e72a..ec2f86f9dc 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/RenamePackagingElementAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/RenamePackagingElementAction.java @@ -53,7 +53,6 @@ public class RenamePackagingElementAction extends DumbAwareAction { final PackagingElementNode node = selection.getNodeIfSingle(); if (node == null) return; final TreePath path = selection.getPath(node); - myArtifactEditor.getLayoutTreeComponent().ensureRootIsWritable(); - myArtifactEditor.getLayoutTreeComponent().rename(path); + myArtifactEditor.getLayoutTreeComponent().startRenaming(path); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingElementNode.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingElementNode.java index c59ebce526..cc7e19c8d1 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingElementNode.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingElementNode.java @@ -131,4 +131,18 @@ public class PackagingElementNode> extends Artifac public ArtifactEditorContext getContext() { return myContext; } + + @Nullable + public CompositePackagingElementNode findCompositeChild(@NotNull String name) { + final SimpleNode[] children = getChildren(); + for (SimpleNode child : children) { + if (child instanceof CompositePackagingElementNode) { + final CompositePackagingElementNode composite = (CompositePackagingElementNode)child; + if (name.equals(composite.getFirstElement().getName())) { + return composite; + } + } + } + return null; + } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/sourceItems/PutSourceItemIntoParentAndLinkViaManifestAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/sourceItems/PutSourceItemIntoParentAndLinkViaManifestAction.java index fc32a07509..3433b21e94 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/sourceItems/PutSourceItemIntoParentAndLinkViaManifestAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/sourceItems/PutSourceItemIntoParentAndLinkViaManifestAction.java @@ -100,22 +100,37 @@ public class PutSourceItemIntoParentAndLinkViaManifestAction extends AnAction { final Artifact artifact = parentsInfo.getGrandparentArtifact(); final ArtifactEditorContext context = myArtifactEditor.getContext(); - context.ensureRootIsWritable(artifact); - context.ensureRootIsWritable(parentsInfo.getParentArtifact()); + //todo[nik] improve + final Runnable emptyRunnable = new Runnable() { + public void run() { + } + }; + context.editLayout(artifact, emptyRunnable); + context.editLayout(parentsInfo.getParentArtifact(), emptyRunnable); parentsInfo = findParentAndGrandParent(myArtifactEditor.getArtifact());//find elements under modifiable root if (parentsInfo == null) { return; } final CompositePackagingElement grandParent = parentsInfo.getGrandparentElement(); - List classpath = new ArrayList(); - for (PackagingSourceItem item : items) { - final List> elements = item.createElements(context); - grandParent.addOrFindChildren(elements); - classpath.addAll(ManifestFileUtil.getClasspathForElements(elements, context, artifact.getArtifactType())); - } + final List classpath = new ArrayList(); + context.editLayout(artifact, new Runnable() { + public void run() { + for (PackagingSourceItem item : items) { + final List> elements = item.createElements(context); + grandParent.addOrFindChildren(elements); + classpath.addAll(ManifestFileUtil.getClasspathForElements(elements, context, artifact.getArtifactType())); + } + } + }); + final ArtifactEditor parentArtifactEditor = context.getOrCreateEditor(parentsInfo.getParentArtifact()); - parentArtifactEditor.addToClasspath(parentsInfo.getParentElement(), classpath); + final ParentElementsInfo finalParentsInfo = parentsInfo; + context.editLayout(parentsInfo.getParentArtifact(), new Runnable() { + public void run() { + parentArtifactEditor.addToClasspath(finalParentsInfo.getParentElement(), classpath); + } + }); ((ArtifactEditorImpl)context.getOrCreateEditor(parentsInfo.getGrandparentArtifact())).rebuildTries(); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseLibrariesConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseLibrariesConfigurable.java index 39c8f08c37..dc1a06c1a6 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseLibrariesConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseLibrariesConfigurable.java @@ -30,9 +30,9 @@ import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider; import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryTableEditor; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; +import com.intellij.openapi.ui.*; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -40,15 +40,20 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; 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.DefaultTreeModel; +import javax.swing.tree.TreeNode; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; +import java.util.List; public abstract class BaseLibrariesConfigurable extends BaseStructureConfigurable { protected String myLevel; @@ -91,18 +96,28 @@ public abstract class BaseLibrariesConfigurable extends BaseStructureConfigurabl } protected void loadTree() { - final LibraryTablesRegistrar registrar = LibraryTablesRegistrar.getInstance(); - - final LibrariesModifiableModel provider = myContext.myLevel2Providers.get(myLevel); - createLibrariesNode(registrar.getLibraryTableByLevel(myLevel, myProject), provider, - myContext.createModifiableModelProvider(myLevel, false)); + final LibraryTable libraryTable = LibraryTablesRegistrar.getInstance().getLibraryTableByLevel(myLevel, myProject); + createLibrariesNode(myContext.createModifiableModelProvider(myLevel, false), new LibrariesModifiableModel(libraryTable, myProject)); } + @NotNull + @Override + protected Collection getProjectStructureElements() { + final List result = new ArrayList(); + //todo[nik] improve + for (int i = 0; i < myRoot.getChildCount(); i++) { + final TreeNode node = myRoot.getChildAt(i); + if (node instanceof MyNode) { + final NamedConfigurable configurable = ((MyNode)node).getConfigurable(); + if (configurable instanceof LibraryConfigurable) { + result.add(new LibraryProjectStructureElement(myContext, ((LibraryConfigurable)configurable).getEditableObject())); + } + } + } + return result; + } - private void createLibrariesNode(final LibraryTable table, - LibrariesModifiableModel provider, - final LibraryTableModifiableModelProvider modelProvider) { - provider = new LibrariesModifiableModel(table, myProject); + private void createLibrariesNode(final LibraryTableModifiableModelProvider modelProvider, final LibrariesModifiableModel provider) { final Library[] libraries = provider.getLibraries(); for (Library library : libraries) { myRoot.add(new MyNode(new LibraryConfigurable(modelProvider, library, myProject, TREE_UPDATER))); @@ -136,6 +151,7 @@ public abstract class BaseLibrariesConfigurable extends BaseStructureConfigurabl new LibraryConfigurable(myContext.createModifiableModelProvider(level, false), library, myProject, TREE_UPDATER); final MyNode node = new MyNode(configurable); addNode(node, myRoot); + myContext.getDaemonAnalyzer().queueUpdate(new LibraryProjectStructureElement(myContext, library)); return node; } @@ -178,8 +194,7 @@ public abstract class BaseLibrariesConfigurable extends BaseStructureConfigurabl final LibraryTable table = library.getTable(); if (table != null) { getModelProvider(true).getModifiableModel().removeLibrary(library); - myContext.invalidateModules(myContext.myLibraryDependencyCache.get(library)); - myContext.myLibraryDependencyCache.remove(library); + myContext.getDaemonAnalyzer().removeElement(new LibraryProjectStructureElement(myContext, library)); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java index 4e9f45d599..ba5f858e6a 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java @@ -18,7 +18,6 @@ package com.intellij.openapi.roots.ui.configuration.projectRoot; import com.intellij.facet.Facet; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.TreeExpander; -import com.intellij.ide.impl.convert.ProjectFileVersion; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.keymap.Keymap; @@ -31,10 +30,15 @@ import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureDaemonAnalyzer; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemDescription; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemsHolder; import com.intellij.openapi.ui.MasterDetailsComponent; import com.intellij.openapi.ui.NamedConfigurable; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Condition; +import com.intellij.packaging.artifacts.Artifact; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.TreeSpeedSearch; @@ -42,11 +46,9 @@ import com.intellij.ui.TreeToolTipHandler; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.navigation.Place; import com.intellij.util.Icons; -import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.containers.Convertor; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; -import com.intellij.packaging.artifacts.Artifact; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -74,7 +76,7 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i public void init(StructureConfigurableContext context) { myContext = context; - myContext.addCacheUpdateListener(new Runnable() { + myContext.getDaemonAnalyzer().addListener(new Runnable() { public void run() { if (!myTree.isShowing()) return; @@ -149,79 +151,52 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i if (value instanceof MyNode) { final MyNode node = (MyNode)value; - if (node.getConfigurable() == null) { + final NamedConfigurable namedConfigurable = node.getConfigurable(); + if (namedConfigurable == null) { return; } final String displayName = node.getDisplayName(); - final Icon icon = node.getConfigurable().getIcon(expanded); + final Icon icon = namedConfigurable.getIcon(expanded); setIcon(icon); setToolTipText(null); setFont(UIUtil.getTreeFont()); - if (node.isDisplayInBold()){ - append(displayName, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); - } else { - final Object object = node.getConfigurable().getEditableObject(); - final boolean unused = myContext.isUnused(object); - final StructureConfigurableContext.ValidityLevel level = myContext.isInvalid(object); - final boolean invalid = level != StructureConfigurableContext.ValidityLevel.VALID; - if (unused || invalid){ - Color fg = unused - ? UIUtil.getTextInactiveTextColor() - : selected && hasFocus ? UIUtil.getTreeSelectionForeground() : UIUtil.getTreeForeground(); - append(displayName, new SimpleTextAttributes(invalid ? SimpleTextAttributes.STYLE_WAVED : SimpleTextAttributes.STYLE_PLAIN, - fg, - level == StructureConfigurableContext.ValidityLevel.ERROR ? Color.RED : Color.GRAY)); - setToolTipText(composeTooltipMessage(invalid, object, displayName, unused)); - } - else { - append(displayName, selected && hasFocus ? SimpleTextAttributes.SELECTED_SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES); - } - } - } - } - }); - - } - - - private String composeTooltipMessage(final boolean invalid, final Object object, final String displayName, final boolean unused) { - final StringBuilder buf = StringBuilderSpinAllocator.alloc(); - try { - if (invalid) { - if (object instanceof Module) { - final Module module = (Module)object; - final Map> problems = myContext.myValidityCache.get(module); - - if (problems.containsKey(StructureConfigurableContext.DUPLICATE_MODULE_NAME)) { - buf.append(StructureConfigurableContext.DUPLICATE_MODULE_NAME).append("\n"); - } - if (problems.containsKey(StructureConfigurableContext.NO_JDK)){ - buf.append(StructureConfigurableContext.NO_JDK).append("\n"); - } - final Set deletedLibraries = problems.get(StructureConfigurableContext.DELETED_LIBRARIES); - if (deletedLibraries != null) { - buf.append(ProjectBundle.message("project.roots.library.problem.message", deletedLibraries.size())); - for (String problem : deletedLibraries) { - if (deletedLibraries.size() > 1) { - buf.append(" - "); + SimpleTextAttributes textAttributes = + selected && hasFocus ? SimpleTextAttributes.SELECTED_SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES; + if (node.isDisplayInBold()) { + textAttributes = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; + } else if (namedConfigurable instanceof ProjectStructureElementConfigurable) { + final ProjectStructureElement projectStructureElement = + ((ProjectStructureElementConfigurable)namedConfigurable).getProjectStructureElement(); + if (projectStructureElement != null) { + final ProjectStructureDaemonAnalyzer daemonAnalyzer = myContext.getDaemonAnalyzer(); + final boolean unused = daemonAnalyzer.isUnused(projectStructureElement); + final ProjectStructureProblemsHolder problemsHolder = daemonAnalyzer.getProblemsHolder(projectStructureElement); + if (problemsHolder == null) { + daemonAnalyzer.queueUpdate(projectStructureElement, true, false); + } + final ProjectStructureProblemDescription.Severity level = problemsHolder != null ? problemsHolder.getSeverity() : null; + final boolean invalid = level != null; + if (unused || invalid) { + Color fg = unused + ? UIUtil.getTextInactiveTextColor() + : selected && hasFocus ? UIUtil.getTreeSelectionForeground() : UIUtil.getTreeForeground(); + textAttributes = new SimpleTextAttributes(invalid ? SimpleTextAttributes.STYLE_WAVED : SimpleTextAttributes.STYLE_PLAIN, fg, + level == ProjectStructureProblemDescription.Severity.ERROR ? Color.RED : Color.GRAY); + String text = problemsHolder != null ? problemsHolder.composeTooltipMessage() : ""; + if (unused) { + text += ProjectBundle.message("project.roots.tooltip.unused", displayName); + } + setToolTipText(text); } - buf.append("\'").append(problem).append("\'").append("\n"); } } - } else { - buf.append(ProjectBundle.message("project.roots.tooltip.library.misconfigured", displayName)).append("\n"); + append(displayName, textAttributes); } } - if (unused) { - buf.append(ProjectBundle.message("project.roots.tooltip.unused", displayName)); - } - return buf.toString(); - } - finally { - StringBuilderSpinAllocator.dispose(buf); - } + }); + } public void disposeUIResources() { @@ -232,16 +207,12 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i myUiDisposed = true; myAutoScrollHandler.cancelAllRequests(); - myContext.myUpdateDependenciesAlarm.cancelAllRequests(); - myContext.myUpdateDependenciesAlarm.addRequest(new Runnable(){ + + SwingUtilities.invokeLater(new Runnable() { public void run() { - SwingUtilities.invokeLater(new Runnable(){ - public void run() { - dispose(); - } - }); + dispose(); } - }, 0); + }); } protected void addCollapseExpandActions(final List result) { @@ -267,6 +238,19 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i result.add(actionsManager.createCollapseAllAction(expander, myTree)); } + @Nullable + public ProjectStructureElement getSelectedElement() { + final TreePath selectionPath = myTree.getSelectionPath(); + if (selectionPath != null && selectionPath.getLastPathComponent() instanceof MyNode) { + MyNode node = (MyNode)selectionPath.getLastPathComponent(); + final NamedConfigurable configurable = node.getConfigurable(); + if (configurable instanceof ProjectStructureElementConfigurable) { + return ((ProjectStructureElementConfigurable)configurable).getProjectStructureElement(); + } + } + return null; + } + private class MyFindUsagesAction extends FindUsagesInProjectStructureActionBase { public MyFindUsagesAction(JComponent parentComponent) { @@ -287,8 +271,8 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i return myContext; } - protected Object getSelectedObject() { - return BaseStructureConfigurable.this.getSelectedObject(); + protected ProjectStructureElement getSelectedElement() { + return BaseStructureConfigurable.this.getSelectedElement(); } protected RelativePoint getPointToShowResults() { @@ -313,10 +297,18 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i myTree.setShowsRootHandles(false); loadTree(); } + for (ProjectStructureElement element : getProjectStructureElements()) { + myContext.getDaemonAnalyzer().queueUpdate(element, false, true); + } super.reset(); } + @NotNull + protected Collection getProjectStructureElements() { + return Collections.emptyList(); + } + protected abstract void loadTree(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FindUsagesInProjectStructureActionBase.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FindUsagesInProjectStructureActionBase.java index 05c52edaef..3600e72ef4 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FindUsagesInProjectStructureActionBase.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FindUsagesInProjectStructureActionBase.java @@ -20,36 +20,29 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.module.Module; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.ModuleRootModel; -import com.intellij.openapi.roots.OrderEntry; -import com.intellij.openapi.roots.impl.OrderEntryUtil; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; -import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElementUsage; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.IconLoader; import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Set; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; /** * @author nik */ public abstract class FindUsagesInProjectStructureActionBase extends AnAction implements DumbAware { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.projectRoot.FindUsagesInProjectStructureActionBase"); private static final Icon FIND_ICON = IconLoader.getIcon("/actions/find.png"); private final JComponent myParentComponent; private final Project myProject; @@ -68,60 +61,46 @@ public abstract class FindUsagesInProjectStructureActionBase extends AnAction im protected abstract boolean isEnabled(); public void actionPerformed(AnActionEvent e) { - final Object selectedObject = getSelectedObject(); - if (selectedObject == null) return; + final ProjectStructureElement selected = getSelectedElement(); + if (selected == null) return; - final Set dependencies = getContext().getCachedDependencies(selectedObject, true); - if (dependencies == null || dependencies.isEmpty()) { - Messages.showInfoMessage(myParentComponent, FindBundle.message("find.usage.view.no.usages.text"), - FindBundle.message("find.pointcut.applications.not.found.title")); + final Collection usages = getContext().getDaemonAnalyzer().getUsages(selected); + if (usages.isEmpty()) { + Messages.showInfoMessage(myParentComponent, FindBundle.message("find.usage.view.no.usages.text"), FindBundle.message("find.pointcut.applications.not.found.title")); return; } - RelativePoint point = getPointToShowResults(); - JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep(ProjectBundle.message("dependencies.used.in.popup.title"), - ArrayUtil.toStringArray(dependencies)) { - public PopupStep onChosen(final String nameToSelect, final boolean finalChoice) { - navigateToObject(nameToSelect, selectedObject); + RelativePoint point = getPointToShowResults(); + final ProjectStructureElementUsage[] usagesArray = usages.toArray(new ProjectStructureElementUsage[usages.size()]); + Arrays.sort(usagesArray, new Comparator() { + public int compare(ProjectStructureElementUsage o1, ProjectStructureElementUsage o2) { + return o1.getPresentableName().compareToIgnoreCase(o2.getPresentableName()); + } + }); + + JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep(ProjectBundle.message("dependencies.used.in.popup.title"), usagesArray) { + @Override + public PopupStep onChosen(final ProjectStructureElementUsage selected, final boolean finalChoice) { + selected.navigate(); return FINAL_CHOICE; } - public Icon getIconFor(String selection) { - final Module module = getContext().myModulesConfigurator.getModule(selection); - LOG.assertTrue(module != null, selection + " was not found"); - return module.getModuleType().getNodeIcon(false); + @NotNull + @Override + public String getTextFor(ProjectStructureElementUsage value) { + return value.getPresentableName(); } - }).show(point); - } - - private void navigateToObject(final String moduleName, final @NotNull Object selectedObject) { - ModulesConfigurator modulesConfigurator = getContext().myModulesConfigurator; - Module module = modulesConfigurator.getModule(moduleName); - if (module == null) { - ProjectStructureConfigurable.getInstance(myProject).select(moduleName, null, true); - return; - } + @Override + public Icon getIconFor(ProjectStructureElementUsage selection) { + return selection.getIcon(); + } - ModuleRootModel rootModel = modulesConfigurator.getRootModel(module); - OrderEntry entry; - if (selectedObject instanceof Library) { - entry = OrderEntryUtil.findLibraryOrderEntry(rootModel, (Library)selectedObject); - } - else if (selectedObject instanceof Module) { - entry = OrderEntryUtil.findModuleOrderEntry(rootModel, (Module)selectedObject); - } - else if (selectedObject instanceof Sdk) { - entry = OrderEntryUtil.findJdkOrderEntry(rootModel, (Sdk)selectedObject); - } - else { - entry = null; - } - ModuleStructureConfigurable.getInstance(myProject).selectOrderEntry(module, entry); + }).show(point); } @Nullable - protected abstract Object getSelectedObject(); + protected abstract ProjectStructureElement getSelectedElement(); protected StructureConfigurableContext getContext() { return ModuleStructureConfigurable.getInstance(myProject).getContext(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java index 300a7617ee..4f2ff5c95c 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java @@ -17,11 +17,13 @@ package com.intellij.openapi.roots.ui.configuration.projectRoot; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.projectRoots.ui.SdkEditor; -import com.intellij.openapi.ui.NamedConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.SdkProjectStructureElement; import com.intellij.openapi.util.ActionCallback; import com.intellij.ui.navigation.History; import com.intellij.ui.navigation.Place; @@ -35,16 +37,24 @@ import javax.swing.*; * User: anna * Date: 05-Jun-2006 */ -public class JdkConfigurable extends NamedConfigurable implements Place.Navigator { +public class JdkConfigurable extends ProjectStructureElementConfigurable implements Place.Navigator { private final ProjectJdkImpl myProjectJdk; private final SdkEditor mySdkEditor; + private SdkProjectStructureElement myProjectStructureElement; public JdkConfigurable(final ProjectJdkImpl projectJdk, final ProjectJdksModel configurable, - final Runnable updateTree, @NotNull History history) { + final Runnable updateTree, @NotNull History history, Project project) { super(true, updateTree); myProjectJdk = projectJdk; mySdkEditor = new SdkEditor(configurable, history, myProjectJdk); + final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(project).getContext(); + myProjectStructureElement = new SdkProjectStructureElement(context, myProjectJdk); + } + + @Override + public ProjectStructureElement getProjectStructureElement() { + return myProjectStructureElement; } public void setDisplayName(final String name) { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkListConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkListConfigurable.java index 531d5a90ee..1204e297a5 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkListConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkListConfigurable.java @@ -29,16 +29,22 @@ import com.intellij.openapi.projectRoots.SdkModel; import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.SdkProjectStructureElement; import com.intellij.openapi.ui.MasterDetailsComponent; import com.intellij.openapi.ui.NamedConfigurable; import com.intellij.util.Consumer; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.TreePath; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.List; @State( name = "JdkListConfigurable.UI", @@ -120,14 +126,26 @@ public class JdkListConfigurable extends BaseStructureConfigurable { protected void loadTree() { final HashMap sdks = myJdksTreeModel.getProjectJdks(); for (Sdk sdk : sdks.keySet()) { - final JdkConfigurable configurable = new JdkConfigurable((ProjectJdkImpl)sdks.get(sdk), myJdksTreeModel, TREE_UPDATER, myHistory); + final JdkConfigurable configurable = new JdkConfigurable((ProjectJdkImpl)sdks.get(sdk), myJdksTreeModel, TREE_UPDATER, myHistory, + myProject); addNode(new MyNode(configurable), myRoot); } } + @NotNull + @Override + protected Collection getProjectStructureElements() { + final List result = new ArrayList(); + for (Sdk sdk : myJdksTreeModel.getProjectJdks().values()) { + result.add(new SdkProjectStructureElement(myContext, sdk)); + } + return result; + } + public boolean addJdkNode(final Sdk jdk, final boolean selectInTree) { if (!myUiDisposed) { - addNode(new MyNode(new JdkConfigurable((ProjectJdkImpl)jdk, myJdksTreeModel, TREE_UPDATER, myHistory)), myRoot); + myContext.getDaemonAnalyzer().queueUpdate(new SdkProjectStructureElement(myContext, jdk)); + addNode(new MyNode(new JdkConfigurable((ProjectJdkImpl)jdk, myJdksTreeModel, TREE_UPDATER, myHistory, myProject)), myRoot); if (selectInTree) { selectNodeInTree(MasterDetailsComponent.findNodeByObject(myRoot, jdk)); } @@ -188,8 +206,7 @@ public class JdkListConfigurable extends BaseStructureConfigurable { protected void removeJdk(final Sdk jdk) { myJdksTreeModel.removeJdk(jdk); - myContext.myJdkDependencyCache.remove(jdk); - myContext.myValidityCache.clear(); + myContext.getDaemonAnalyzer().removeElement(new SdkProjectStructureElement(myContext, jdk)); } protected diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/LibraryConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/LibraryConfigurable.java index 469f746707..ef49eb2026 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/LibraryConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/LibraryConfigurable.java @@ -24,7 +24,8 @@ import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider; import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor; import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryTableEditor; -import com.intellij.openapi.ui.NamedConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import org.jetbrains.annotations.NonNls; @@ -36,13 +37,14 @@ import javax.swing.*; * User: anna * Date: 02-Jun-2006 */ -public class LibraryConfigurable extends NamedConfigurable { +public class LibraryConfigurable extends ProjectStructureElementConfigurable { private static final Icon ICON = IconLoader.getIcon("/modules/library.png"); private LibraryTableEditor myLibraryEditor; private final Library myLibrary; private final LibraryTableModifiableModelProvider myModel; private final Project myProject; + private final LibraryProjectStructureElement myProjectStructureElement; protected LibraryConfigurable(final LibraryTableModifiableModelProvider libraryTable, final Library library, @@ -52,10 +54,17 @@ public class LibraryConfigurable extends NamedConfigurable { myModel = libraryTable; myProject = project; myLibrary = library; + final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(myProject).getContext(); + myProjectStructureElement = new LibraryProjectStructureElement(context, myLibrary); } public JComponent createOptionsPanel() { myLibraryEditor = LibraryTableEditor.editLibrary(myModel, myLibrary, myProject); + myLibraryEditor.addListener(new Runnable() { + public void run() { + ModuleStructureConfigurable.getInstance(myProject).getContext().getDaemonAnalyzer().queueUpdate(myProjectStructureElement); + } + }); return myLibraryEditor.getComponent(); } @@ -63,6 +72,11 @@ public class LibraryConfigurable extends NamedConfigurable { return myLibraryEditor != null && myLibraryEditor.hasChanges(); } + @Override + public ProjectStructureElement getProjectStructureElement() { + return myProjectStructureElement; + } + public void apply() throws ConfigurationException { //do nothing } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleConfigurable.java index 24a3faf699..aa645ed865 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleConfigurable.java @@ -23,12 +23,13 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.ui.configuration.ModuleEditor; import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; -import com.intellij.openapi.ui.NamedConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.navigation.Place; import com.intellij.ui.navigation.History; +import com.intellij.ui.navigation.Place; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,10 +40,11 @@ import javax.swing.*; * User: anna * Date: 04-Jun-2006 */ -public class ModuleConfigurable extends NamedConfigurable implements Place.Navigator { +public class ModuleConfigurable extends ProjectStructureElementConfigurable implements Place.Navigator { private final Module myModule; private final ModulesConfigurator myConfigurator; private String myModuleName; + private final ModuleProjectStructureElement myProjectStructureElement; public ModuleConfigurable(ModulesConfigurator modulesConfigurator, Module module, @@ -51,6 +53,8 @@ public class ModuleConfigurable extends NamedConfigurable implements Pla myModule = module; myModuleName = myModule.getName(); myConfigurator = modulesConfigurator; + final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(myModule.getProject()).getContext(); + myProjectStructureElement = new ModuleProjectStructureElement(context, myModule); } public void setDisplayName(String name) { @@ -69,6 +73,11 @@ public class ModuleConfigurable extends NamedConfigurable implements Pla myConfigurator.setModified(!Comparing.strEqual(myModuleName, myModule.getName())); } + @Override + public ProjectStructureElement getProjectStructureElement() { + return myProjectStructureElement; + } + public Module getEditableObject() { return myModule; } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java index 48618138ac..2fb605327e 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java @@ -47,6 +47,7 @@ import com.intellij.openapi.roots.ui.configuration.ClasspathEditor; import com.intellij.openapi.roots.ui.configuration.ModuleEditor; import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.*; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.NamedConfigurable; @@ -136,6 +137,16 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple myUiDisposed = false; } + @NotNull + @Override + protected Collection getProjectStructureElements() { + final List result = new ArrayList(); + for (Module module : myModuleManager.getModules()) { + result.add(new ModuleProjectStructureElement(myContext, module)); + } + return result; + } + protected void updateSelection(@Nullable final NamedConfigurable configurable) { FacetStructureConfigurable.getInstance(myProject).disposeMultipleSettingsEditor(); ApplicationManager.getApplication().assertIsDispatchThread(); @@ -299,7 +310,7 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple node.removeFromParent(); ((DefaultTreeModel)myTree.getModel()).reload(parent); } - myContext.invalidateModules(myContext.myLibraryDependencyCache.get(library)); + myContext.getDaemonAnalyzer().removeElement(new LibraryProjectStructureElement(myContext, library)); } } @@ -331,7 +342,6 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple public void disposeUIResources() { super.disposeUIResources(); myFacetEditorFacade.clearMaps(); - myContext.clearCaches(); myContext.myModulesConfigurator.disposeUIResources(); ModuleStructureConfigurable.super.disposeUIResources(); } @@ -445,12 +455,7 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple } } modelProxy.addLibraryEntry(library); - Set modules = myContext.myLibraryDependencyCache.get(library); - if (modules == null) { - modules = new HashSet(); - myContext.myLibraryDependencyCache.put(library, modules); - } - modules.add(module.getName()); + myContext.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(myContext, module)); myTree.repaint(); } @@ -500,7 +505,9 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple myFacetEditorFacade.addFacetsNodes(module, node); ((DefaultTreeModel)myTree.getModel()).reload(parent); selectNodeInTree(node); - myContext.myValidityCache.clear(); //missing modules added + final ProjectStructureDaemonAnalyzer daemonAnalyzer = myContext.getDaemonAnalyzer(); + daemonAnalyzer.queueUpdate(new ModuleProjectStructureElement(myContext, module)); + daemonAnalyzer.clearAllProblems(); //missing modules added } @Nullable @@ -670,9 +677,7 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple } List removed = modulesConfigurator.getFacetsConfigurator().removeAllFacets(module); FacetStructureConfigurable.getInstance(myProject).removeFacetNodes(removed); - myContext.myValidityCache.remove(module); - myContext.invalidateModules(myContext.myModulesDependencyCache.get(module)); - myContext.myModulesDependencyCache.remove(module); + myContext.getDaemonAnalyzer().removeElement(new ModuleProjectStructureElement(myContext, module)); return true; } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectStructureElementConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectStructureElementConfigurable.java new file mode 100644 index 0000000000..e44c95fd17 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectStructureElementConfigurable.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2009 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.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; +import com.intellij.openapi.ui.NamedConfigurable; +import org.jetbrains.annotations.Nullable; + +/** + * @author nik + */ +public abstract class ProjectStructureElementConfigurable extends NamedConfigurable { + protected ProjectStructureElementConfigurable() { + } + + protected ProjectStructureElementConfigurable(boolean isNameEditable, @Nullable Runnable updateTree) { + super(isNameEditable, updateTree); + } + + @Nullable + public abstract ProjectStructureElement getProjectStructureElement(); + +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/StructureConfigurableContext.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/StructureConfigurableContext.java dissimilarity index 70% index eb05e617dd..cae23c6c7e 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/StructureConfigurableContext.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/StructureConfigurableContext.java @@ -1,499 +1,156 @@ -/* - * Copyright 2000-2009 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.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.module.ModifiableModuleModel; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.roots.impl.libraries.LibraryEx; -import com.intellij.openapi.roots.impl.libraries.LibraryImpl; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.roots.libraries.LibraryTable; -import com.intellij.openapi.roots.libraries.LibraryTablePresentation; -import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; -import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider; -import com.intellij.openapi.roots.ui.configuration.ModuleEditor; -import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Condition; -import com.intellij.util.Alarm; -import com.intellij.util.NotNullFunction; -import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashMap; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.util.*; - -public class StructureConfigurableContext implements Disposable { - private static final Logger LOG = Logger.getInstance("#" + StructureConfigurableContext.class.getName()); - - public enum ValidityLevel { VALID, WARNING, ERROR } - - public static final String NO_JDK = ProjectBundle.message("project.roots.module.jdk.problem.message"); - public static final String DUPLICATE_MODULE_NAME = ProjectBundle.message("project.roots.module.duplicate.name.message"); - @NonNls public static final String DELETED_LIBRARIES = "lib"; - - public final Map> myLibraryDependencyCache = new HashMap>(); - public final Map> myJdkDependencyCache = new HashMap>(); - public final Map>> myValidityCache = new HashMap>>(); - public final Map myLibraryPathValidityCache = new HashMap(); //can be invalidated on startup only - public final Map> myModulesDependencyCache = new HashMap>(); - - private final ModuleManager myModuleManager; - public final ModulesConfigurator myModulesConfigurator; - private boolean myDisposed; - - public final Alarm myUpdateDependenciesAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD); - public final Alarm myReloadProjectAlarm = new Alarm(); - - private final List myCacheUpdaters = new ArrayList(); - - - public final Map myLevel2Providers = new THashMap(); - private final Project myProject; - - - public StructureConfigurableContext(Project project, final ModuleManager moduleManager, final ModulesConfigurator modulesConfigurator) { - myProject = project; - myModuleManager = moduleManager; - myModulesConfigurator = modulesConfigurator; - } - - @Nullable - public Set getCachedDependencies(final Object selectedObject, boolean force) { - if (selectedObject instanceof Library){ - final Library library = (Library)selectedObject; - if (myLibraryDependencyCache.containsKey(library)){ - return myLibraryDependencyCache.get(library); - } - } else if (selectedObject instanceof Sdk){ - final Sdk projectJdk = (Sdk)selectedObject; - if (myJdkDependencyCache.containsKey(projectJdk)){ - return myJdkDependencyCache.get(projectJdk); - } - } else if (selectedObject instanceof Module) { - final Module module = (Module)selectedObject; - if (myModulesDependencyCache.containsKey(module)) { - return myModulesDependencyCache.get(module); - } - } - if (force){ - LOG.assertTrue(ApplicationManager.getApplication().isDispatchThread()); - final Set dep = getDependencies(selectedObject); - updateCache(selectedObject, dep); - return dep; - } else { - myUpdateDependenciesAlarm.addRequest(new Runnable(){ - public void run() { - final Set dep = getDependencies(selectedObject); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (!myDisposed) { - updateCache(selectedObject, dep); - fireOnCacheChanged(); - } - } - }); - } - }, 100); - return null; - } - } - - private void updateCache(final Object selectedObject, final Set dep) { - if (selectedObject instanceof Library) { - myLibraryDependencyCache.put((Library)selectedObject, dep); - } - else if (selectedObject instanceof Sdk) { - myJdkDependencyCache.put((Sdk)selectedObject, dep); - } - else if (selectedObject instanceof Module) { - myModulesDependencyCache.put((Module)selectedObject, dep); - } - } - - private Set getDependencies(final Condition condition) { - final Set result = new TreeSet(); - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - final Module[] modules = myModulesConfigurator.getModules(); - for (final Module module : modules) { - final ModuleEditor moduleEditor = myModulesConfigurator.getModuleEditor(module); - if (moduleEditor != null) { - final OrderEntry[] entries = moduleEditor.getOrderEntries(); - for (OrderEntry entry : entries) { - if (myDisposed) return; - if (condition.value(entry)) { - result.add(module.getName()); - break; - } - } - } - } - } - }); - return result; - } - - @Nullable - private Set getDependencies(final Object selectedObject) { - if (selectedObject instanceof Module) { - return getDependencies(new Condition() { - public boolean value(final OrderEntry orderEntry) { - return orderEntry instanceof ModuleOrderEntry && Comparing.equal(((ModuleOrderEntry)orderEntry).getModule(), selectedObject); - } - }); - } - else if (selectedObject instanceof Library) { - Library library = (Library)selectedObject; - if (library.getTable() == null) { //module library navigation - HashSet deps = new HashSet(); - Module module = ((LibraryImpl)library).getModule(); - if (module != null) { - deps.add(module.getName()); - } - return deps; - } - return getDependencies(new Condition() { - @SuppressWarnings({"SimplifiableIfStatement"}) - public boolean value(final OrderEntry orderEntry) { - if (orderEntry instanceof LibraryOrderEntry){ - final LibraryImpl library = (LibraryImpl)((LibraryOrderEntry)orderEntry).getLibrary(); - if (Comparing.equal(library, selectedObject)) return true; - return library != null && Comparing.equal(library.getSource(), selectedObject); - } - return false; - } - }); - } - else if (selectedObject instanceof Sdk) { - return getDependencies(new Condition() { - public boolean value(final OrderEntry orderEntry) { - return orderEntry instanceof JdkOrderEntry && Comparing.equal(((JdkOrderEntry)orderEntry).getJdk(), selectedObject); - } - }); - } - return null; - } - - public void dispose() { - clearCaches(); - myDisposed = true; - } - - public void invalidateModules(final Set modules) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (modules != null) { - for (String module : modules) { - myValidityCache.remove(myModuleManager.findModuleByName(module)); - } - } - } - }); - } - public void invalidateModuleName(final Module module) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - final Map> problems = myValidityCache.remove(module); - if (problems != null) { - fireOnCacheChanged(); - } - } - }); - } - - public ModulesConfigurator getModulesConfigurator() { - return myModulesConfigurator; - } - - public void clearCaches() { - myJdkDependencyCache.clear(); - myLibraryDependencyCache.clear(); - myValidityCache.clear(); - myLibraryPathValidityCache.clear(); - myModulesDependencyCache.clear(); - myCacheUpdaters.clear(); - } - - public void clearCaches(final Module module, final List chosen) { - LOG.assertTrue(ApplicationManager.getApplication().isDispatchThread()); - for (Library library : chosen) { - myLibraryDependencyCache.remove(library); - } - myValidityCache.remove(module); - fireOnCacheChanged(); - } - - public void clearCaches(final Module module, final Sdk oldJdk, final Sdk selectedModuleJdk) { - LOG.assertTrue(ApplicationManager.getApplication().isDispatchThread()); - myJdkDependencyCache.remove(oldJdk); - myJdkDependencyCache.remove(selectedModuleJdk); - myValidityCache.remove(module); - fireOnCacheChanged(); - } - - public void clearCaches(final OrderEntry entry) { - LOG.assertTrue(ApplicationManager.getApplication().isDispatchThread()); - if (entry instanceof ModuleOrderEntry) { - final Module module = ((ModuleOrderEntry)entry).getModule(); - myValidityCache.remove(module); - myModulesDependencyCache.remove(module); - } else if (entry instanceof JdkOrderEntry) { - invalidateModules(myJdkDependencyCache.remove(((JdkOrderEntry)entry).getJdk())); - } else if (entry instanceof LibraryOrderEntry) { - invalidateModules(myLibraryDependencyCache.remove(((LibraryOrderEntry)entry).getLibrary())); - } - fireOnCacheChanged(); - } - - public ValidityLevel isInvalid(final Object object) { - if (object instanceof Module){ - final Module module = (Module)object; - if (myValidityCache.containsKey(module)) { - boolean valid = myValidityCache.get(module) == null; - return valid ? ValidityLevel.VALID : ValidityLevel.ERROR; - } - myUpdateDependenciesAlarm.addRequest(new Runnable(){ - public void run() { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - updateModuleValidityCache(module); - } - }); - } - }, 100); - } else if (object instanceof LibraryEx) { - final LibraryEx library = (LibraryEx)object; - if (myLibraryPathValidityCache.containsKey(library)) return myLibraryPathValidityCache.get(library); - myUpdateDependenciesAlarm.addRequest(new Runnable(){ - public void run() { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - updateLibraryValidityCache(library); - } - }); - } - }, 100); - } - return ValidityLevel.VALID; - } - - private void updateLibraryValidityCache(final LibraryEx library) { - if (myLibraryPathValidityCache.containsKey(library)) return; //do not check twice - ValidityLevel level = ValidityLevel.VALID; - if (!(library.allPathsValid(JavadocOrderRootType.getInstance()) && library.allPathsValid(OrderRootType.SOURCES))) { - level = ValidityLevel.WARNING; - } - if (!library.allPathsValid(OrderRootType.CLASSES)) { - level = ValidityLevel.ERROR; - } - - final ValidityLevel finalLevel = level; - SwingUtilities.invokeLater(new Runnable(){ - public void run() { - if (!myDisposed){ - myLibraryPathValidityCache.put(library, finalLevel); - fireOnCacheChanged(); - } - } - }); - } - - private void updateModuleValidityCache(final Module module) { - if (myValidityCache.containsKey(module)) return; //do not check twice - - if (myDisposed) return; - - Map> problems = null; - final ModifiableModuleModel moduleModel = myModulesConfigurator.getModuleModel(); - final Module[] all = moduleModel.getModules(); - for (Module each : all) { - if (each != module && getRealName(each).equals(getRealName(module))) { - problems = new HashMap>(); - problems.put(DUPLICATE_MODULE_NAME, null); - break; - } - } - - final ModuleRootModel rootModel = myModulesConfigurator.getRootModel(module); - if (rootModel == null) return; //already disposed - final OrderEntry[] entries = rootModel.getOrderEntries(); - for (OrderEntry entry : entries) { - if (myDisposed) return; - if (!entry.isValid()){ - if (problems == null) { - problems = new HashMap>(); - } - if (entry instanceof JdkOrderEntry && ((JdkOrderEntry)entry).getJdkName() == null) { - problems.put(NO_JDK, null); - } else { - Set deletedLibraries = problems.get(DELETED_LIBRARIES); - if (deletedLibraries == null){ - deletedLibraries = new HashSet(); - problems.put(DELETED_LIBRARIES, deletedLibraries); - } - deletedLibraries.add(entry.getPresentableName()); - } - } - } - final Map> finalProblems = problems; - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (!myDisposed) { - myValidityCache.put(module, finalProblems); - fireOnCacheChanged(); - } - } - }); - } - - public Module[] getModules() { - return myModulesConfigurator.getModules(); - } - - public String getRealName(final Module module) { - final ModifiableModuleModel moduleModel = myModulesConfigurator.getModuleModel(); - String newName = moduleModel.getNewName(module); - return newName != null ? newName : module.getName(); - } - - public boolean isUnused(final Object object) { - if (object == null) return false; - if (object instanceof Module){ - getCachedDependencies(object, false); - return false; - } - if (object instanceof Sdk) { - return false; - } - if (object instanceof Library) { - final LibraryTable libraryTable = ((Library)object).getTable(); - if (libraryTable == null || !libraryTable.getTableLevel().equals(LibraryTablesRegistrar.PROJECT_LEVEL)) { - return false; - } - } - final Set dependencies = getCachedDependencies(object, false); - return dependencies != null && dependencies.isEmpty(); - } - - private void fireOnCacheChanged() { - final Runnable[] all = myCacheUpdaters.toArray(new Runnable[myCacheUpdaters.size()]); - for (Runnable each : all) { - each.run(); - } - } - - public void addReloadProjectRequest(final Runnable runnable) { - myReloadProjectAlarm.cancelAllRequests(); - myReloadProjectAlarm.addRequest(runnable, 300, ModalityState.NON_MODAL); - } - - - public void resetLibraries() { - final LibraryTablesRegistrar tablesRegistrar = LibraryTablesRegistrar.getInstance(); - - myLevel2Providers.clear(); - myLevel2Providers.put(LibraryTablesRegistrar.APPLICATION_LEVEL, new LibrariesModifiableModel(tablesRegistrar.getLibraryTable(), myProject)); - myLevel2Providers.put(LibraryTablesRegistrar.PROJECT_LEVEL, new LibrariesModifiableModel(tablesRegistrar.getLibraryTable(myProject), myProject)); - for (final LibraryTable table : tablesRegistrar.getCustomLibraryTables()) { - myLevel2Providers.put(table.getTableLevel(), new LibrariesModifiableModel(table, myProject)); - } - } - - public LibraryTableModifiableModelProvider getGlobalLibrariesProvider(final boolean tableEditable) { - return createModifiableModelProvider(LibraryTablesRegistrar.APPLICATION_LEVEL, tableEditable); - } - - public LibraryTableModifiableModelProvider createModifiableModelProvider(final String level, final boolean isTableEditable) { - final LibraryTable table = LibraryTablesRegistrar.getInstance().getLibraryTableByLevel(level, myProject); - return new LibraryTableModifiableModelProvider() { - public LibraryTable.ModifiableModel getModifiableModel() { - return myLevel2Providers.get(level); - } - - public String getTableLevel() { - return table.getTableLevel(); - } - - public LibraryTablePresentation getLibraryTablePresentation() { - return table.getPresentation(); - } - - public boolean isLibraryTableEditable() { - return isTableEditable && table.isEditable(); - } - }; - } - - public LibraryTableModifiableModelProvider getProjectLibrariesProvider(final boolean tableEditable) { - return createModifiableModelProvider(LibraryTablesRegistrar.PROJECT_LEVEL, tableEditable); - } - - - public List getCustomLibrariesProviders(final boolean tableEditable) { - return ContainerUtil.map2List(LibraryTablesRegistrar.getInstance().getCustomLibraryTables(), new NotNullFunction() { - @NotNull - public LibraryTableModifiableModelProvider fun(final LibraryTable libraryTable) { - return createModifiableModelProvider(libraryTable.getTableLevel(), tableEditable); - } - }); - } - - - @Nullable - public Library getLibrary(final String libraryName, final String libraryLevel) { -/* the null check is added only to prevent NPE when called from getLibrary */ - if (myLevel2Providers.isEmpty()) resetLibraries(); - final LibrariesModifiableModel model = myLevel2Providers.get(libraryLevel); - return model == null ? null : findLibraryModel(libraryName, model); - } - - @Nullable - private static Library findLibraryModel(final String libraryName, @NotNull LibrariesModifiableModel model) { - final Library library = model.getLibraryByName(libraryName); - return findLibraryModel(library, model); - } - - @Nullable - private static Library findLibraryModel(final Library library, LibrariesModifiableModel tableModel) { - if (tableModel == null) return library; - if (tableModel.wasLibraryRemoved(library)) return null; - return tableModel.hasLibraryEditor(library) ? (Library)tableModel.getLibraryEditor(library).getModel() : library; - } - - - public void reset() { - myDisposed = false; - resetLibraries(); - myModulesConfigurator.resetModuleEditors(); - } - - public void addCacheUpdateListener(Runnable runnable) { - myCacheUpdaters.add(runnable); - } -} +/* + * Copyright 2000-2009 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.openapi.Disposable; +import com.intellij.openapi.module.ModifiableModuleModel; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.roots.libraries.LibraryTablePresentation; +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; +import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider; +import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureDaemonAnalyzer; +import com.intellij.openapi.util.Disposer; +import com.intellij.util.NotNullFunction; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class StructureConfigurableContext implements Disposable { + private final ProjectStructureDaemonAnalyzer myDaemonAnalyzer; + public final ModulesConfigurator myModulesConfigurator; + public final Map myLevel2Providers = new THashMap(); + private final Project myProject; + + + public StructureConfigurableContext(Project project, final ModulesConfigurator modulesConfigurator) { + myProject = project; + myModulesConfigurator = modulesConfigurator; + Disposer.register(project, this); + myDaemonAnalyzer = new ProjectStructureDaemonAnalyzer(this); + } + + public Project getProject() { + return myProject; + } + + public ProjectStructureDaemonAnalyzer getDaemonAnalyzer() { + return myDaemonAnalyzer; + } + + public void dispose() { + } + + public ModulesConfigurator getModulesConfigurator() { + return myModulesConfigurator; + } + + public Module[] getModules() { + return myModulesConfigurator.getModules(); + } + + public String getRealName(final Module module) { + final ModifiableModuleModel moduleModel = myModulesConfigurator.getModuleModel(); + String newName = moduleModel.getNewName(module); + return newName != null ? newName : module.getName(); + } + + public void resetLibraries() { + final LibraryTablesRegistrar tablesRegistrar = LibraryTablesRegistrar.getInstance(); + + myLevel2Providers.clear(); + myLevel2Providers.put(LibraryTablesRegistrar.APPLICATION_LEVEL, new LibrariesModifiableModel(tablesRegistrar.getLibraryTable(), myProject)); + myLevel2Providers.put(LibraryTablesRegistrar.PROJECT_LEVEL, new LibrariesModifiableModel(tablesRegistrar.getLibraryTable(myProject), myProject)); + for (final LibraryTable table : tablesRegistrar.getCustomLibraryTables()) { + myLevel2Providers.put(table.getTableLevel(), new LibrariesModifiableModel(table, myProject)); + } + } + + public LibraryTableModifiableModelProvider getGlobalLibrariesProvider(final boolean tableEditable) { + return createModifiableModelProvider(LibraryTablesRegistrar.APPLICATION_LEVEL, tableEditable); + } + + public LibraryTableModifiableModelProvider createModifiableModelProvider(final String level, final boolean isTableEditable) { + final LibraryTable table = LibraryTablesRegistrar.getInstance().getLibraryTableByLevel(level, myProject); + return new LibraryTableModifiableModelProvider() { + public LibraryTable.ModifiableModel getModifiableModel() { + return myLevel2Providers.get(level); + } + + public String getTableLevel() { + return table.getTableLevel(); + } + + public LibraryTablePresentation getLibraryTablePresentation() { + return table.getPresentation(); + } + + public boolean isLibraryTableEditable() { + return isTableEditable && table.isEditable(); + } + }; + } + + public LibraryTableModifiableModelProvider getProjectLibrariesProvider(final boolean tableEditable) { + return createModifiableModelProvider(LibraryTablesRegistrar.PROJECT_LEVEL, tableEditable); + } + + + public List getCustomLibrariesProviders(final boolean tableEditable) { + return ContainerUtil.map2List(LibraryTablesRegistrar.getInstance().getCustomLibraryTables(), new NotNullFunction() { + @NotNull + public LibraryTableModifiableModelProvider fun(final LibraryTable libraryTable) { + return createModifiableModelProvider(libraryTable.getTableLevel(), tableEditable); + } + }); + } + + + @Nullable + public Library getLibrary(final String libraryName, final String libraryLevel) { +/* the null check is added only to prevent NPE when called from getLibrary */ + if (myLevel2Providers.isEmpty()) resetLibraries(); + final LibrariesModifiableModel model = myLevel2Providers.get(libraryLevel); + return model == null ? null : findLibraryModel(libraryName, model); + } + + @Nullable + private static Library findLibraryModel(final String libraryName, @NotNull LibrariesModifiableModel model) { + final Library library = model.getLibraryByName(libraryName); + return findLibraryModel(library, model); + } + + @Nullable + private static Library findLibraryModel(final Library library, LibrariesModifiableModel tableModel) { + if (tableModel == null) return library; + if (tableModel.wasLibraryRemoved(library)) return null; + return tableModel.hasLibraryEditor(library) ? (Library)tableModel.getLibraryEditor(library).getModel() : library; + } + + + public void reset() { + myDaemonAnalyzer.reset(); + resetLibraries(); + myModulesConfigurator.resetModuleEditors(); + } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/LibraryProjectStructureElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/LibraryProjectStructureElement.java new file mode 100644 index 0000000000..31f7dbe021 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/LibraryProjectStructureElement.java @@ -0,0 +1,78 @@ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import com.intellij.openapi.project.ProjectBundle; +import com.intellij.openapi.roots.JavadocOrderRootType; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.impl.libraries.LibraryEx; +import com.intellij.openapi.roots.impl.libraries.LibraryImpl; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * @author nik + */ +public class LibraryProjectStructureElement extends ProjectStructureElement { + private final Library myLibrary; + + public LibraryProjectStructureElement(@NotNull StructureConfigurableContext context, @NotNull Library library) { + super(context); + myLibrary = library; + } + + public Library getLibrary() { + return myLibrary; + } + + @Override + public void check(ProjectStructureProblemsHolder problemsHolder) { + final LibraryEx library = (LibraryEx)myLibrary; + final String libraryName = myLibrary.getName();//todo[nik] get modified name? + if (!library.allPathsValid(OrderRootType.CLASSES)) { + problemsHolder.addError(ProjectBundle.message("project.roots.tooltip.library.misconfigured", libraryName)); + } + else if (!library.allPathsValid(JavadocOrderRootType.getInstance()) || !library.allPathsValid(OrderRootType.SOURCES)) { + problemsHolder.addWarning(ProjectBundle.message("project.roots.tooltip.library.misconfigured", libraryName)); + } + } + + @Override + public List getUsagesInElement() { + return Collections.emptyList(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LibraryProjectStructureElement)) return false; + + return getSourceOrThis().equals(((LibraryProjectStructureElement)o).getSourceOrThis()); + } + + @NotNull + private Library getSourceOrThis() { + final Library source = ((LibraryImpl)myLibrary).getSource(); + return source != null ? source : myLibrary; + } + + @Override + public int hashCode() { + return getSourceOrThis().hashCode(); + } + + @Override + public String toString() { + return "library:" + myLibrary.getName(); + } + + @Override + public boolean highlightIfUnused() { + final LibraryTable libraryTable = myLibrary.getTable(); + return libraryTable != null && LibraryTablesRegistrar.PROJECT_LEVEL.equals(libraryTable.getTableLevel()); + } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java new file mode 100644 index 0000000000..839556a404 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java @@ -0,0 +1,108 @@ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import com.intellij.openapi.module.ModifiableModuleModel; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.ProjectBundle; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.ui.configuration.ModuleEditor; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author nik + */ +public class ModuleProjectStructureElement extends ProjectStructureElement { + private Module myModule; + + public ModuleProjectStructureElement(@NotNull StructureConfigurableContext context, @NotNull Module module) { + super(context); + myModule = module; + } + + public Module getModule() { + return myModule; + } + + @Override + public void check(ProjectStructureProblemsHolder problemsHolder) { + final ModifiableModuleModel moduleModel = myContext.getModulesConfigurator().getModuleModel(); + final Module[] all = moduleModel.getModules(); + for (Module each : all) { + if (each != myModule && myContext.getRealName(each).equals(myContext.getRealName(myModule))) { + problemsHolder.addError(ProjectBundle.message("project.roots.module.duplicate.name.message")); + break; + } + } + + final ModuleRootModel rootModel = myContext.getModulesConfigurator().getRootModel(myModule); + if (rootModel == null) return; //already disposed + final OrderEntry[] entries = rootModel.getOrderEntries(); + for (OrderEntry entry : entries) { + if (!entry.isValid()){ + if (entry instanceof JdkOrderEntry && ((JdkOrderEntry)entry).getJdkName() == null) { + problemsHolder.addError(ProjectBundle.message("project.roots.module.jdk.problem.message")); + } else { + problemsHolder.addError(ProjectBundle.message("project.roots.library.problem.message", entry.getPresentableName())); + } + } + } + } + + @Override + public List getUsagesInElement() { + final List usages = new ArrayList(); + final ModuleEditor moduleEditor = myContext.getModulesConfigurator().getModuleEditor(myModule); + if (moduleEditor != null) { + for (OrderEntry entry : moduleEditor.getOrderEntries()) { + if (entry instanceof ModuleOrderEntry) { + final Module module = ((ModuleOrderEntry)entry).getModule(); + if (module != null) { + usages.add(new UsageInModuleClasspath(myContext, this, new ModuleProjectStructureElement(myContext, module))); + } + } + else if (entry instanceof LibraryOrderEntry) { + final Library library = ((LibraryOrderEntry)entry).getLibrary(); + if (library != null) { + usages.add(new UsageInModuleClasspath(myContext, this, new LibraryProjectStructureElement(myContext, library))); + } + } + else if (entry instanceof JdkOrderEntry) { + final Sdk jdk = ((JdkOrderEntry)entry).getJdk(); + if (jdk != null) { + usages.add(new UsageInModuleClasspath(myContext, this, new SdkProjectStructureElement(myContext, jdk))); + } + } + } + } + return usages; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ModuleProjectStructureElement)) return false; + + return myModule.equals(((ModuleProjectStructureElement)o).myModule); + + } + + @Override + public int hashCode() { + return myModule.hashCode(); + } + + @Override + public String toString() { + return "module:" + myModule.getName(); + } + + @Override + public boolean highlightIfUnused() { + return false; + } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java new file mode 100644 index 0000000000..04ff2888d7 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java @@ -0,0 +1,243 @@ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.MultiValuesMap; +import com.intellij.util.ui.update.MergingUpdateQueue; +import com.intellij.util.ui.update.Update; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.*; + +/** + * @author nik + */ +public class ProjectStructureDaemonAnalyzer implements Disposable { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.projectRoot.validation.ProjectStructureDaemonAnalyzer"); + private Map myProblemHolders = new HashMap(); + private MultiValuesMap mySourceElement2Usages = new MultiValuesMap(); + private MultiValuesMap myContainingElement2Usages = new MultiValuesMap(); + private Set myElementWithNotCalculatedUsages = new HashSet(); + private MergingUpdateQueue myAnalyzerQueue; + private List myListeners = new ArrayList(); + private boolean myDisposed; + + public ProjectStructureDaemonAnalyzer(StructureConfigurableContext context) { + Disposer.register(context, this); + myAnalyzerQueue = new MergingUpdateQueue("Project Structure Daemon Analyzer", 300, false, null, this, null, false); + } + + private void doUpdate(final ProjectStructureElement element, final boolean check, final boolean collectUsages) { + if (myDisposed) return; + + if (check) { + doCheck(element); + } + if (collectUsages) { + doCollectUsages(element); + } + } + + private void doCheck(final ProjectStructureElement element) { + final ProjectStructureProblemsHolder problemsHolder = new ProjectStructureProblemsHolder(); + new ReadAction() { + protected void run(final Result result) { + if (LOG.isDebugEnabled()) { + LOG.debug("checking " + element); + } + element.check(problemsHolder); + } + }.execute(); + invokeLater(new Runnable() { + public void run() { + if (LOG.isDebugEnabled()) { + LOG.debug("updating problems for " + element); + } + myProblemHolders.put(element, problemsHolder); + fireProblemsUpdated(); + } + }); + } + + private void fireProblemsUpdated() { + Runnable[] listeners = myListeners.toArray(new Runnable[myListeners.size()]); + for (Runnable listener : listeners) { + listener.run(); + } + } + + private void doCollectUsages(final ProjectStructureElement element) { + final List usages = new ReadAction>() { + protected void run(final Result> result) { + if (LOG.isDebugEnabled()) { + LOG.debug("collecting usages in " + element); + } + result.setResult(element.getUsagesInElement()); + } + }.execute().getResultObject(); + + invokeLater(new Runnable() { + public void run() { + if (LOG.isDebugEnabled()) { + LOG.debug("updating usages for " + element); + } + updateUsages(element, usages); + fireProblemsUpdated(); + } + }); + } + + private void updateUsages(ProjectStructureElement element, List usages) { + removeUsagesInElement(element); + for (ProjectStructureElementUsage usage : usages) { + addUsage(usage); + } + myElementWithNotCalculatedUsages.remove(element); + } + + private static void invokeLater(Runnable runnable) { + SwingUtilities.invokeLater(runnable); + } + + public void queueUpdate(@NotNull final ProjectStructureElement element) { + queueUpdate(element, true, true); + } + + public void queueUpdate(@NotNull final ProjectStructureElement element, final boolean check, final boolean collectUsages) { + if (LOG.isDebugEnabled()) { + LOG.debug("start " + (check ? "checking " : "") + (collectUsages ? "collecting usages " : "") + "for " + element); + } + if (collectUsages) { + myElementWithNotCalculatedUsages.add(element); + } + myAnalyzerQueue.queue(new AnalyzeElementUpdate(element, check, collectUsages)); + } + + public void removeElement(ProjectStructureElement element) { + myElementWithNotCalculatedUsages.remove(element); + myProblemHolders.remove(element); + final Collection usages = mySourceElement2Usages.removeAll(element); + if (usages != null) { + for (ProjectStructureElementUsage usage : usages) { + myProblemHolders.remove(usage.getContainingElement()); + } + } + removeUsagesInElement(element); + fireProblemsUpdated(); + } + + public boolean isUnused(ProjectStructureElement element) { + if (!element.highlightIfUnused()) { + return false; + } + if (!myElementWithNotCalculatedUsages.isEmpty()) { + return false; + } + final Collection usages = mySourceElement2Usages.get(element); + return usages == null || usages.isEmpty(); + } + + private void removeUsagesInElement(ProjectStructureElement element) { + final Collection usages = myContainingElement2Usages.removeAll(element); + if (usages != null) { + for (ProjectStructureElementUsage usage : usages) { + mySourceElement2Usages.remove(usage.getSourceElement(), usage); + } + } + } + + private void addUsage(@NotNull ProjectStructureElementUsage usage) { + mySourceElement2Usages.put(usage.getSourceElement(), usage); + myContainingElement2Usages.put(usage.getContainingElement(), usage); + } + + public void stop() { + LOG.debug("analyzer stopped"); + myAnalyzerQueue.cancelAllUpdates(); + clearCaches(); + myAnalyzerQueue.deactivate(); + } + + public void clearCaches() { + LOG.debug("clear caches"); + myProblemHolders.clear(); + mySourceElement2Usages.clear(); + myContainingElement2Usages.clear(); + myElementWithNotCalculatedUsages.clear(); + } + + public void clearAllProblems() { + myProblemHolders.clear(); + fireProblemsUpdated(); + } + + public void dispose() { + myDisposed = true; + myAnalyzerQueue.cancelAllUpdates(); + } + + public ProjectStructureProblemsHolder getProblemsHolder(ProjectStructureElement element) { + return myProblemHolders.get(element); + } + + public Collection getUsages(ProjectStructureElement selected) { + ProjectStructureElement[] elements = myElementWithNotCalculatedUsages.toArray(new ProjectStructureElement[myElementWithNotCalculatedUsages.size()]); + for (ProjectStructureElement element : elements) { + updateUsages(element, element.getUsagesInElement()); + } + fireProblemsUpdated(); + final Collection usages = mySourceElement2Usages.get(selected); + return usages != null ? usages : Collections.emptyList(); + } + + public void addListener(Runnable runnable) { + LOG.debug("listener added " + runnable); + myListeners.add(runnable); + } + + public void reset() { + LOG.debug("analyzer started"); + myAnalyzerQueue.activate(); + myAnalyzerQueue.queue(new Update("reset") { + public void run() { + myDisposed = false; + } + }); + } + + private class AnalyzeElementUpdate extends Update { + private final ProjectStructureElement myElement; + private final boolean myCheck; + private final boolean myCollectUsages; + private final Object[] myEqualityObjects; + + public AnalyzeElementUpdate(ProjectStructureElement element, boolean check, boolean collectUsages) { + super(element); + myElement = element; + myCheck = check; + myCollectUsages = collectUsages; + myEqualityObjects = new Object[]{myElement, myCheck, myCollectUsages}; + } + + @Override + public boolean canEat(Update update) { + if (!(update instanceof AnalyzeElementUpdate)) return false; + final AnalyzeElementUpdate other = (AnalyzeElementUpdate)update; + return myElement.equals(other.myElement) && (!other.myCheck || myCheck) && (!other.myCollectUsages || myCollectUsages); + } + + @Override + public Object[] getEqualityObjects() { + return myEqualityObjects; + } + + public void run() { + doUpdate(myElement, myCheck, myCollectUsages); + } + } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElement.java new file mode 100644 index 0000000000..70ee1e0352 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElement.java @@ -0,0 +1,29 @@ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author nik + */ +public abstract class ProjectStructureElement { + protected final StructureConfigurableContext myContext; + + protected ProjectStructureElement(@NotNull StructureConfigurableContext context) { + myContext = context; + } + + public abstract void check(ProjectStructureProblemsHolder problemsHolder); + + public abstract List getUsagesInElement(); + + public abstract boolean highlightIfUnused(); + + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElementUsage.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElementUsage.java new file mode 100644 index 0000000000..7ed2aff3b8 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElementUsage.java @@ -0,0 +1,24 @@ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import javax.swing.*; + +/** + * @author nik + */ +public abstract class ProjectStructureElementUsage { + public abstract ProjectStructureElement getSourceElement(); + + public abstract ProjectStructureElement getContainingElement(); + + public abstract String getPresentableName(); + + public abstract void navigate(); + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object obj); + + public abstract Icon getIcon(); +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemDescription.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemDescription.java new file mode 100644 index 0000000000..fa12df0d06 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemDescription.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2009 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.daemon; + +/** + * @author nik + */ +public class ProjectStructureProblemDescription { + private String myMessage; + private final Severity mySeverity; + + public ProjectStructureProblemDescription(String message, Severity severity) { + myMessage = message; + mySeverity = severity; + } + + public String getMessage() { + return myMessage; + } + + public Severity getSeverity() { + return mySeverity; + } + + public enum Severity { ERROR, WARNING } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemsHolder.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemsHolder.java new file mode 100644 index 0000000000..35727828aa --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemsHolder.java @@ -0,0 +1,57 @@ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import com.intellij.util.SmartList; +import com.intellij.util.StringBuilderSpinAllocator; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author nik + */ +public class ProjectStructureProblemsHolder { + private List myProblemDescriptions; + + public void addError(String message) { + addProblem(message, ProjectStructureProblemDescription.Severity.ERROR); + } + + public void addWarning(String message) { + addProblem(message, ProjectStructureProblemDescription.Severity.WARNING); + } + + public void addProblem(String description, ProjectStructureProblemDescription.Severity severity) { + if (myProblemDescriptions == null) { + myProblemDescriptions = new SmartList(); + } + myProblemDescriptions.add(new ProjectStructureProblemDescription(description, severity)); + } + + @Nullable + public ProjectStructureProblemDescription.Severity getSeverity() { + if (myProblemDescriptions == null || myProblemDescriptions.isEmpty()) { + return null; + } + for (ProjectStructureProblemDescription description : myProblemDescriptions) { + if (description.getSeverity() == ProjectStructureProblemDescription.Severity.ERROR) { + return ProjectStructureProblemDescription.Severity.ERROR; + } + } + return ProjectStructureProblemDescription.Severity.WARNING; + } + + public String composeTooltipMessage() { + final StringBuilder buf = StringBuilderSpinAllocator.alloc(); + try { + if (myProblemDescriptions != null) { + for (ProjectStructureProblemDescription problemDescription : myProblemDescriptions) { + buf.append(problemDescription.getMessage()).append("\n"); + } + } + return buf.toString(); + } + finally { + StringBuilderSpinAllocator.dispose(buf); + } + } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/SdkProjectStructureElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/SdkProjectStructureElement.java new file mode 100644 index 0000000000..758b6e6140 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/SdkProjectStructureElement.java @@ -0,0 +1,55 @@ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; + +import java.util.Collections; +import java.util.List; + +/** + * @author nik + */ +public class SdkProjectStructureElement extends ProjectStructureElement { + private Sdk mySdk; + + public SdkProjectStructureElement(StructureConfigurableContext context, Sdk sdk) { + super(context); + mySdk = sdk; + } + + public Sdk getSdk() { + return mySdk; + } + + @Override + public void check(ProjectStructureProblemsHolder problemsHolder) { + } + + @Override + public List getUsagesInElement() { + return Collections.emptyList(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SdkProjectStructureElement)) return false; + return mySdk.equals(((SdkProjectStructureElement)o).mySdk); + + } + + @Override + public int hashCode() { + return mySdk.hashCode(); + } + + @Override + public String toString() { + return "sdk:" + mySdk.getName(); + } + + @Override + public boolean highlightIfUnused() { + return false; + } +} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/UsageInModuleClasspath.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/UsageInModuleClasspath.java new file mode 100644 index 0000000000..9a0ead0e66 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/UsageInModuleClasspath.java @@ -0,0 +1,86 @@ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.ModuleRootModel; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.impl.OrderEntryUtil; +import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; +import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author nik + */ +public class UsageInModuleClasspath extends ProjectStructureElementUsage { + private final StructureConfigurableContext myContext; + private final ModuleProjectStructureElement myContainingElement; + private ProjectStructureElement mySourceElement; + private Module myModule; + + public UsageInModuleClasspath(@NotNull StructureConfigurableContext context, @NotNull ModuleProjectStructureElement containingElement, ProjectStructureElement sourceElement) { + myContext = context; + myContainingElement = containingElement; + myModule = containingElement.getModule(); + mySourceElement = sourceElement; + } + + + @Override + public ProjectStructureElement getSourceElement() { + return mySourceElement; + } + + @Override + public ProjectStructureElement getContainingElement() { + return myContainingElement; + } + + @Override + public String getPresentableName() { + return myModule.getName(); + } + + public String getModuleName() { + return myModule.getName(); + } + + @Override + public void navigate() { + ModulesConfigurator modulesConfigurator = myContext.getModulesConfigurator(); + + ModuleRootModel rootModel = modulesConfigurator.getRootModel(myModule); + OrderEntry entry; + if (mySourceElement instanceof LibraryProjectStructureElement) { + entry = OrderEntryUtil.findLibraryOrderEntry(rootModel, ((LibraryProjectStructureElement)mySourceElement).getLibrary()); + } + else if (mySourceElement instanceof ModuleProjectStructureElement) { + entry = OrderEntryUtil.findModuleOrderEntry(rootModel, ((ModuleProjectStructureElement)mySourceElement).getModule()); + } + else if (mySourceElement instanceof SdkProjectStructureElement) { + entry = OrderEntryUtil.findJdkOrderEntry(rootModel, ((SdkProjectStructureElement)mySourceElement).getSdk()); + } + else { + entry = null; + } + ModuleStructureConfigurable.getInstance(myContext.getProject()).selectOrderEntry(myModule, entry); + } + + @Override + public int hashCode() { + return myModule.hashCode()*31 + mySourceElement.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof UsageInModuleClasspath && myModule.equals(((UsageInModuleClasspath)obj).myModule) + && mySourceElement.equals(((UsageInModuleClasspath)obj).mySourceElement); + } + + @Override + public Icon getIcon() { + return myModule.getModuleType().getNodeIcon(false); + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index 571f64237a..9c5d72b5cd 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -461,14 +461,14 @@ public abstract class MasterDetailsComponent implements Configurable, Persistent } public void fireItemsChangeListener(final Object editableObject) { - for (ItemsChangeListener listner : myListners) { - listner.itemChanged(editableObject); + for (ItemsChangeListener listener : myListners) { + listener.itemChanged(editableObject); } } private void fireItemsChangedExternally() { - for (ItemsChangeListener listner : myListners) { - listner.itemsExternallyChanged(); + for (ItemsChangeListener listener : myListners) { + listener.itemsExternallyChanged(); } } diff --git a/platform/platform-resources-en/src/messages/ProjectBundle.properties b/platform/platform-resources-en/src/messages/ProjectBundle.properties index 1d886f3209..e254eb57d0 100644 --- a/platform/platform-resources-en/src/messages/ProjectBundle.properties +++ b/platform/platform-resources-en/src/messages/ProjectBundle.properties @@ -338,7 +338,7 @@ choose.modules.dialog.title=Choose modules choose.modules.dialog.description=Library '' {0}'' will be added to the selected modules. project.roots.module.jdk.problem.message=Module JDK is not defined. project.roots.module.duplicate.name.message=Duplicate module name -project.roots.library.problem.message=Classpath {0, choice, 1#entry is invalid: |2#entries are invalid: \n} +project.roots.library.problem.message=Classpath entry is invalid: {0} project.roots.project.display.name=Project project.roots.global.resources.display.name=Global Resources project.roots.modules.display.name=Modules -- 2.11.4.GIT