From 415e55ea77a16b514be125a07237de9bad5d1635 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 9 Feb 2011 17:36:17 +0300 Subject: [PATCH] NavBar presentation and other refactorings --- .../ide/navigationToolbar/NavBarIdeView.java | 86 ++++++ .../NavBarListCellRenderer.java | 99 ++++++ .../ide/navigationToolbar/NavBarModel.java | 102 +------ .../ide/navigationToolbar/NavBarPanel.java | 287 +++++------------- .../navigationToolbar/NavBarPresentation.java | 160 ++++++++++ 5 files changed, 426 insertions(+), 308 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarIdeView.java create mode 100644 platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListCellRenderer.java create mode 100644 platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPresentation.java diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarIdeView.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarIdeView.java new file mode 100644 index 000000000000..e0dde3178c1d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarIdeView.java @@ -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 dirs = new ArrayList(); + 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); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListCellRenderer.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListCellRenderer.java new file mode 100644 index 000000000000..68189c10234c --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListCellRenderer.java @@ -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()); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java index 7a6ac208133d..2500ab25fac9 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java @@ -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 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() { - 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() { - 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 result) { final ModuleFileIndex moduleFileIndex = rootElement instanceof Module ? ModuleRootManager.getInstance((Module)rootElement).getFileIndex() : null; @@ -370,8 +278,8 @@ public class NavBarModel { return child; } - List calcElementChildren(final Object object) { - if (!checkValid(object)) return new ArrayList(); + List getChildren(final Object object) { + if (!isValid(object)) return new ArrayList(); final List result = new ArrayList(); final Object rootElement = size() > 1 ? getElement(1) : null; if (!(object instanceof Project) && rootElement instanceof Module && ((Module)rootElement).isDisposed()) return result; diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java index 416aaa02ff99..cf80cbf1f0e7 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java @@ -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 myList = new ArrayList(); 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() { - 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 objects = myModel.calcElementChildren(object); + final java.util.List 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 getSelectedElement(Class klass) { + T getSelectedElement(Class 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 dirs = new ArrayList(); - 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()); - } - } - } diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPresentation.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPresentation.java new file mode 100644 index 000000000000..f6a556ada366 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPresentation.java @@ -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() { + 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() { + 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() { + public Module[] compute() { + return ModuleManager.getInstance(project).getModules(); + } + } + ); + for (Module module : modules) { + if (WolfTheProblemSolver.getInstance(project).hasProblemFilesBeneath(module)) { + return WOLFED; + } + } + } + return SimpleTextAttributes.REGULAR_ATTRIBUTES; + } + +}