project structure: renderer for project structure elements refactored

This commit is contained in:
nik
2011-10-07 16:20:07 +04:00
parent d484ae9779
commit bab860ab6e
10 changed files with 110 additions and 113 deletions
@@ -98,10 +98,6 @@ public class ProjectConfigurable extends ProjectStructureElementConfigurable<Pro
}
});
daemonAnalyzer.addListener(new ProjectStructureDaemonAnalyzerListener() {
@Override
public void usagesCollected(@NotNull ProjectStructureElement containingElement) {
}
@Override
public void problemsChanged(@NotNull ProjectStructureElement element) {
if (element instanceof GeneralProjectSettingsElement) {
@@ -64,9 +64,6 @@ public class ArtifactsStructureConfigurableContextImpl implements ArtifactsStruc
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();
@@ -25,7 +25,6 @@ import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
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;
@@ -38,8 +37,6 @@ import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.TreeSpeedSearch;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.navigation.Place;
@@ -47,7 +44,6 @@ import com.intellij.util.Function;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -82,15 +78,7 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i
public void init(StructureConfigurableContext context) {
myContext = context;
myContext.getDaemonAnalyzer().addListener(new ProjectStructureDaemonAnalyzerListener() {
public void usagesCollected(@NotNull ProjectStructureElement containingElement) {
updateTree();
}
public void problemsChanged(@NotNull ProjectStructureElement element) {
updateTree();
}
private void updateTree() {
if (!myTree.isShowing()) return;
myTree.revalidate();
@@ -162,57 +150,7 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i
}
}, true);
ToolTipManager.sharedInstance().registerComponent(myTree);
myTree.setCellRenderer(new ColoredTreeCellRenderer(){
public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (value instanceof MyNode) {
final MyNode node = (MyNode)value;
final NamedConfigurable namedConfigurable = node.getConfigurable();
if (namedConfigurable == null) {
return;
}
final String displayName = node.getDisplayName();
final Icon icon = namedConfigurable.getIcon(expanded);
setIcon(icon);
setToolTipText(null);
setFont(UIUtil.getTreeFont());
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 ProjectStructureProblemsHolderImpl problemsHolder = daemonAnalyzer.getProblemsHolder(projectStructureElement);
if (problemsHolder == null) {
daemonAnalyzer.queueUpdate(projectStructureElement, true, false);
}
final ProjectStructureProblemType.Severity level = problemsHolder != null ? problemsHolder.getSeverity() : null;
final boolean invalid = level != null;
if (unused || invalid) {
Color fg = unused
? UIUtil.getInactiveTextColor()
: selected && hasFocus ? UIUtil.getTreeSelectionForeground() : UIUtil.getTreeForeground();
textAttributes = new SimpleTextAttributes(invalid ? SimpleTextAttributes.STYLE_WAVED : SimpleTextAttributes.STYLE_PLAIN, fg,
level == ProjectStructureProblemType.Severity.ERROR ? Color.RED : Color.GRAY);
String text = problemsHolder != null ? problemsHolder.composeTooltipMessage() : "";
if (unused) {
text += ProjectBundle.message("project.roots.tooltip.unused", displayName);
}
setToolTipText(text);
}
}
}
append(displayName, textAttributes);
}
}
});
myTree.setCellRenderer(new ProjectStructureElementRenderer(myContext));
}
public void disposeUIResources() {
@@ -312,7 +250,7 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i
loadTree();
}
for (ProjectStructureElement element : getProjectStructureElements()) {
myContext.getDaemonAnalyzer().queueUpdate(element, false, true);
myContext.getDaemonAnalyzer().queueUpdate(element);
}
super.reset();
@@ -502,5 +440,4 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i
return 0;
}
}
}
@@ -0,0 +1,82 @@
/*
* Copyright 2000-2011 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.ProjectStructureDaemonAnalyzer;
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemType;
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureProblemsHolderImpl;
import com.intellij.openapi.ui.MasterDetailsComponent;
import com.intellij.openapi.ui.NamedConfigurable;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
import java.awt.*;
/**
* @author nik
*/
class ProjectStructureElementRenderer extends ColoredTreeCellRenderer {
private StructureConfigurableContext myContext;
public ProjectStructureElementRenderer(StructureConfigurableContext context) {
myContext = context;
}
public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (value instanceof MasterDetailsComponent.MyNode) {
final MasterDetailsComponent.MyNode node = (MasterDetailsComponent.MyNode)value;
final NamedConfigurable namedConfigurable = node.getConfigurable();
if (namedConfigurable == null) {
return;
}
final String displayName = node.getDisplayName();
final Icon icon = namedConfigurable.getIcon(expanded);
setIcon(icon);
setToolTipText(null);
setFont(UIUtil.getTreeFont());
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 ProjectStructureProblemsHolderImpl problemsHolder = daemonAnalyzer.getProblemsHolder(projectStructureElement);
if (problemsHolder != null && problemsHolder.containsProblems()) {
final boolean isUnused = problemsHolder.containsProblems(ProjectStructureProblemType.Severity.UNUSED);
final boolean haveWarnings = problemsHolder.containsProblems(ProjectStructureProblemType.Severity.WARNING);
final boolean haveErrors = problemsHolder.containsProblems(ProjectStructureProblemType.Severity.ERROR);
Color foreground = isUnused ? UIUtil.getInactiveTextColor() : null;
final int style = haveWarnings || haveErrors ? SimpleTextAttributes.STYLE_WAVED : -1;
final Color waveColor = haveErrors ? Color.RED : haveWarnings ? Color.GRAY : null;
textAttributes = textAttributes.derive(style, foreground, null, waveColor);
setToolTipText(problemsHolder.composeTooltipMessage());
}
}
}
append(displayName, textAttributes);
}
}
}
@@ -111,7 +111,7 @@ public class LibraryProjectStructureElement extends ProjectStructureElement {
if (this == o) return true;
if (!(o instanceof LibraryProjectStructureElement)) return false;
return getSourceOrThis().equals(((LibraryProjectStructureElement)o).getSourceOrThis());
return getSourceOrThis() == (((LibraryProjectStructureElement)o).getSourceOrThis());
}
@NotNull
@@ -125,7 +125,7 @@ public class LibraryProjectStructureElement extends ProjectStructureElement {
@Override
public int hashCode() {
return getSourceOrThis().hashCode();
return System.identityHashCode(getSourceOrThis());
}
@Override
@@ -138,7 +138,7 @@ public class LibraryProjectStructureElement extends ProjectStructureElement {
public ProjectStructureProblemDescription createUnusedElementWarning() {
final List<ConfigurationErrorQuickFix> fixes = Arrays.asList(new AddLibraryToDependenciesFix(), new RemoveLibraryFix());
return new ProjectStructureProblemDescription(getPresentableName() + " is not used", null, createPlace(), fixes,
ProjectStructureProblemType.warning("unused-library"));
ProjectStructureProblemType.unused("unused-library"));
}
@Override
@@ -39,10 +39,6 @@ public class ProjectConfigurationProblems {
myAnalyzer = analyzer;
myContext = context;
analyzer.addListener(new ProjectStructureDaemonAnalyzerListener() {
@Override
public void usagesCollected(@NotNull ProjectStructureElement containingElement) {
}
@Override
public void problemsChanged(@NotNull ProjectStructureElement element) {
updateErrors(element);
@@ -102,7 +102,6 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
LOG.debug("updating usages for " + element);
}
updateUsages(element, usages);
myDispatcher.getMulticaster().usagesCollected(element);
}
});
}
@@ -124,7 +123,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
queueUpdate(element, true, true);
}
public void queueUpdate(@NotNull final ProjectStructureElement element, final boolean check, final boolean collectUsages) {
private 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);
}
@@ -184,17 +183,6 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
}
}
public boolean isUnused(ProjectStructureElement element) {
if (!element.shouldShowWarningIfUnused()) {
return false;
}
if (!myElementWithNotCalculatedUsages.isEmpty()) {
return false;
}
final Collection<ProjectStructureElementUsage> usages = mySourceElement2Usages.get(element);
return usages == null || usages.isEmpty();
}
private void removeUsagesInElement(ProjectStructureElement element) {
final Collection<ProjectStructureElementUsage> usages = myContainingElement2Usages.removeAll(element);
if (usages != null) {
@@ -225,7 +213,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
public void queueUpdateForAllElementsWithErrors() {
List<ProjectStructureElement> toUpdate = new ArrayList<ProjectStructureElement>();
for (Map.Entry<ProjectStructureElement, ProjectStructureProblemsHolderImpl> entry : myProblemHolders.entrySet()) {
if (entry.getValue().containProblems()) {
if (entry.getValue().containsProblems()) {
toUpdate.add(entry.getKey());
}
}
@@ -274,6 +262,8 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
}
public void clear() {
myWarningsAboutUnused.clear();
myElementsToShowWarningIfUnused.clear();
mySourceElement2Usages.clear();
myContainingElement2Usages.clear();
myElementWithNotCalculatedUsages.clear();
@@ -23,8 +23,5 @@ import java.util.EventListener;
* @author nik
*/
public interface ProjectStructureDaemonAnalyzerListener extends EventListener {
void usagesCollected(@NotNull ProjectStructureElement containingElement);
void problemsChanged(@NotNull ProjectStructureElement element);
}
@@ -21,7 +21,7 @@ import org.jetbrains.annotations.NotNull;
* @author nik
*/
public class ProjectStructureProblemType {
public enum Severity { ERROR, WARNING }
public enum Severity { ERROR, WARNING, UNUSED }
private final String myId;
private final Severity mySeverity;
@@ -39,6 +39,10 @@ public class ProjectStructureProblemType {
return new ProjectStructureProblemType(id, Severity.WARNING);
}
public static ProjectStructureProblemType unused(@NotNull String id) {
return new ProjectStructureProblemType(id, Severity.UNUSED);
}
@NotNull
public String getId() {
return myId;
@@ -1,8 +1,8 @@
package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.SmartList;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,19 +30,6 @@ public class ProjectStructureProblemsHolderImpl implements ProjectStructureProbl
myProblemDescriptions.add(description);
}
@Nullable
public ProjectStructureProblemType.Severity getSeverity() {
if (myProblemDescriptions == null || myProblemDescriptions.isEmpty()) {
return null;
}
for (ProjectStructureProblemDescription description : myProblemDescriptions) {
if (description.getSeverity() == ProjectStructureProblemType.Severity.ERROR) {
return ProjectStructureProblemType.Severity.ERROR;
}
}
return ProjectStructureProblemType.Severity.WARNING;
}
public String composeTooltipMessage() {
final StringBuilder buf = StringBuilderSpinAllocator.alloc();
try {
@@ -50,7 +37,7 @@ public class ProjectStructureProblemsHolderImpl implements ProjectStructureProbl
if (myProblemDescriptions != null) {
int problems = 0;
for (ProjectStructureProblemDescription problemDescription : myProblemDescriptions) {
buf.append(StringUtil.escapeXml(problemDescription.getMessage())).append("<br>");
buf.append(XmlStringUtil.escapeString(problemDescription.getMessage())).append("<br>");
problems++;
if (problems >= 10 && myProblemDescriptions.size() > 12) {
buf.append(myProblemDescriptions.size() - problems).append(" more problems...<br>");
@@ -66,10 +53,21 @@ public class ProjectStructureProblemsHolderImpl implements ProjectStructureProbl
}
}
public boolean containProblems() {
public boolean containsProblems() {
return myProblemDescriptions != null && !myProblemDescriptions.isEmpty();
}
public boolean containsProblems(final ProjectStructureProblemType.Severity severity) {
if (myProblemDescriptions != null) {
for (ProjectStructureProblemDescription description : myProblemDescriptions) {
if (description.getSeverity() == severity) {
return true;
}
}
}
return false;
}
public void removeProblem(@NotNull ProjectStructureProblemDescription description) {
if (myProblemDescriptions != null) {
myProblemDescriptions.remove(description);