validation in artifacts migrated to use ProjectStructureDaemonAnalyzer
authornik <Nikolay.Chashnikov@jetbrains.com>
Fri, 13 Nov 2009 16:08:02 +0000 (19:08 +0300)
committernik <Nikolay.Chashnikov@jetbrains.com>
Tue, 17 Nov 2009 12:33:41 +0000 (15:33 +0300)
24 files changed:
java/compiler/impl/src/com/intellij/packaging/impl/ui/ArtifactProblemsHolderBase.java [moved from java/compiler/impl/src/com/intellij/packaging/impl/ui/ArtifactValidationManagerBase.java with 84% similarity]
java/compiler/openapi/src/com/intellij/packaging/artifacts/ArtifactType.java
java/compiler/openapi/src/com/intellij/packaging/ui/ArtifactProblemsHolder.java [moved from java/compiler/openapi/src/com/intellij/packaging/ui/ArtifactValidationManager.java with 96% similarity]
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactConfigurable.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProblemDescription.java [new file with mode: 0644]
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProblemsHolderImpl.java [new file with mode: 0644]
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProjectStructureElement.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactValidationManagerImpl.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContext.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurableContextImpl.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/actions/ArtifactEditorFindUsagesActionBase.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingElementNode.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/LibraryProjectStructureElement.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzerListener.java [new file with mode: 0644]
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemDescription.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemsHolder.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemsHolderImpl.java [new file with mode: 0644]

similarity index 84%
rename from java/compiler/impl/src/com/intellij/packaging/impl/ui/ArtifactValidationManagerBase.java
rename to java/compiler/impl/src/com/intellij/packaging/impl/ui/ArtifactProblemsHolderBase.java
index 81ea40d312db23a55876358b48de0983af80df8f..5b31da48790e50fe938cb5975730178619b247cb 100644 (file)
@@ -15,7 +15,7 @@
  */
 package com.intellij.packaging.impl.ui;
 
-import com.intellij.packaging.ui.ArtifactValidationManager;
+import com.intellij.packaging.ui.ArtifactProblemsHolder;
 import com.intellij.packaging.ui.ArtifactEditorContext;
 import com.intellij.packaging.ui.ArtifactProblemQuickFix;
 import org.jetbrains.annotations.NotNull;
@@ -24,10 +24,10 @@ import org.jetbrains.annotations.Nullable;
 /**
  * @author nik
  */
-public abstract class ArtifactValidationManagerBase implements ArtifactValidationManager {
+public abstract class ArtifactProblemsHolderBase implements ArtifactProblemsHolder {
   private ArtifactEditorContext myContext;
 
-  protected ArtifactValidationManagerBase(ArtifactEditorContext context) {
+  protected ArtifactProblemsHolderBase(ArtifactEditorContext context) {
     myContext = context;
   }
 
index 533c2adc5657b679885423cb14f6ae682c802274..130d0e2383e1ac0ac500b306a396d5d7adcaa57d 100644 (file)
@@ -21,7 +21,7 @@ import com.intellij.packaging.elements.CompositePackagingElement;
 import com.intellij.packaging.elements.PackagingElement;
 import com.intellij.packaging.elements.PackagingElementOutputKind;
 import com.intellij.packaging.elements.PackagingElementResolvingContext;
-import com.intellij.packaging.ui.ArtifactValidationManager;
+import com.intellij.packaging.ui.ArtifactProblemsHolder;
 import com.intellij.packaging.ui.PackagingSourceItem;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
@@ -50,7 +50,7 @@ public abstract class ArtifactType {
 
   public String getPresentableName() {
     return myTitle;
-  }
+  }                                
 
   @NotNull
   public abstract Icon getIcon();
@@ -89,7 +89,7 @@ public abstract class ArtifactType {
     return Collections.emptyList();
   }
 
-  public void checkRootElement(@NotNull CompositePackagingElement<?> rootElement, @NotNull Artifact artifact, @NotNull ArtifactValidationManager manager) {
+  public void checkRootElement(@NotNull CompositePackagingElement<?> rootElement, @NotNull Artifact artifact, @NotNull ArtifactProblemsHolder manager) {
   }
 
   @Nullable
similarity index 96%
rename from java/compiler/openapi/src/com/intellij/packaging/ui/ArtifactValidationManager.java
rename to java/compiler/openapi/src/com/intellij/packaging/ui/ArtifactProblemsHolder.java
index 345ca96b6562f9083727ce1f38df04dae691536a..5dc1c9f170c3c8030744abcb7d623ba0d52768d7 100644 (file)
@@ -22,7 +22,7 @@ import org.jetbrains.annotations.Nullable;
 /**
  * @author nik
  */
-public interface ArtifactValidationManager {
+public interface ArtifactProblemsHolder {
 
   ArtifactEditorContext getContext();
 
index d482338a23c50a3818574ba1b193d8ace2220dcf..33549a34a4bbcd366683a0759f3791c4533dd261 100644 (file)
@@ -67,14 +67,8 @@ public class ModulesConfigurator implements ModulesProvider, ModuleEditor.Change
   private static final Logger LOG = Logger.getInstance("#" + ModulesConfigurator.class.getName());
 
   private final Project myProject;
-  //private final ModuleStructureConfigurable myProjectRootConfigurable;
-
-  private boolean myModified = false;
-
   private final ProjectConfigurable myProjectConfigurable;
-
   private final List<ModuleEditor> myModuleEditors = new ArrayList<ModuleEditor>();
-
   private final Comparator<ModuleEditor> myModuleEditorComparator = new Comparator<ModuleEditor>() {
     final ModulesAlphaComparator myModulesComparator = new ModulesAlphaComparator();
 
@@ -87,10 +81,12 @@ public class ModulesConfigurator implements ModulesProvider, ModuleEditor.Change
       return false;
     }
   };
+  private boolean myModified = false;
   private ModifiableModuleModel myModuleModel;
   private ProjectFacetsConfigurator myFacetsConfigurator;
 
   private StructureConfigurableContext myContext;
+  private List<ModuleEditor.ChangeListener> myAllModulesChangeListeners = new ArrayList<ModuleEditor.ChangeListener>();
 
   public ModulesConfigurator(Project project, ProjectJdksModel projectJdksModel) {
     myProject = project;
@@ -211,6 +207,13 @@ public class ModulesConfigurator implements ModulesProvider, ModuleEditor.Change
 
   public void moduleStateChanged(final ModifiableRootModel moduleRootModel) {
     myProjectConfigurable.updateCircularDependencyWarning();
+    for (ModuleEditor.ChangeListener listener : myAllModulesChangeListeners) {
+      listener.moduleStateChanged(moduleRootModel);
+    }
+  }
+
+  public void addAllModuleChangeListener(ModuleEditor.ChangeListener listener) {
+    myAllModulesChangeListeners.add(listener);
   }
 
   public GraphGenerator<ModifiableRootModel> createGraphGenerator() {
index 9fe5bf3afd929ceb4d4a6076a245079d59371c65..d75c33ebff0500a662a0b2c2a42d70fcb5f8d676 100644 (file)
@@ -18,7 +18,6 @@ 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.util.Comparing;
@@ -41,13 +40,12 @@ public class ArtifactConfigurable extends ProjectStructureElementConfigurable<Ar
   private boolean myIsInUpdateName;
   private ProjectStructureElement myProjectStructureElement;
 
-  public ArtifactConfigurable(Artifact originalArtifact, ArtifactsStructureConfigurableContextImpl artifactsStructureContext, final Runnable updateTree,
-                              StructureConfigurableContext context) {
+  public ArtifactConfigurable(Artifact originalArtifact, ArtifactsStructureConfigurableContextImpl artifactsStructureContext, final Runnable updateTree) {
     super(true, updateTree);
     myOriginalArtifact = originalArtifact;
     myArtifactsStructureContext = artifactsStructureContext;
     myEditor = artifactsStructureContext.getOrCreateEditor(originalArtifact);
-    myProjectStructureElement = new ArtifactProjectStructureElement(context, myArtifactsStructureContext, myOriginalArtifact);
+    myProjectStructureElement = myArtifactsStructureContext.getOrCreateArtifactElement(myOriginalArtifact);
   }
 
   public void setDisplayName(String name) {
index 0b8f51cc2f81ffee17bf69efccc7f55177ef7c11..da4ffef5b2d44a1f096c498dd3e6e2b37acd7822 100644 (file)
@@ -50,7 +50,6 @@ import java.util.List;
 public class ArtifactEditorContextImpl implements ArtifactEditorContext {
   private final ArtifactsStructureConfigurableContext myParent;
   private final ArtifactEditorEx myEditor;
-  private ArtifactValidationManagerImpl myValidationManager;
 
   public ArtifactEditorContextImpl(ArtifactsStructureConfigurableContext parent, ArtifactEditorEx editor) {
     myParent = parent;
@@ -155,7 +154,7 @@ public class ArtifactEditorContextImpl implements ArtifactEditorContext {
   }
 
   public void queueValidation() {
-    myEditor.queueValidation();
+    myParent.queueValidation(getArtifact());
   }
 
   @NotNull
@@ -163,14 +162,6 @@ public class ArtifactEditorContextImpl implements ArtifactEditorContext {
     return myEditor.getArtifact().getArtifactType();
   }
 
-  public ArtifactValidationManagerImpl getValidationManager() {
-    return myValidationManager;
-  }
-
-  public void setValidationManager(ArtifactValidationManagerImpl validationManager) {
-    myValidationManager = validationManager;
-  }
-
   public List<Module> chooseModules(final List<Module> modules, final String title) {
     ChooseModulesDialog dialog = new ChooseModulesDialog(getProject(), modules, title, null);
     dialog.show();
index 0e8d5b41e6d46447b48eb9f7299da29a8ccc8849..0177313d2b70d389bd4d39a1120b6bebcc122b81 100644 (file)
@@ -111,7 +111,6 @@ public class ArtifactEditorImpl implements ArtifactEditorEx {
     });
     setOutputPath(outputPath);
     myValidationManager = new ArtifactValidationManagerImpl(this);
-    myContext.setValidationManager(myValidationManager);
     updateShowContentCheckbox();
   }
 
@@ -174,7 +173,7 @@ public class ArtifactEditorImpl implements ArtifactEditorEx {
   }
 
   public void queueValidation() {
-    myValidationManager.queueValidation();
+    myContext.queueValidation();
   }
 
   public JComponent createMainComponent() {
@@ -400,6 +399,10 @@ public class ArtifactEditorImpl implements ArtifactEditorEx {
     myLayoutTreeComponent.setRootElement(newRootElement);
   }
 
+  public ArtifactValidationManagerImpl getValidationManager() {
+    return myValidationManager;
+  }
+
   private class MyDataProvider implements TypeSafeDataProvider {
     public void calcData(DataKey key, DataSink sink) {
       if (ARTIFACTS_EDITOR_KEY.equals(key)) {
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProblemDescription.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProblemDescription.java
new file mode 100644 (file)
index 0000000..43ac8ce
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemDescription;
+import com.intellij.packaging.elements.PackagingElement;
+import com.intellij.packaging.ui.ArtifactProblemQuickFix;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author nik
+ */
+public class ArtifactProblemDescription extends ProjectStructureProblemDescription {
+  private ArtifactProblemQuickFix myQuickFix;
+  private PackagingElement<?> myPlace;
+
+  public ArtifactProblemDescription(@NotNull String message, @NotNull Severity severity) {
+    super(message, severity);
+  }
+
+  public ArtifactProblemDescription(@NotNull String message, @NotNull Severity severity, @Nullable ArtifactProblemQuickFix quickFix) {
+    super(message, severity);
+    myQuickFix = quickFix;
+  }
+
+  public ArtifactProblemDescription(@NotNull String message,
+                                    @NotNull Severity severity,
+                                    @Nullable PackagingElement<?> place,
+                                    @Nullable ArtifactProblemQuickFix quickFix) {
+    super(message, severity);
+    myPlace = place;
+    myQuickFix = quickFix;
+  }
+
+  @Nullable
+  public ArtifactProblemQuickFix getQuickFix() {
+    return myQuickFix;
+  }
+
+  public PackagingElement<?> getPlace() {
+    return myPlace;
+  }
+}
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProblemsHolderImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProblemsHolderImpl.java
new file mode 100644 (file)
index 0000000..0ca1c72
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemDescription;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemsHolder;
+import com.intellij.packaging.elements.PackagingElement;
+import com.intellij.packaging.impl.ui.ArtifactProblemsHolderBase;
+import com.intellij.packaging.ui.ArtifactEditorContext;
+import com.intellij.packaging.ui.ArtifactProblemQuickFix;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author nik
+ */
+public class ArtifactProblemsHolderImpl extends ArtifactProblemsHolderBase {
+  private ProjectStructureProblemsHolder myProblemsHolder;
+
+  public ArtifactProblemsHolderImpl(ArtifactEditorContext context, ProjectStructureProblemsHolder problemsHolder) {
+    super(context);
+    myProblemsHolder = problemsHolder;
+  }
+
+  public void registerProblem(@NotNull String message, @Nullable PackagingElement<?> place, @Nullable ArtifactProblemQuickFix quickFix) {
+    myProblemsHolder.registerProblem(new ArtifactProblemDescription(message, ProjectStructureProblemDescription.Severity.ERROR, place, quickFix));
+  }
+}
index 9adc9590653ac3588bc51bfa95680bfc5b519c6e..d137641004c61fbd326f79e9dbd269fcd3f5d9f3 100644 (file)
@@ -39,15 +39,23 @@ public class ArtifactProjectStructureElement extends ProjectStructureElement {
   private final ArtifactsStructureConfigurableContext myArtifactsStructureContext;
   private final Artifact myOriginalArtifact;
 
-  public ArtifactProjectStructureElement(StructureConfigurableContext context,
-                                         ArtifactsStructureConfigurableContext artifactsStructureContext, Artifact artifact) {
+  ArtifactProjectStructureElement(StructureConfigurableContext context,
+                                  ArtifactsStructureConfigurableContext artifactsStructureContext, Artifact artifact) {
     super(context);
     myArtifactsStructureContext = artifactsStructureContext;
     myOriginalArtifact = artifactsStructureContext.getOriginalArtifact(artifact);
   }
 
   @Override
-  public void check(ProjectStructureProblemsHolder problemsHolder) {
+  public void check(final ProjectStructureProblemsHolder problemsHolder) {
+    final ArtifactEditorEx artifactEditor = (ArtifactEditorEx)myArtifactsStructureContext.getOrCreateEditor(myOriginalArtifact);
+    artifactEditor.getLayoutTreeComponent().saveElementProperties();
+    final Artifact artifact = artifactEditor.getArtifact();
+    artifact.getArtifactType().checkRootElement(artifactEditor.getRootElement(), artifact, new ArtifactProblemsHolderImpl(artifactEditor.getContext(), problemsHolder));
+  }
+
+  public Artifact getOriginalArtifact() {
+    return myOriginalArtifact;
   }
 
   @Override
@@ -74,8 +82,7 @@ public class ArtifactProjectStructureElement extends ProjectStructureElement {
         else if (packagingElement instanceof ArtifactPackagingElement) {
           final Artifact usedArtifact = ((ArtifactPackagingElement)packagingElement).findArtifact(myArtifactsStructureContext);
           if (usedArtifact != null) {
-            final ArtifactProjectStructureElement artifactElement =
-              new ArtifactProjectStructureElement(myContext, myArtifactsStructureContext, usedArtifact);
+            final ArtifactProjectStructureElement artifactElement = myArtifactsStructureContext.getOrCreateArtifactElement(usedArtifact);
             usages.add(new UsageInArtifact(myOriginalArtifact, myArtifactsStructureContext, artifactElement,
                                            ArtifactProjectStructureElement.this, getPathFromRoot(parents, "/"), packagingElement));
           }
@@ -109,4 +116,5 @@ public class ArtifactProjectStructureElement extends ProjectStructureElement {
   public boolean highlightIfUnused() {
     return false;
   }
+
 }
index df03f0f634752a6a4efb038f1e097a778ccf3662..54c745bfdfcc0d7fbfadaba6998f15beddbfdece 100644 (file)
@@ -18,60 +18,32 @@ package com.intellij.openapi.roots.ui.configuration.artifacts;
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.CompositePackagingElementNode;
 import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.PackagingElementNode;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemDescription;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemsHolderImpl;
 import com.intellij.openapi.util.Disposer;
-import com.intellij.packaging.artifacts.Artifact;
 import com.intellij.packaging.elements.PackagingElement;
-import com.intellij.packaging.impl.ui.ArtifactValidationManagerBase;
 import com.intellij.packaging.ui.ArtifactProblemQuickFix;
-import com.intellij.util.ui.update.MergingUpdateQueue;
-import com.intellij.util.ui.update.Update;
-import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
 * @author nik
 */
-public class ArtifactValidationManagerImpl extends ArtifactValidationManagerBase implements Disposable {
-  private MergingUpdateQueue myValidationQueue;
+public class ArtifactValidationManagerImpl implements Disposable {
   private ArtifactErrorPanel myErrorPanel;
   private final ArtifactEditorImpl myArtifactEditor;
   private Map<PackagingElementNode<?>, String> myErrorsForNodes = new HashMap<PackagingElementNode<?>, String>();
   private Map<PackagingElement<?>, String> myErrorsForElements = new HashMap<PackagingElement<?>, String>();
 
   ArtifactValidationManagerImpl(ArtifactEditorImpl artifactEditor) {
-    super(artifactEditor.getContext());
     Disposer.register(artifactEditor, this);
     myArtifactEditor = artifactEditor;
     myErrorPanel = new ArtifactErrorPanel(artifactEditor);
-    final JComponent mainComponent = artifactEditor.getMainComponent();
-    myValidationQueue = new MergingUpdateQueue("ArtifactValidation", 300, false, mainComponent, this, mainComponent);
-  }
-
-  private void runValidation() {
-    myErrorPanel.clearError();
-    myErrorsForNodes.clear();
-    myErrorsForElements.clear();
-
-    myArtifactEditor.getLayoutTreeComponent().saveElementProperties();
-    final Artifact artifact = myArtifactEditor.getArtifact();
-    artifact.getArtifactType().checkRootElement(myArtifactEditor.getRootElement(), artifact, this);
-
-    myArtifactEditor.getLayoutTreeComponent().updateTreeNodesPresentation();
-  }
-
-  public void registerProblem(@NotNull String message, @Nullable PackagingElement<?> place, @Nullable ArtifactProblemQuickFix quickFix) {
-    if (place != null) {
-      final LayoutTree layoutTree = myArtifactEditor.getLayoutTreeComponent().getLayoutTree();
-      myErrorsForElements.put(place, message);
-      final List<PackagingElementNode<?>> nodes = layoutTree.findNodes(Collections.singletonList(place));
-      for (PackagingElementNode<?> node : nodes) {
-        addNodeToErrorsWithParents(node, message);
-      }
-    }
-    myErrorPanel.showError(message, quickFix);
   }
 
   private void addNodeToErrorsWithParents(PackagingElementNode<?> node, String message) {
@@ -87,14 +59,6 @@ public class ArtifactValidationManagerImpl extends ArtifactValidationManagerBase
   public void dispose() {
   }
 
-  public void queueValidation() {
-    myValidationQueue.queue(new Update("validate") {
-      public void run() {
-        runValidation();
-      }
-    });
-  }
-
   public JComponent getMainErrorPanel() {
     return myErrorPanel.getMainPanel();
   }
@@ -110,4 +74,33 @@ public class ArtifactValidationManagerImpl extends ArtifactValidationManagerBase
   public String getProblem(PackagingElementNode<?> node) {
     return myErrorsForNodes.get(node);
   }
+
+  public void updateProblems(@Nullable ProjectStructureProblemsHolderImpl holder) {
+    myErrorPanel.clearError();
+    myErrorsForNodes.clear();
+    myErrorsForElements.clear();
+    if (holder != null) {
+      final List<ProjectStructureProblemDescription> problemDescriptions = holder.getProblemDescriptions();
+      if (problemDescriptions != null) {
+        for (ProjectStructureProblemDescription description : problemDescriptions) {
+          final String message = description.getMessage();
+          ArtifactProblemQuickFix quickFix = null;
+          if (description instanceof ArtifactProblemDescription) {
+            quickFix = ((ArtifactProblemDescription)description).getQuickFix();
+            final PackagingElement<?> place = ((ArtifactProblemDescription)description).getPlace();
+            if (place != null) {
+              final LayoutTree layoutTree = myArtifactEditor.getLayoutTreeComponent().getLayoutTree();
+              myErrorsForElements.put(place, message);
+              final List<PackagingElementNode<?>> nodes = layoutTree.findNodes(Collections.singletonList(place));
+              for (PackagingElementNode<?> node : nodes) {
+                addNodeToErrorsWithParents(node, message);
+              }
+            }
+          }
+          myErrorPanel.showError(message, quickFix);
+        }
+      }
+    }
+    myArtifactEditor.getLayoutTreeComponent().updateTreeNodesPresentation();
+  }
 }
index ba8911c93c3212eea0eeaaeab789a8578a236a24..914dfd05bed7ab9f89cea630312be194d5acddac 100644 (file)
@@ -27,6 +27,8 @@ import com.intellij.openapi.options.ConfigurationException;
 import com.intellij.openapi.project.DumbAwareAction;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.project.ProjectBundle;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ui.configuration.ModuleEditor;
 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;
@@ -64,7 +66,15 @@ 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));
+        myContext.getDaemonAnalyzer().queueUpdate(myPackagingEditorContext.getOrCreateArtifactElement(artifact));
+      }
+    });
+
+    context.getModulesConfigurator().addAllModuleChangeListener(new ModuleEditor.ChangeListener() {
+      public void moduleStateChanged(ModifiableRootModel moduleRootModel) {
+        for (ProjectStructureElement element : getProjectStructureElements()) {
+          myContext.getDaemonAnalyzer().queueUpdate(element, true, false);
+        }
       }
     });
   }
@@ -87,13 +97,13 @@ public class ArtifactsStructureConfigurable extends BaseStructureConfigurable {
   protected Collection<? extends ProjectStructureElement> getProjectStructureElements() {
     final List<ProjectStructureElement> elements = new ArrayList<ProjectStructureElement>();
     for (Artifact artifact : myPackagingEditorContext.getArtifactModel().getArtifacts()) {
-      elements.add(new ArtifactProjectStructureElement(myContext, myPackagingEditorContext, artifact));
+      elements.add(myPackagingEditorContext.getOrCreateArtifactElement(artifact));
     }
     return elements;
   }
 
   private MyNode addArtifactNode(final Artifact artifact) {
-    final MyNode node = new MyNode(new ArtifactConfigurable(artifact, myPackagingEditorContext, TREE_UPDATER, myContext));
+    final MyNode node = new MyNode(new ArtifactConfigurable(artifact, myPackagingEditorContext, TREE_UPDATER));
     addNode(node, myRoot);
     return node;
   }
@@ -216,7 +226,7 @@ public class ArtifactsStructureConfigurable extends BaseStructureConfigurable {
   @Override
   protected void removeArtifact(Artifact artifact) {
     myPackagingEditorContext.getOrCreateModifiableArtifactModel().removeArtifact(artifact);
-    myContext.getDaemonAnalyzer().removeElement(new ArtifactProjectStructureElement(myContext, myPackagingEditorContext, artifact));
+    myContext.getDaemonAnalyzer().removeElement(myPackagingEditorContext.getOrCreateArtifactElement(artifact));
   }
 
   protected void processRemovedItems() {
index 6c1f7bccb5791e7d6b49100d0a6ff17b4361ea74..a11097eaedda5fb1555ea130be82b84173a9d909 100644 (file)
@@ -49,4 +49,9 @@ public interface ArtifactsStructureConfigurableContext extends PackagingElementR
 
   @Nullable
   ModifiableModuleModel getModifiableModuleModel();
+
+  void queueValidation(Artifact artifact);
+
+  @NotNull
+  ArtifactProjectStructureElement getOrCreateArtifactElement(@NotNull Artifact artifact);
 }
index 2fa3ffd9f5a7004a170b8a29c12bb256a9eca82d..6da61b401a333482b2663f5e2af978d1885a1d37 100644 (file)
  */
 package com.intellij.openapi.roots.ui.configuration.artifacts;
 
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.WriteAction;
 import com.intellij.openapi.module.ModifiableModuleModel;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.ui.configuration.FacetsProvider;
 import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
 import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureDaemonAnalyzerListener;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemsHolderImpl;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.packaging.artifacts.*;
 import com.intellij.packaging.elements.CompositePackagingElement;
@@ -34,7 +39,7 @@ import java.util.Map;
 /**
 * @author nik
 */
-class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureConfigurableContext {
+public class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureConfigurableContext {
   private ModifiableArtifactModel myModifiableModel;
   private final ManifestFilesInfo myManifestFilesInfo = new ManifestFilesInfo();
   private ArtifactAdapter myModifiableModelListener;
@@ -43,6 +48,7 @@ class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureCon
   private Map<Artifact, CompositePackagingElement<?>> myModifiableRoots = new HashMap<Artifact, CompositePackagingElement<?>>();
   private Map<Artifact, ArtifactEditorImpl> myArtifactEditors = new HashMap<Artifact, ArtifactEditorImpl>();
   private Map<ArtifactPointer, ArtifactEditorSettings> myEditorSettings = new HashMap<ArtifactPointer, ArtifactEditorSettings>();
+  private Map<Artifact, ArtifactProjectStructureElement> myArtifactElements = new HashMap<Artifact, ArtifactProjectStructureElement>();
   private final ArtifactEditorSettings myDefaultSettings;
 
   public ArtifactsStructureConfigurableContextImpl(StructureConfigurableContext context, Project project,
@@ -51,6 +57,31 @@ class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureCon
     myModifiableModelListener = modifiableModelListener;
     myContext = context;
     myProject = project;
+    context.getDaemonAnalyzer().addListener(new ProjectStructureDaemonAnalyzerListener() {
+      public void usagesCollected(@NotNull ProjectStructureElement containingElement) {
+      }
+
+      public void problemsChanged(@NotNull ProjectStructureElement element) {
+        if (element instanceof ArtifactProjectStructureElement) {
+          final Artifact originalArtifact = ((ArtifactProjectStructureElement)element).getOriginalArtifact();
+          final ArtifactEditorImpl artifactEditor = myArtifactEditors.get(originalArtifact);
+          if (artifactEditor != null) {
+            updateProblems(originalArtifact, artifactEditor);
+          }
+        }
+      }
+
+      public void allProblemsChanged() {
+        for (Map.Entry<Artifact, ArtifactEditorImpl> entry : myArtifactEditors.entrySet()) {
+          updateProblems(entry.getKey(), entry.getValue());
+        }
+      }
+    });
+  }
+
+  private void updateProblems(Artifact originalArtifact, ArtifactEditorImpl artifactEditor) {
+    final ProjectStructureProblemsHolderImpl holder = myContext.getDaemonAnalyzer().getProblemsHolder(getOrCreateArtifactElement(originalArtifact));
+    artifactEditor.getValidationManager().updateProblems(holder);
   }
 
   @NotNull
@@ -78,6 +109,10 @@ class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureCon
     return myContext.getModulesConfigurator().getModuleModel();
   }
 
+  public void queueValidation(Artifact artifact) {
+    myContext.getDaemonAnalyzer().queueUpdate(getOrCreateArtifactElement(artifact), true, false);
+  }
+
   public CompositePackagingElement<?> getRootElement(@NotNull Artifact artifact) {
     artifact = getOriginalArtifact(artifact);
     if (myModifiableModel != null) {
@@ -98,14 +133,18 @@ class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureCon
     return root;
   }
 
-  public void editLayout(@NotNull Artifact artifact, Runnable action) {
-    artifact = getOriginalArtifact(artifact);
-    final ModifiableArtifact modifiableArtifact = getOrCreateModifiableArtifactModel().getOrCreateModifiableArtifact(artifact);
-    if (modifiableArtifact.getRootElement() == artifact.getRootElement()) {
-      modifiableArtifact.setRootElement(getOrCreateModifiableRootElement(artifact));
-    }
-    action.run();
-    myContext.getDaemonAnalyzer().queueUpdate(new ArtifactProjectStructureElement(myContext, this, artifact));
+  public void editLayout(@NotNull final Artifact artifact, final Runnable action) {
+    final Artifact originalArtifact = getOriginalArtifact(artifact);
+    new WriteAction() {
+      protected void run(final Result result) {
+        final ModifiableArtifact modifiableArtifact = getOrCreateModifiableArtifactModel().getOrCreateModifiableArtifact(originalArtifact);
+        if (modifiableArtifact.getRootElement() == originalArtifact.getRootElement()) {
+          modifiableArtifact.setRootElement(getOrCreateModifiableRootElement(originalArtifact));
+        }
+        action.run();
+      }
+    }.execute();
+    myContext.getDaemonAnalyzer().queueUpdate(getOrCreateArtifactElement(originalArtifact));
   }
 
   public ArtifactEditorImpl getOrCreateEditor(Artifact artifact) {
@@ -175,6 +214,7 @@ class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureCon
     if (myModifiableModel != null) {
       myModifiableModel.dispose();
     }
+    myArtifactElements.clear();
   }
 
   public void saveEditorSettings() {
@@ -184,4 +224,14 @@ class ArtifactsStructureConfigurableContextImpl implements ArtifactsStructureCon
       myEditorSettings.put(pointer, artifactEditor.createSettings());
     }
   }
+
+  @NotNull
+  public ArtifactProjectStructureElement getOrCreateArtifactElement(@NotNull Artifact artifact) {
+    ArtifactProjectStructureElement element = myArtifactElements.get(getOriginalArtifact(artifact));
+    if (element == null) {
+      element = new ArtifactProjectStructureElement(myContext, this, artifact);
+      myArtifactElements.put(artifact, element);
+    }
+    return element;
+  }
 }
index 7b0efce581fd9b055710036dfa826372c2cb2a86..3840f7af69a584f7cf377d2cac10997cf92f9a90 100644 (file)
@@ -19,7 +19,6 @@ import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.libraries.Library;
 import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable;
-import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactProjectStructureElement;
 import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactsStructureConfigurableContext;
 import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.ArtifactsTreeNode;
 import com.intellij.openapi.roots.ui.configuration.projectRoot.FindUsagesInProjectStructureActionBase;
@@ -67,7 +66,7 @@ public abstract class ArtifactEditorFindUsagesActionBase extends FindUsagesInPro
       return new LibraryProjectStructureElement(context, (Library)sourceObject);
     }
     else if (sourceObject instanceof Artifact) {
-      return new ArtifactProjectStructureElement(context, myArtifactContext, (Artifact)sourceObject);
+      return myArtifactContext.getOrCreateArtifactElement((Artifact)sourceObject);
     }
     return null;
   }
index cc7e19c8d1c6317d877bf53ada42808b6a558e01..7135ef9cb8ccd4ddf5f03e532da297aef7d8be23 100644 (file)
@@ -18,7 +18,7 @@ package com.intellij.openapi.roots.ui.configuration.artifacts.nodes;
 import com.intellij.ide.projectView.PresentationData;
 import com.intellij.openapi.editor.markup.EffectType;
 import com.intellij.openapi.editor.markup.TextAttributes;
-import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactEditorContextImpl;
+import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactEditorImpl;
 import com.intellij.openapi.util.MultiValuesMap;
 import com.intellij.packaging.elements.CompositePackagingElement;
 import com.intellij.packaging.elements.PackagingElement;
@@ -55,7 +55,7 @@ public class PackagingElementNode<E extends PackagingElement<?>> extends Artifac
 
   private void doAddElement(E packagingElement) {
     myPackagingElements.add(packagingElement);
-    ((ArtifactEditorContextImpl)myContext).getValidationManager().elementAddedToNode(this, packagingElement);
+    ((ArtifactEditorImpl)myContext.getThisArtifactEditor()).getValidationManager().elementAddedToNode(this, packagingElement);
   }
 
   @Nullable 
@@ -93,7 +93,7 @@ public class PackagingElementNode<E extends PackagingElement<?>> extends Artifac
 
   @Override
   protected void update(PresentationData presentation) {
-    final String message = ((ArtifactEditorContextImpl)myContext).getValidationManager().getProblem(this);
+    final String message = ((ArtifactEditorImpl)myContext.getThisArtifactEditor()).getValidationManager().getProblem(this);
     if (message == null) {
       super.update(presentation);
       return;
@@ -104,7 +104,7 @@ public class PackagingElementNode<E extends PackagingElement<?>> extends Artifac
     presentation.setTooltip(message);
   }
 
-  private SimpleTextAttributes addErrorHighlighting(SimpleTextAttributes attributes) {
+  private static SimpleTextAttributes addErrorHighlighting(SimpleTextAttributes attributes) {
     final TextAttributes textAttributes = attributes.toTextAttributes();
     textAttributes.setEffectType(EffectType.WAVE_UNDERSCORE);
     textAttributes.setEffectColor(Color.RED);
index decbe7b9672880a5bb66cd62c183e58f785f6d80..589ca1fe4f444a1b735e0e48372f857d3196bbcc 100644 (file)
@@ -30,10 +30,7 @@ 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.roots.ui.configuration.projectRoot.daemon.*;
 import com.intellij.openapi.ui.MasterDetailsComponent;
 import com.intellij.openapi.ui.NamedConfigurable;
 import com.intellij.openapi.util.ActionCallback;
@@ -77,8 +74,20 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i
 
   public void init(StructureConfigurableContext context) {
     myContext = context;
-    myContext.getDaemonAnalyzer().addListener(new Runnable() {
-      public void run() {
+    myContext.getDaemonAnalyzer().addListener(new ProjectStructureDaemonAnalyzerListener() {
+      public void usagesCollected(@NotNull ProjectStructureElement containingElement) {
+        updateTree();
+      }
+
+      public void problemsChanged(@NotNull ProjectStructureElement element) {
+        updateTree();
+      }
+
+      public void allProblemsChanged() {
+        updateTree();
+      }
+
+      private void updateTree() {
         if (!myTree.isShowing()) return;
 
         myTree.revalidate();
@@ -173,7 +182,7 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i
             if (projectStructureElement != null) {
               final ProjectStructureDaemonAnalyzer daemonAnalyzer = myContext.getDaemonAnalyzer();
               final boolean unused = daemonAnalyzer.isUnused(projectStructureElement);
-              final ProjectStructureProblemsHolder problemsHolder = daemonAnalyzer.getProblemsHolder(projectStructureElement);
+              final ProjectStructureProblemsHolderImpl problemsHolder = daemonAnalyzer.getProblemsHolder(projectStructureElement);
               if (problemsHolder == null) {
                 daemonAnalyzer.queueUpdate(projectStructureElement, true, false);
               }
index 31f7dbe02158be50cfe8aa04c3c3cdc563f7b0cd..0fb2837e350bc125db54124d9abac9e0b4744e3b 100644 (file)
@@ -34,10 +34,10 @@ public class LibraryProjectStructureElement extends ProjectStructureElement {
     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));
+      problemsHolder.registerError(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));
+      problemsHolder.registerWarning(ProjectBundle.message("project.roots.tooltip.library.misconfigured", libraryName));
     }
   }
 
index 839556a404d01558c9dc6683d25a66e832428ef7..7eef60439e94ebd74e49120b1fb92b585afcda84 100644 (file)
@@ -34,7 +34,7 @@ public class ModuleProjectStructureElement extends ProjectStructureElement {
     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"));
+        problemsHolder.registerError(ProjectBundle.message("project.roots.module.duplicate.name.message"));
         break;
       }
     }
@@ -45,9 +45,9 @@ public class ModuleProjectStructureElement extends ProjectStructureElement {
     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"));
+          problemsHolder.registerError(ProjectBundle.message("project.roots.module.jdk.problem.message"));
         } else {
-          problemsHolder.addError(ProjectBundle.message("project.roots.library.problem.message", entry.getPresentableName()));
+          problemsHolder.registerError(ProjectBundle.message("project.roots.library.problem.message", entry.getPresentableName()));
         }
       }
     }
index aa5b46984392d9b5c6508e5804926358d3b4a978..53aa639815413db8809101b6ddd26b44db23324c 100644 (file)
@@ -7,9 +7,11 @@ 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.EventDispatcher;
 import com.intellij.util.ui.update.MergingUpdateQueue;
 import com.intellij.util.ui.update.Update;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
 import java.util.*;
@@ -20,12 +22,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
  */
 public class ProjectStructureDaemonAnalyzer implements Disposable {
   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.projectRoot.validation.ProjectStructureDaemonAnalyzer");
-  private Map<ProjectStructureElement, ProjectStructureProblemsHolder> myProblemHolders = new HashMap<ProjectStructureElement, ProjectStructureProblemsHolder>();
+  private Map<ProjectStructureElement, ProjectStructureProblemsHolderImpl> myProblemHolders = new HashMap<ProjectStructureElement, ProjectStructureProblemsHolderImpl>();
   private MultiValuesMap<ProjectStructureElement, ProjectStructureElementUsage> mySourceElement2Usages = new MultiValuesMap<ProjectStructureElement, ProjectStructureElementUsage>();
   private MultiValuesMap<ProjectStructureElement, ProjectStructureElementUsage> myContainingElement2Usages = new MultiValuesMap<ProjectStructureElement, ProjectStructureElementUsage>();
   private Set<ProjectStructureElement> myElementWithNotCalculatedUsages = new HashSet<ProjectStructureElement>();
   private MergingUpdateQueue myAnalyzerQueue;
-  private List<Runnable> myListeners = new ArrayList<Runnable>();
+  private final EventDispatcher<ProjectStructureDaemonAnalyzerListener> myDispatcher = EventDispatcher.create(ProjectStructureDaemonAnalyzerListener.class);
   private final AtomicBoolean myStopped = new AtomicBoolean(false);
 
   public ProjectStructureDaemonAnalyzer(StructureConfigurableContext context) {
@@ -45,7 +47,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
   }
 
   private void doCheck(final ProjectStructureElement element) {
-    final ProjectStructureProblemsHolder problemsHolder = new ProjectStructureProblemsHolder();
+    final ProjectStructureProblemsHolderImpl problemsHolder = new ProjectStructureProblemsHolderImpl();
     new ReadAction() {
       protected void run(final Result result) {
         if (myStopped.get()) return;
@@ -64,18 +66,11 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
           LOG.debug("updating problems for " + element);
         }
         myProblemHolders.put(element, problemsHolder);
-        fireProblemsUpdated();
+        myDispatcher.getMulticaster().problemsChanged(element);
       }
     });
   }
 
-  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<ProjectStructureElementUsage> usages = new ReadAction<List<ProjectStructureElementUsage>>() {
       protected void run(final Result<List<ProjectStructureElementUsage>> result) {
@@ -96,7 +91,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
           LOG.debug("updating usages for " + element);
         }
         updateUsages(element, usages);
-        fireProblemsUpdated();
+        myDispatcher.getMulticaster().usagesCollected(element);
       }
     });
   }
@@ -137,7 +132,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
       }
     }
     removeUsagesInElement(element);
-    fireProblemsUpdated();
+    myDispatcher.getMulticaster().problemsChanged(element);
   }
 
   public boolean isUnused(ProjectStructureElement element) {
@@ -180,7 +175,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
 
   public void clearAllProblems() {
     myProblemHolders.clear();
-    fireProblemsUpdated();
+    myDispatcher.getMulticaster().allProblemsChanged();
   }
 
   public void dispose() {
@@ -188,7 +183,8 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
     myAnalyzerQueue.cancelAllUpdates();
   }
 
-  public ProjectStructureProblemsHolder getProblemsHolder(ProjectStructureElement element) {
+  @Nullable
+  public ProjectStructureProblemsHolderImpl getProblemsHolder(ProjectStructureElement element) {
     return myProblemHolders.get(element);
   }
 
@@ -197,14 +193,13 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
     for (ProjectStructureElement element : elements) {
       updateUsages(element, element.getUsagesInElement());
     }
-    fireProblemsUpdated();
     final Collection<ProjectStructureElementUsage> usages = mySourceElement2Usages.get(selected);
     return usages != null ? usages : Collections.<ProjectStructureElementUsage>emptyList();
   }
 
-  public void addListener(Runnable runnable) {
-    LOG.debug("listener added " + runnable);
-    myListeners.add(runnable);
+  public void addListener(ProjectStructureDaemonAnalyzerListener listener) {
+    LOG.debug("listener added " + listener);
+    myDispatcher.addListener(listener);
   }
 
   public void reset() {
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzerListener.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzerListener.java
new file mode 100644 (file)
index 0000000..1ca0276
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EventListener;
+
+/**
+ * @author nik
+ */
+public interface ProjectStructureDaemonAnalyzerListener extends EventListener {
+
+  void usagesCollected(@NotNull ProjectStructureElement containingElement);
+
+  void problemsChanged(@NotNull ProjectStructureElement element);
+
+  void allProblemsChanged();
+}
index fa12df0d06e65c9e28e04969da2f1c1bef96eb6c..8f36da05fd638ce38746c975b8713b5dc33b18ad 100644 (file)
@@ -15,6 +15,8 @@
  */
 package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon;
 
+import org.jetbrains.annotations.NotNull;
+
 /**
  * @author nik
  */
@@ -22,7 +24,7 @@ public class ProjectStructureProblemDescription {
   private String myMessage;
   private final Severity mySeverity;
 
-  public ProjectStructureProblemDescription(String message, Severity severity) {
+  public ProjectStructureProblemDescription(@NotNull String message, @NotNull Severity severity) {
     myMessage = message;
     mySeverity = severity;
   }
index 35727828aa5f59f8d838cf92e37b0782e057ef60..9094b4ac654c255fb40977bda80b24a864078451 100644 (file)
@@ -1,57 +1,29 @@
+/*
+ * 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;
 
-import com.intellij.util.SmartList;
-import com.intellij.util.StringBuilderSpinAllocator;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * @author nik
  */
-public class ProjectStructureProblemsHolder {
-  private List<ProjectStructureProblemDescription> 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<ProjectStructureProblemDescription>();
-    }
-    myProblemDescriptions.add(new ProjectStructureProblemDescription(description, severity));
-  }
+public interface ProjectStructureProblemsHolder {
+  void registerError(@NotNull String message);
 
-  @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;
-  }
+  void registerWarning(@NotNull String message);
 
-  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);
-    }
-  }
+  void registerProblem(@NotNull ProjectStructureProblemDescription description);
 }
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemsHolderImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureProblemsHolderImpl.java
new file mode 100644 (file)
index 0000000..425f266
--- /dev/null
@@ -0,0 +1,63 @@
+package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon;
+
+import com.intellij.util.SmartList;
+import com.intellij.util.StringBuilderSpinAllocator;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public class ProjectStructureProblemsHolderImpl implements ProjectStructureProblemsHolder {
+  private List<ProjectStructureProblemDescription> myProblemDescriptions;
+
+  public void registerError(@NotNull String message) {
+    registerProblem(new ProjectStructureProblemDescription(message, ProjectStructureProblemDescription.Severity.ERROR));
+  }
+
+  public void registerWarning(@NotNull String message) {
+    registerProblem(new ProjectStructureProblemDescription(message, ProjectStructureProblemDescription.Severity.WARNING));
+  }
+
+  public void registerProblem(final @NotNull ProjectStructureProblemDescription description) {
+    if (myProblemDescriptions == null) {
+      myProblemDescriptions = new SmartList<ProjectStructureProblemDescription>();
+    }
+    myProblemDescriptions.add(description);
+  }
+
+  @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);
+    }
+  }
+
+  @Nullable
+  public List<ProjectStructureProblemDescription> getProblemDescriptions() {
+    return myProblemDescriptions;
+  }
+}