NavBar presentation and other refactorings

This commit is contained in:
Konstantin Bulenkov
2011-02-09 17:36:17 +03:00
parent 112d6736b0
commit 415e55ea77
5 changed files with 426 additions and 308 deletions
@@ -0,0 +1,86 @@
/*
* 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.ide.navigationToolbar;
import com.intellij.ide.IdeView;
import com.intellij.ide.util.DirectoryChooserUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import java.util.ArrayList;
/**
* @author Konstantin Bulenkov
*/
public final class NavBarIdeView implements IdeView {
private final NavBarPanel myPanel;
public NavBarIdeView(NavBarPanel panel) {
myPanel = panel;
}
public void selectElement(PsiElement element) {
myPanel.getModel().updateModel(element);
if (element instanceof Navigatable) {
final Navigatable navigatable = (Navigatable)element;
if (navigatable.canNavigate()) {
((Navigatable)element).navigate(true);
}
}
myPanel.hideHint();
}
public PsiDirectory[] getDirectories() {
final PsiDirectory dir = myPanel.getSelectedElement(PsiDirectory.class);
if (dir != null && dir.isValid()) {
return new PsiDirectory[]{dir};
}
final PsiElement element = myPanel.getSelectedElement(PsiElement.class);
if (element != null && element.isValid()) {
final PsiFile file = element.getContainingFile();
if (file != null) {
final PsiDirectory psiDirectory = file.getContainingDirectory();
return psiDirectory != null ? new PsiDirectory[]{psiDirectory} : PsiDirectory.EMPTY_ARRAY;
}
}
final PsiDirectoryContainer directoryContainer = myPanel.getSelectedElement(PsiDirectoryContainer.class);
if (directoryContainer != null) {
return directoryContainer.getDirectories();
}
final Module module = myPanel.getSelectedElement(Module.class);
if (module != null && !module.isDisposed()) {
ArrayList<PsiDirectory> dirs = new ArrayList<PsiDirectory>();
final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots();
final PsiManager psiManager = PsiManager.getInstance(myPanel.getProject());
for (VirtualFile virtualFile : sourceRoots) {
final PsiDirectory directory = psiManager.findDirectory(virtualFile);
if (directory != null && directory.isValid()) {
dirs.add(directory);
}
}
return dirs.toArray(new PsiDirectory[dirs.size()]);
}
return PsiDirectory.EMPTY_ARRAY;
}
public PsiDirectory getOrChooseDirectory() {
return DirectoryChooserUtil.getOrChooseDirectory(this);
}
}
@@ -0,0 +1,99 @@
/*
* 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.ide.navigationToolbar;
import com.intellij.openapi.editor.markup.EffectType;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
import java.awt.*;
/**
* @author Konstantin Bulenkov
*/
public class NavBarListCellRenderer extends ColoredListCellRenderer {
private final Project myProject;
private final NavBarPanel myPanel;
NavBarListCellRenderer(Project project, NavBarPanel panel) {
myProject = project;
myPanel = panel;
}
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
setFocusBorderAroundIcon(false);
final String name = NavBarPresentation.getPresentableText(value, myPanel.getWindow());
Color color = list.getForeground();
boolean isProblemFile = false;
if (value instanceof PsiElement) {
final PsiElement psiElement = (PsiElement)value;
PsiFile psiFile = psiElement.getContainingFile();
if (psiFile != null) {
VirtualFile vFile = psiFile.getVirtualFile();
if (vFile != null) {
if (WolfTheProblemSolver.getInstance(myProject).isProblemFile(vFile)) {
isProblemFile = true;
}
FileStatus status = FileStatusManager.getInstance(myProject).getStatus(vFile);
color = status.getColor();
}
}
else {
isProblemFile = NavBarPanel.wolfHasProblemFilesBeneath(psiElement);
}
}
else if (value instanceof Module) {
final Module module = (Module)value;
isProblemFile = WolfTheProblemSolver.getInstance(myProject).hasProblemFilesBeneath(module);
}
else if (value instanceof Project) {
final Module[] modules = ModuleManager.getInstance((Project)value).getModules();
for (Module module : modules) {
if (WolfTheProblemSolver.getInstance(myProject).hasProblemFilesBeneath(module)) {
isProblemFile = true;
break;
}
}
}
final SimpleTextAttributes nameAttributes;
if (isProblemFile) {
TextAttributes attributes = new TextAttributes(color, null, Color.red, EffectType.WAVE_UNDERSCORE, Font.PLAIN);
nameAttributes = SimpleTextAttributes.fromTextAttributes(attributes);
}
else {
nameAttributes = new SimpleTextAttributes(Font.PLAIN, color);
}
append(name, nameAttributes);
// manually set icon opaque to prevent background artifacts
setIconOpaque(false);
setIcon(NavBarPresentation.getIcon(value, false));
setPaintFocusBorder(false);
setBackground(selected ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground());
}
}
@@ -20,14 +20,11 @@
*/
package com.intellij.ide.navigationToolbar;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.projectView.impl.ProjectRootsUtil;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
@@ -38,31 +35,21 @@ import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.*;
import java.util.List;
public class NavBarModel {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.navigationToolbar.NavBarModel");
private List<Object> myModel = Collections.emptyList();
private int mySelectedIndex;
private final Project myProject;
private final static SimpleTextAttributes WOLFED = new SimpleTextAttributes(null, null, Color.red, SimpleTextAttributes.STYLE_WAVED);
private final NavBarModelListener myNotificator;
public NavBarModel(final Project project) {
@@ -241,13 +228,13 @@ public class NavBarModel {
protected boolean hasChildren(Object object) {
if (!checkValid(object)) return false;
if (!isValid(object)) return false;
return !calcElementChildren(object).isEmpty();
return !getChildren(object).isEmpty();
}
@SuppressWarnings({"SimplifiableIfStatement"})
static boolean checkValid(final Object object) {
static boolean isValid(final Object object) {
if (object instanceof Project) {
return !((Project)object).isDisposed();
}
@@ -266,85 +253,6 @@ public class NavBarModel {
return object != null;
}
@NotNull
protected static String getPresentableText(final Object object, Window window) {
if (!checkValid(object)) return IdeBundle.message("node.structureview.invalid");
for (NavBarModelExtension modelExtension : Extensions.getExtensions(NavBarModelExtension.EP_NAME)) {
String text = modelExtension.getPresentableText(object);
if (text != null) {
boolean truncated = false;
if (window != null) {
Rectangle wndBounds = window.getBounds();
Rectangle rec = ScreenUtil.getScreenRectangle(wndBounds.x, wndBounds.y);
final int windowWidth = rec.width;
while (window.getFontMetrics(window.getFont()).stringWidth(text) + 100 > windowWidth && text.length() > 10) {
text = text.substring(0, text.length() - 10);
truncated = true;
}
}
return text + (truncated ? "..." : "");
}
}
LOG.error("Failed to find navbar presentable text for " + object);
return object.toString();
}
protected SimpleTextAttributes getTextAttributes(final Object object, final boolean selected) {
if (!checkValid(object)) return SimpleTextAttributes.REGULAR_ATTRIBUTES;
if (object instanceof PsiElement) {
if (!ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
return ((PsiElement)object).isValid();
}
}).booleanValue()) return SimpleTextAttributes.GRAYED_ATTRIBUTES;
PsiFile psiFile = ((PsiElement)object).getContainingFile();
if (psiFile != null) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
return new SimpleTextAttributes(null, selected ? null : FileStatusManager.getInstance(myProject).getStatus(virtualFile).getColor(),
Color.red, WolfTheProblemSolver.getInstance(myProject).isProblemFile(virtualFile)
? SimpleTextAttributes.STYLE_WAVED
: SimpleTextAttributes.STYLE_PLAIN);
}
else {
if (object instanceof PsiDirectory) {
VirtualFile vDir = ((PsiDirectory)object).getVirtualFile();
if (vDir.getParent() == null || ProjectRootsUtil.isModuleContentRoot(vDir, myProject)) {
return SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES;
}
}
if (NavBarPanel.wolfHasProblemFilesBeneath((PsiElement)object)) {
return WOLFED;
}
}
}
else if (object instanceof Module) {
if (WolfTheProblemSolver.getInstance(myProject).hasProblemFilesBeneath((Module)object)) {
return WOLFED;
}
}
else if (object instanceof Project) {
final Project project = (Project)object;
final Module[] modules = ApplicationManager.getApplication().runReadAction(
new Computable<Module[]>() {
public Module[] compute() {
return ModuleManager.getInstance(project).getModules();
}
}
);
for (Module module : modules) {
if (WolfTheProblemSolver.getInstance(project).hasProblemFilesBeneath(module)) {
return WOLFED;
}
}
}
return SimpleTextAttributes.REGULAR_ATTRIBUTES;
}
public static void getDirectoryChildren(final PsiDirectory psiDirectory, final Object rootElement, final List<Object> result) {
final ModuleFileIndex moduleFileIndex =
rootElement instanceof Module ? ModuleRootManager.getInstance((Module)rootElement).getFileIndex() : null;
@@ -370,8 +278,8 @@ public class NavBarModel {
return child;
}
List<Object> calcElementChildren(final Object object) {
if (!checkValid(object)) return new ArrayList<Object>();
List<Object> getChildren(final Object object) {
if (!isValid(object)) return new ArrayList<Object>();
final List<Object> result = new ArrayList<Object>();
final Object rootElement = size() > 1 ? getElement(1) : null;
if (!(object instanceof Project) && rootElement instanceof Module && ((Module)rootElement).isDisposed()) return result;
@@ -27,17 +27,11 @@ import com.intellij.ide.projectView.impl.ProjectRootsUtil;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.ui.customization.CustomActionsSchema;
import com.intellij.ide.util.DeleteHandler;
import com.intellij.ide.util.DirectoryChooserUtil;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.markup.EffectType;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.ui.configuration.actions.ModuleDeleteProvider;
@@ -46,7 +40,6 @@ import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.FileStatusListener;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.VfsUtil;
@@ -84,35 +77,30 @@ import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* User: anna
* Date: 03-Nov-2005
*/
public class NavBarPanel extends OpaquePanel.List implements DataProvider, PopupOwner {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.navigationToolbar.NavigationToolbarPanel");
/*private static final Icon LEFT_ICON = IconLoader.getIcon("/general/splitLeft.png");
private static final Icon RIGHT_ICON = IconLoader.getIcon("/general/splitRight.png");
*/
private final ArrayList<MyItemLabel> myList = new ArrayList<MyItemLabel>();
private final NavBarModel myModel;
private final NavBarPresentation myPresentation;
private final Project myProject;
private Runnable myDetacher;
private final ModuleDeleteProvider myDeleteModuleProvider = new ModuleDeleteProvider();
private final IdeView myIdeView = new MyIdeView();
private final ModuleDeleteProvider myDeleteModuleProvider = new ModuleDeleteProvider();
private final IdeView myIdeView;
private final CopyPasteDelegator myCopyPasteDelegator;
private LightweightHint myHint = null;
private ListPopupImpl myNodePopup = null;
private ListPopupImpl myNodePopup = null;
private JComponent myHintContainer;
private Component myContextComponent;
private Runnable myRunWhenListRebuilt;
private final MergingUpdateQueue myUpdateQueue;
private AtomicBoolean myModelUpdating = new AtomicBoolean(Boolean.FALSE);
private MyItemLabel myContextObject;
private PropertyChangeListener myFocusListener = new PropertyChangeListener() {
@@ -124,11 +112,6 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
}
};
private void restartRebuild() {
myUserActivityAlarm.cancelAllRequests();
myUserActivityAlarm.addRequest(myUserActivityAlarmRunnable, Registry.intValue("navbar.userActivityMergeTime"));
}
private Alarm myUserActivityAlarm = new Alarm();
private Runnable myUserActivityAlarmRunnable = new Runnable() {
@Override
@@ -136,7 +119,6 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
processUserActivity();
}
};
private Runnable myUserActivityRunnable = new Runnable() {
@Override
public void run() {
@@ -144,48 +126,12 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
}
};
private void processUserActivity() {
if (!isShowing()) {
return;
}
IdeFocusManager.getInstance(myProject).doWhenFocusSettlesDown(new Runnable() {
@Override
public void run() {
Window wnd = SwingUtilities.windowForComponent(NavBarPanel.this);
if (wnd == null) return;
Component focus = null;
if (!wnd.isActive()) {
IdeFrame frame = UIUtil.getParentOfType(IdeFrame.class, NavBarPanel.this);
if (frame != null) {
focus = IdeFocusManager.getInstance(myProject).getLastFocusedFor(frame);
}
} else {
final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
if (window instanceof Dialog) {
final Dialog dialog = (Dialog)window;
if (dialog.isModal() && !SwingUtilities.isDescendingFrom(NavBarPanel.this, dialog)) {
return;
}
}
}
if (focus != null && focus.isShowing()) {
queueModelUpdate(DataManager.getInstance().getDataContext(focus));
} else if (wnd.isActive()) {
queueModelUpdateFromFocus();
}
}
});
}
public NavBarPanel(final Project project) {
super(new FlowLayout(FlowLayout.LEFT, 5, 0), UIUtil.isUnderGTKLookAndFeel() ? Color.WHITE : UIUtil.getListBackground());
myProject = project;
myModel = new NavBarModel(myProject);
myIdeView = new NavBarIdeView(this);
myPresentation = new NavBarPresentation(myProject);
IdeEventQueue.getInstance().addActivityListener(myUserActivityRunnable);
@@ -294,6 +240,48 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
queueRebuildUi();
}
private void restartRebuild() {
myUserActivityAlarm.cancelAllRequests();
myUserActivityAlarm.addRequest(myUserActivityAlarmRunnable, Registry.intValue("navbar.userActivityMergeTime"));
}
private void processUserActivity() {
if (!isShowing()) {
return;
}
IdeFocusManager.getInstance(myProject).doWhenFocusSettlesDown(new Runnable() {
@Override
public void run() {
Window wnd = SwingUtilities.windowForComponent(NavBarPanel.this);
if (wnd == null) return;
Component focus = null;
if (!wnd.isActive()) {
IdeFrame frame = UIUtil.getParentOfType(IdeFrame.class, NavBarPanel.this);
if (frame != null) {
focus = IdeFocusManager.getInstance(myProject).getLastFocusedFor(frame);
}
} else {
final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
if (window instanceof Dialog) {
final Dialog dialog = (Dialog)window;
if (dialog.isModal() && !SwingUtilities.isDescendingFrom(NavBarPanel.this, dialog)) {
return;
}
}
}
if (focus != null && focus.isShowing()) {
queueModelUpdate(DataManager.getInstance().getDataContext(focus));
} else if (wnd.isActive()) {
queueModelUpdateFromFocus();
}
}
});
}
private void queueModelUpdate(DataContext context) {
_queueModelUpdate(context, null, false);
}
@@ -407,6 +395,14 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
});
}
public Project getProject() {
return myProject;
}
public NavBarModel getModel() {
return myModel;
}
private abstract class AfterModel extends Update {
private AfterModel(Object identity, int priority) {
super(identity, priority);
@@ -518,8 +514,8 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
}
SimpleTextAttributes modelAttributes1 = myModel.getTextAttributes(eachElement, true);
SimpleTextAttributes modelAttributes2 = myModel.getTextAttributes(eachElement, false);
SimpleTextAttributes modelAttributes1 = myPresentation.getTextAttributes(eachElement, true);
SimpleTextAttributes modelAttributes2 = myPresentation.getTextAttributes(eachElement, false);
SimpleTextAttributes labelAttributes = eachLabel.getAttributes();
if (!modelAttributes1.toTextAttributes().equals(labelAttributes.toTextAttributes())
@@ -542,8 +538,8 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
myList.clear();
for (int index = 0; index < myModel.size(); index++) {
final Object object = myModel.get(index);
Icon closedIcon = getIcon(object, false);
Icon openIcon = getIcon(object, true);
Icon closedIcon = NavBarPresentation.getIcon(object, false);
Icon openIcon = NavBarPresentation.getIcon(object, true);
if (closedIcon == null && openIcon != null) closedIcon = openIcon;
if (openIcon == null && closedIcon != null) openIcon = closedIcon;
@@ -551,9 +547,11 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
openIcon = closedIcon = EmptyIcon.create(5);
}
final MyItemLabel label =
new MyItemLabel(object, index, wrapIcon(openIcon, closedIcon, index), NavBarModel.getPresentableText(object, getWindow()),
myModel.getTextAttributes(object, false));
final MyItemLabel label = new MyItemLabel(object,
index,
wrapIcon(openIcon, closedIcon, index),
NavBarPresentation.getPresentableText(object, getWindow()),
myPresentation.getTextAttributes(object, false));
installActions(index, label);
myList.add(label);
@@ -569,31 +567,6 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
}
}
@Nullable
private static Icon getIcon(final Object object, final boolean isopen) {
if (!NavBarModel.checkValid(object)) return null;
if (object instanceof Project) return IconLoader.getIcon("/nodes/project.png");
if (object instanceof Module) return ((Module)object).getModuleType().getNodeIcon(false);
try {
if (object instanceof PsiElement) {
return ApplicationManager.getApplication().runReadAction(new Computable<Icon>() {
public Icon compute() {
return ((PsiElement)object).isValid() ? ((PsiElement)object)
.getIcon(isopen ? Iconable.ICON_FLAG_OPEN : Iconable.ICON_FLAG_CLOSED) : null;
}
});
}
}
catch (IndexNotReadyException e) {
return null;
}
if (object instanceof JdkOrderEntry) return ((JdkOrderEntry)object).getJdk().getSdkType().getIcon();
if (object instanceof LibraryOrderEntry) return IconLoader.getIcon("/nodes/ppLibClosed.png");
if (object instanceof ModuleOrderEntry) return ((ModuleOrderEntry)object).getModule().getModuleType().getNodeIcon(false);
return null;
}
private Icon wrapIcon(final Icon openIcon, final Icon closedIcon, final int idx) {
return new Icon() {
public void paintIcon(Component c, Graphics g, int x, int y) {
@@ -633,7 +606,7 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
}, "scrollToVisible");
}
private Window getWindow() {
Window getWindow() {
return !isShowing() ? null : (Window)UIUtil.findUltimateParent(this);
}
@@ -727,14 +700,14 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
}
final Object object = myModel.getElement(index);
final java.util.List<Object> objects = myModel.calcElementChildren(object);
final java.util.List<Object> objects = myModel.getChildren(object);
if (!objects.isEmpty()) {
final Object[] siblings = new Object[objects.size()];
final Icon[] icons = new Icon[objects.size()];
for (int i = 0; i < objects.size(); i++) {
siblings[i] = objects.get(i);
icons[i] = getIcon(siblings[i], false);
icons[i] = NavBarPresentation.getIcon(siblings[i], false);
}
final MyItemLabel item = getItem(index);
LOG.assertTrue(item != null);
@@ -745,7 +718,7 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
@NotNull
public String getTextFor(final Object value) {
return NavBarModel.getPresentableText(value, null);
return NavBarPresentation.getPresentableText(value, null);
}
public boolean isSelectable(Object value) {
@@ -770,7 +743,7 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
step.setDefaultOptionIndex(index < myModel.size() - 1 ? objects.indexOf(myModel.getElement(index + 1)) : 0);
myNodePopup = new ListPopupImpl(step) {
protected ListCellRenderer getListElementRenderer() {
return new MySiblingsListCellRenderer();
return new NavBarListCellRenderer(myProject, NavBarPanel.this);
}
};
@@ -873,7 +846,7 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
}
}
private void hideHint() {
void hideHint() {
if (myHint != null) {
myHint.hide();
myHint = null;
@@ -950,7 +923,7 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
@Nullable
@SuppressWarnings({"unchecked"})
private <T> T getSelectedElement(Class<T> klass) {
<T> T getSelectedElement(Class<T> klass) {
Object selectedValue1 = myModel.getSelectedValue();
if (selectedValue1 == null) {
final int modelSize = myModel.size();
@@ -1251,59 +1224,6 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
}
}
private final class MyIdeView implements IdeView {
public void selectElement(PsiElement element) {
myModel.updateModel(element);
if (element instanceof Navigatable) {
final Navigatable navigatable = (Navigatable)element;
if (navigatable.canNavigate()) {
((Navigatable)element).navigate(true);
}
}
hideHint();
}
public PsiDirectory[] getDirectories() {
final PsiDirectory dir = getSelectedElement(PsiDirectory.class);
if (dir != null && dir.isValid()) {
return new PsiDirectory[]{dir};
}
final PsiElement element = getSelectedElement(PsiElement.class);
if (element != null && element.isValid()) {
final PsiFile file = element.getContainingFile();
if (file != null) {
final PsiDirectory psiDirectory = file.getContainingDirectory();
return psiDirectory != null ? new PsiDirectory[]{psiDirectory} : PsiDirectory.EMPTY_ARRAY;
}
}
final PsiDirectoryContainer directoryContainer = getSelectedElement(PsiDirectoryContainer.class);
if (directoryContainer != null) {
return directoryContainer.getDirectories();
}
final Module module = getSelectedElement(Module.class);
if (module != null && !module.isDisposed()) {
ArrayList<PsiDirectory> dirs = new ArrayList<PsiDirectory>();
final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots();
final PsiManager psiManager = PsiManager.getInstance(myProject);
for (VirtualFile virtualFile : sourceRoots) {
final PsiDirectory directory = psiManager.findDirectory(virtualFile);
if (directory != null && directory.isValid()) {
dirs.add(directory);
}
}
return dirs.toArray(new PsiDirectory[dirs.size()]);
}
return PsiDirectory.EMPTY_ARRAY;
}
public PsiDirectory getOrChooseDirectory() {
return DirectoryChooserUtil.getOrChooseDirectory(this);
}
}
private class MyPsiTreeChangeAdapter extends PsiTreeChangeAdapter {
public void childAdded(PsiTreeChangeEvent event) {
queueModelUpdateFromFocus();
@@ -1357,59 +1277,4 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup
queueRebuildUi();
}
}
private class MySiblingsListCellRenderer extends ColoredListCellRenderer {
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
setFocusBorderAroundIcon(false);
String name = NavBarModel.getPresentableText(value, getWindow());
Color color = list.getForeground();
boolean isProblemFile = false;
if (value instanceof PsiElement) {
final PsiElement psiElement = (PsiElement)value;
PsiFile psiFile = psiElement.getContainingFile();
if (psiFile != null) {
VirtualFile vFile = psiFile.getVirtualFile();
if (vFile != null) {
if (WolfTheProblemSolver.getInstance(myProject).isProblemFile(vFile)) {
isProblemFile = true;
}
FileStatus status = FileStatusManager.getInstance(myProject).getStatus(vFile);
color = status.getColor();
}
}
else {
isProblemFile = wolfHasProblemFilesBeneath(psiElement);
}
}
else if (value instanceof Module) {
final Module module = (Module)value;
isProblemFile = WolfTheProblemSolver.getInstance(myProject).hasProblemFilesBeneath(module);
}
else if (value instanceof Project) {
final Module[] modules = ModuleManager.getInstance((Project)value).getModules();
for (Module module : modules) {
if (WolfTheProblemSolver.getInstance(myProject).hasProblemFilesBeneath(module)) {
isProblemFile = true;
break;
}
}
}
SimpleTextAttributes nameAttributes;
if (isProblemFile) {
TextAttributes attributes = new TextAttributes(color, null, Color.red, EffectType.WAVE_UNDERSCORE, Font.PLAIN);
nameAttributes = SimpleTextAttributes.fromTextAttributes(attributes);
}
else {
nameAttributes = new SimpleTextAttributes(Font.PLAIN, color);
}
append(name, nameAttributes);
// manually set icon opaque to prevent background artifacts
setIconOpaque(false);
setIcon(NavBarPanel.getIcon(value, false));
setPaintFocusBorder(false);
setBackground(selected ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground());
}
}
}
@@ -0,0 +1,160 @@
/*
* 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.ide.navigationToolbar;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.projectView.impl.ProjectRootsUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.JdkOrderEntry;
import com.intellij.openapi.roots.LibraryOrderEntry;
import com.intellij.openapi.roots.ModuleOrderEntry;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
/**
* @author Konstantin Bulenkov
*/
public class NavBarPresentation {
private static final SimpleTextAttributes WOLFED = new SimpleTextAttributes(null, null, Color.red, SimpleTextAttributes.STYLE_WAVED);
private static final Icon PROJECT_ICON = IconLoader.getIcon("/nodes/project.png");
private final Project myProject;
public NavBarPresentation(Project project) {
myProject = project;
}
@Nullable
public static Icon getIcon(final Object object, final boolean open) {
if (!NavBarModel.isValid(object)) return null;
if (object instanceof Project) return PROJECT_ICON;
if (object instanceof Module) return ((Module)object).getModuleType().getNodeIcon(false);
try {
if (object instanceof PsiElement) {
return ApplicationManager.getApplication().runReadAction(new Computable<Icon>() {
public Icon compute() {
return ((PsiElement)object).isValid() ? ((PsiElement)object)
.getIcon(open ? Iconable.ICON_FLAG_OPEN : Iconable.ICON_FLAG_CLOSED) : null;
}
});
}
}
catch (IndexNotReadyException e) {
return null;
}
if (object instanceof JdkOrderEntry) return ((JdkOrderEntry)object).getJdk().getSdkType().getIcon();
if (object instanceof LibraryOrderEntry) return IconLoader.getIcon("/nodes/ppLibClosed.png");
if (object instanceof ModuleOrderEntry) return ((ModuleOrderEntry)object).getModule().getModuleType().getNodeIcon(false);
return null;
}
@NotNull
protected static String getPresentableText(final Object object, Window window) {
if (!NavBarModel.isValid(object)) return IdeBundle.message("node.structureview.invalid");
for (NavBarModelExtension modelExtension : Extensions.getExtensions(NavBarModelExtension.EP_NAME)) {
String text = modelExtension.getPresentableText(object);
if (text != null) {
boolean truncated = false;
if (window != null) {
Rectangle wndBounds = window.getBounds();
Rectangle rec = ScreenUtil.getScreenRectangle(wndBounds.x, wndBounds.y);
final int windowWidth = rec.width;
while (window.getFontMetrics(window.getFont()).stringWidth(text) + 100 > windowWidth && text.length() > 10) {
text = text.substring(0, text.length() - 10);
truncated = true;
}
}
return text + (truncated ? "..." : "");
}
}
return object.toString();
}
protected SimpleTextAttributes getTextAttributes(final Object object, final boolean selected) {
if (!NavBarModel.isValid(object)) return SimpleTextAttributes.REGULAR_ATTRIBUTES;
if (object instanceof PsiElement) {
if (!ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
return ((PsiElement)object).isValid();
}
}).booleanValue()) return SimpleTextAttributes.GRAYED_ATTRIBUTES;
PsiFile psiFile = ((PsiElement)object).getContainingFile();
if (psiFile != null) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
return new SimpleTextAttributes(null, selected ? null : FileStatusManager.getInstance(myProject).getStatus(virtualFile).getColor(),
Color.red, WolfTheProblemSolver.getInstance(myProject).isProblemFile(virtualFile)
? SimpleTextAttributes.STYLE_WAVED
: SimpleTextAttributes.STYLE_PLAIN);
}
else {
if (object instanceof PsiDirectory) {
VirtualFile vDir = ((PsiDirectory)object).getVirtualFile();
if (vDir.getParent() == null || ProjectRootsUtil.isModuleContentRoot(vDir, myProject)) {
return SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES;
}
}
if (NavBarPanel.wolfHasProblemFilesBeneath((PsiElement)object)) {
return WOLFED;
}
}
}
else if (object instanceof Module) {
if (WolfTheProblemSolver.getInstance(myProject).hasProblemFilesBeneath((Module)object)) {
return WOLFED;
}
}
else if (object instanceof Project) {
final Project project = (Project)object;
final Module[] modules = ApplicationManager.getApplication().runReadAction(
new Computable<Module[]>() {
public Module[] compute() {
return ModuleManager.getInstance(project).getModules();
}
}
);
for (Module module : modules) {
if (WolfTheProblemSolver.getInstance(project).hasProblemFilesBeneath(module)) {
return WOLFED;
}
}
}
return SimpleTextAttributes.REGULAR_ATTRIBUTES;
}
}