From d6ce188febad487cb2122fb841eaa74da2b163e2 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 9 Mar 2011 11:45:23 +0300 Subject: [PATCH 1/8] IDEA-66228 SVN+SSH: on attempt to login IDEA hangs --- .../idea/svn/SvnAuthenticationNotifier.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java index 51ea0e34f958..a9d21e7781ca 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java @@ -79,17 +79,18 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl resultRef = new Ref(); + final boolean done = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { + public void run() { + final boolean result = interactiveValidation(obj.myProject, obj.getUrl(), obj.getRealm(), obj.getKind()); + log("ask result for: " + obj.getUrl() + " is: " + result); + resultRef.set(result); + if (result) { onStateChangedToSuccess(obj); } - }, "Checking authorization state", true, myVcs.getProject()); - } - return result; + } + }, "Checking authorization state", true, myVcs.getProject()); + return done && Boolean.TRUE.equals(resultRef.get()); } private void onStateChangedToSuccess(final AuthenticationRequest obj) { From 562a2b0145f1ce307f0e43ffd930356e633bc8ef Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 9 Mar 2011 15:10:56 +0300 Subject: [PATCH 2/8] IDEA-66228 SVN+SSH: on attempt to login IDEA hangs (+ remember for passive requests) (cherry picked from commit a10a1182f9cee16392ed3bb40cc7ce9fe158118c) --- .../src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java index a9d21e7781ca..fd0e7e06eb24 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java @@ -94,6 +94,7 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl outdatedRequests = new LinkedList(); From b84f7d04635ada848a8321ed92316fbd31fd8a31 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 9 Mar 2011 15:32:19 +0300 Subject: [PATCH 3/8] IDEA-66222 USE at com.intellij.ide.todo.CustomChangelistTodosTreeBuilder$1.getTodoItemsCount --- .../CustomChangelistTodosTreeBuilder.java | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodosTreeBuilder.java b/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodosTreeBuilder.java index 55c8538271f6..f55109b5f0e4 100644 --- a/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodosTreeBuilder.java +++ b/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodosTreeBuilder.java @@ -105,23 +105,7 @@ public class CustomChangelistTodosTreeBuilder extends TodoTreeBuilder { @NotNull @Override public TodoItem[] findTodoItems(@NotNull PsiFile file) { - if (! myIncludedFiles.contains(file)) return EMPTY_ITEMS; - if (myDirtyFileSet.contains(file.getVirtualFile())) { - myMap.remove(file); - final Change change = myChangeListManager.getChange(file.getVirtualFile()); - if (change != null) { - final TodoCheckinHandlerWorker worker = new TodoCheckinHandlerWorker(myProject, Collections.singletonList(change), getTodoTreeStructure().getTodoFilter(), true); - worker.execute(); - final List todoItems = worker.inOneList(); - if (todoItems != null && ! todoItems.isEmpty()) { - for (TodoItem todoItem : todoItems) { - myMap.putValue(file, todoItem); - } - } - } - } - final Collection todoItems = myMap.get(file); - return todoItems == null || todoItems.isEmpty() ? EMPTY_ITEMS : todoItems.toArray(new TodoItem[todoItems.size()]); + return findPatternedTodoItems(file, getTodoTreeStructure().getTodoFilter()); } @NotNull @@ -148,19 +132,34 @@ public class CustomChangelistTodosTreeBuilder extends TodoTreeBuilder { @Override public int getTodoItemsCount(@NotNull PsiFile file, @NotNull TodoPattern pattern) { - throw new UnsupportedOperationException(); - // just would not work while implemented like that - /*final TodoItem[] todoItems = findTodoItems(file); - if (todoItems.length == 0) return 0; - int cnt = 0; - for (TodoItem todoItem : todoItems) { - if (todoItem.getPattern().equals(pattern)) ++ cnt; - } - return cnt;*/ + final TodoFilter filter = new TodoFilter(); + filter.addTodoPattern(pattern); + return findPatternedTodoItems(file, filter).length; } }; } + private TodoItem[] findPatternedTodoItems(PsiFile file, final TodoFilter todoFilter) { + if (! myIncludedFiles.contains(file)) return EMPTY_ITEMS; + if (myDirtyFileSet.contains(file.getVirtualFile())) { + myMap.remove(file); + final Change change = myChangeListManager.getChange(file.getVirtualFile()); + if (change != null) { + final TodoCheckinHandlerWorker + worker = new TodoCheckinHandlerWorker(myProject, Collections.singletonList(change), todoFilter, true); + worker.execute(); + final List todoItems = worker.inOneList(); + if (todoItems != null && ! todoItems.isEmpty()) { + for (TodoItem todoItem : todoItems) { + myMap.putValue(file, todoItem); + } + } + } + } + final Collection todoItems = myMap.get(file); + return todoItems == null || todoItems.isEmpty() ? EMPTY_ITEMS : todoItems.toArray(new TodoItem[todoItems.size()]); + } + @Override protected TodoTreeStructure createTreeStructure() { return new CustomChangelistTodoTreeStructure(myProject, myPsiTodoSearchHelper); From f26ffb5608f84625f7c779c60ff3425a095aee39 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 9 Mar 2011 13:36:19 +0100 Subject: [PATCH 4/8] IDEA-64871 (Inspection result viewer screws up sorting) --- .../ui/InspectionResultsView.java | 7 +++---- .../codeInspection/ui/InspectionTree.java | 18 +++++------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index dafc108e254f..e8755c2f07b4 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -428,10 +428,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private void addTool(InspectionTool tool, HighlightDisplayLevel errorLevel, boolean groupedBySeverity) { final InspectionTreeNode parentNode = getToolParentNode(tool.getGroupDisplayName().length() > 0 ? tool.getGroupDisplayName() : InspectionProfileEntry.GENERAL_GROUP_NAME, errorLevel, groupedBySeverity); tool.createToolNode(myProvider, parentNode, myGlobalInspectionContext.getUIOptions().SHOW_STRUCTURE); - regsisterActionShortcuts(tool); + registerActionShortcuts(tool); } - private void regsisterActionShortcuts(InspectionTool tool) { + private void registerActionShortcuts(InspectionTool tool) { final QuickFixAction[] fixes = tool.getQuickFixes(null); if (fixes != null) { for (QuickFixAction fix : fixes) { @@ -465,8 +465,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } clearTree(); boolean resultsFound = buildTree(); - myTree.sort(); - myTree.restoreExpantionAndSelection(); + myTree.restoreExpansionAndSelection(); return resultsFound; } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java index 870b6e6aa849..46a111d42af5 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java @@ -212,26 +212,22 @@ public class InspectionTree extends Tree { } } - public void restoreExpantionAndSelection() { - restoreExpantion(); + public void restoreExpansionAndSelection() { + restoreExpansionStatus((InspectionTreeNode)getModel().getRoot()); if (mySelectionPath != null) { mySelectionPath.restore(); } } - private void restoreExpantion() { - restoreExpantionStatus((InspectionTreeNode)getModel().getRoot()); - } - - - private void restoreExpantionStatus(InspectionTreeNode node) { + private void restoreExpansionStatus(InspectionTreeNode node) { if (myExpandedUserObjects.contains(node.getUserObject())) { + sortChildren(node); TreeNode[] pathToNode = node.getPath(); expandPath(new TreePath(pathToNode)); Enumeration children = node.children(); while (children.hasMoreElements()) { InspectionTreeNode childNode = (InspectionTreeNode)children.nextElement(); - restoreExpantionStatus(childNode); + restoreExpansionStatus(childNode); } } } @@ -300,10 +296,6 @@ public class InspectionTree extends Tree { } } - public void sort() { - sortChildren(getRoot()); - } - private static void sortChildren(InspectionTreeNode node) { final List children = TreeUtil.childrenToArray(node); Collections.sort(children, InspectionResultsViewComparator.getInstance()); From 908a7adf2815fa507b091f4d4dfba9ac18943092 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 9 Mar 2011 13:39:34 +0100 Subject: [PATCH 5/8] cache line number because it is expensive to calculate and is used for sorting the inspection results tree --- .../ex/ProblemDescriptorImpl.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/ProblemDescriptorImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/ProblemDescriptorImpl.java index d558064fdc00..cbb5a9709b0c 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/ProblemDescriptorImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/ProblemDescriptorImpl.java @@ -49,6 +49,7 @@ public class ProblemDescriptorImpl extends CommonProblemDescriptorImpl implement private final boolean myShowTooltip; private final HintAction myHintAction; private TextAttributesKey myEnforcedTextAttributes; + private int myLineNumber = -1; public ProblemDescriptorImpl(@NotNull PsiElement startElement, @NotNull PsiElement endElement, String descriptionTemplate, LocalQuickFix[] fixes, ProblemHighlightType highlightType, @@ -132,17 +133,20 @@ public class ProblemDescriptorImpl extends CommonProblemDescriptorImpl implement } public int getLineNumber() { - PsiElement psiElement = getPsiElement(); - if (psiElement == null) return -1; - if (!psiElement.isValid()) return -1; - LOG.assertTrue(psiElement.isPhysical()); - PsiFile containingFile = InjectedLanguageUtil.getTopLevelFile(psiElement); - Document document = PsiDocumentManager.getInstance(psiElement.getProject()).getDocument(containingFile); - if (document == null) return -1; - TextRange textRange = getTextRange(); - if (textRange == null) return -1; - textRange = InjectedLanguageManager.getInstance(containingFile.getProject()).injectedToHost(psiElement, textRange); - return document.getLineNumber(textRange.getStartOffset()) + 1; + if (myLineNumber == -1) { + PsiElement psiElement = getPsiElement(); + if (psiElement == null) return -1; + if (!psiElement.isValid()) return -1; + LOG.assertTrue(psiElement.isPhysical()); + PsiFile containingFile = InjectedLanguageUtil.getTopLevelFile(psiElement); + Document document = PsiDocumentManager.getInstance(psiElement.getProject()).getDocument(containingFile); + if (document == null) return -1; + TextRange textRange = getTextRange(); + if (textRange == null) return -1; + textRange = InjectedLanguageManager.getInstance(containingFile.getProject()).injectedToHost(psiElement, textRange); + myLineNumber = document.getLineNumber(textRange.getStartOffset()) + 1; + } + return myLineNumber; } public ProblemHighlightType getHighlightType() { From f064ec8d8452fa8e8d4f81037b5af6a5407b74d4 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 9 Mar 2011 13:42:27 +0100 Subject: [PATCH 6/8] compare element name before line number to get consistent results for files containing multiple classes --- .../ui/InspectionResultsViewComparator.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java index fd143315a1ab..826ed7730b8e 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java @@ -127,10 +127,14 @@ public class InspectionResultsViewComparator implements Comparator { } private static int compareEntities(final RefEntity entity1, final RefEntity entity2) { + if (entity1 != null && entity2 != null) { + final int nameComparison = entity1.getName().compareToIgnoreCase(entity2.getName()); + if (nameComparison != 0) { + return nameComparison; + } + } if (entity1 instanceof RefElement && entity2 instanceof RefElement) { return PsiUtilBase.compareElementsByPosition(((RefElement)entity1).getElement(), ((RefElement)entity2).getElement()); - } else if (entity1 != null && entity2 != null) { - return entity1.getName().compareToIgnoreCase(entity2.getName()); } return 0; } From d7e0a953e0ff274f9539871779b0bc08c4acb158 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 9 Mar 2011 15:42:39 +0300 Subject: [PATCH 7/8] DataProvider registration --- .../src/com/intellij/ui/components/JBList.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/components/JBList.java b/platform/platform-api/src/com/intellij/ui/components/JBList.java index 27b1458d86a9..71f523ac687f 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBList.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBList.java @@ -15,6 +15,8 @@ */ package com.intellij.ui.components; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.ui.ComponentWithExpandableItems; import com.intellij.ui.ExpandableItemsHandler; import com.intellij.ui.ExpandableItemsHandlerFactory; @@ -33,7 +35,7 @@ import java.util.Collection; * @author Anton Makeev * @author Konstantin Bulenkov */ -public class JBList extends JList implements ComponentWithEmptyText, ComponentWithExpandableItems { +public class JBList extends JList implements ComponentWithEmptyText, ComponentWithExpandableItems{ private StatusText myEmptyText; private ExpandableItemsHandler myExpandableItemsHandler; @@ -127,4 +129,8 @@ public class JBList extends JList implements ComponentWithEmptyText, ComponentWi } }); } + + public void setDataProvider(DataProvider provider) { + putClientProperty(DataManager.CLIENT_PROPERTY_DATA_PROVIDER, provider); + } } From f1438992461d8f060dfbfe233c2394f900ce3e78 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 9 Mar 2011 15:43:40 +0300 Subject: [PATCH 8/8] new NavBar popup (in development) --- .../ide/navigationToolbar/NavBarItem.java | 46 ++++- .../ide/navigationToolbar/NavBarListener.java | 4 +- .../ide/navigationToolbar/NavBarPanel.java | 162 +++++++++--------- .../ide/navigationToolbar/NavBarPopup.java | 146 ++++++++++++++++ .../src/misc/registry.properties | 1 + 5 files changed, 272 insertions(+), 87 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPopup.java diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarItem.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarItem.java index cb96da066b1c..628a12fff7f2 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarItem.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarItem.java @@ -15,12 +15,16 @@ */ package com.intellij.ide.navigationToolbar; +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.psi.PsiElement; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; -import com.intellij.ui.popup.list.ListPopupImpl; import com.intellij.util.Icons; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NonNls; import javax.swing.*; import java.awt.*; @@ -28,18 +32,20 @@ import java.awt.*; /** * @author Konstantin Bulenkov */ -class NavBarItem extends SimpleColoredComponent { +class NavBarItem extends SimpleColoredComponent implements DataProvider{ private final String myText; private final SimpleTextAttributes myAttributes; private final int myIndex; private final Icon myIcon; private final NavBarPanel myPanel; private Object myObject; + private final boolean isPopupElement; public NavBarItem(NavBarPanel panel, Object object, int idx) { myPanel = panel; myObject = object; myIndex = idx; + isPopupElement = idx == -1; if (object != null) { Icon closedIcon = NavBarPresentation.getIcon(object, false); Icon openIcon = NavBarPresentation.getIcon(object, true); @@ -63,6 +69,15 @@ class NavBarItem extends SimpleColoredComponent { update(); } + /** + * item for node popup + * @param panel + * @param object + */ + public NavBarItem(NavBarPanel panel, Object object) { + this(panel, object, -1); + } + public Object getObject() { return myObject; } @@ -75,12 +90,13 @@ class NavBarItem extends SimpleColoredComponent { clear(); setIcon(myIcon); - boolean focused = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == myPanel; + final Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + boolean focused = isPopupElement ? myPanel.isNodePopupActive() : focusOwner == myPanel; final NavBarModel model = myPanel.getModel(); - boolean selected = model.getSelectedIndex() == myIndex; + boolean selected = isPopupElement ? myPanel.isSelectedInPopup(myObject) : model.getSelectedIndex() == myIndex; - setPaintFocusBorder(!focused && selected); + setPaintFocusBorder(!focused && selected && !isPopupElement); setFocusBorderAroundIcon(false); setBackground(selected && focused @@ -103,8 +119,7 @@ class NavBarItem extends SimpleColoredComponent { 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) { - final ListPopupImpl nodePopup = myPanel.getNodePopup(); - if (myPanel.getModel().getSelectedIndex() == idx && nodePopup != null && nodePopup.isVisible()) { + if (myPanel.getModel().getSelectedIndex() == idx && myPanel.isNodePopupActive()) { openIcon.paintIcon(c, g, x, y); } else { @@ -121,4 +136,21 @@ class NavBarItem extends SimpleColoredComponent { } }; } + + @Override + public Object getData(@NonNls String dataId) { + if (PlatformDataKeys.PROJECT.is(dataId)) { + return myPanel.getProject(); + } + + if (LangDataKeys.PSI_ELEMENT.is(dataId)) { + return myObject instanceof PsiElement ? myObject : null; + } + + if (LangDataKeys.PSI_FILE.is(dataId)) { + return myObject instanceof PsiElement ? ((PsiElement)myObject).getContainingFile() : null; + } + + return null; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java index fa6576c98f85..7c3435e0bbbb 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java @@ -27,7 +27,6 @@ import com.intellij.problems.WolfTheProblemSolver; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiTreeChangeEvent; import com.intellij.psi.PsiTreeChangeListener; -import com.intellij.ui.popup.list.ListPopupImpl; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; @@ -142,8 +141,7 @@ public class NavBarListener extends WolfTheProblemSolver.ProblemListener } private void processFocusLost(FocusEvent e) { - final ListPopupImpl nodePopup = myPanel.getNodePopup(); - final boolean nodePopupInactive = nodePopup == null || !nodePopup.isVisible() || !nodePopup.isFocused(); + final boolean nodePopupInactive = !myPanel.isNodePopupActive(); boolean childPopupInactive = !JBPopupFactory.getInstance().isChildPopupFocused(myPanel); if (nodePopupInactive && childPopupInactive) { final Component opposite = e.getOppositeComponent(); 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 51d7d4ebddfb..21ad17197e7d 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java @@ -37,6 +37,7 @@ import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.AsyncResult; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFocusManager; @@ -66,7 +67,7 @@ import java.util.Set; * @author Konstantin Bulenkov * @author Anna Kozlova */ -public class NavBarPanel extends OpaquePanel.List implements DataProvider, PopupOwner, Disposable{ +public class NavBarPanel extends OpaquePanel.List implements DataProvider, PopupOwner, Disposable { private final NavBarModel myModel; @@ -79,8 +80,10 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup private final IdeView myIdeView; private final CopyPasteDelegator myCopyPasteDelegator; private LightweightHint myHint = null; + private NavBarPopup myNodeHint = null; private ListPopupImpl myNodePopup = null; + private JComponent myHintContainer; private Component myContextComponent; @@ -114,8 +117,9 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup Disposer.register(project, this); } - public ListPopupImpl getNodePopup() { - return myNodePopup; + public boolean isNodePopupActive() { + return (myNodePopup != null && myNodePopup.isVisible() && myNodePopup.isFocused()) + || (myNodeHint != null && myNodeHint.isVisible() && myNodeHint.getComponent().hasFocus()); } public LightweightHint getHint() { @@ -194,6 +198,13 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup return myDisposed; } + boolean isSelectedInPopup(Object object) { + if (isNodePopupActive()) { + return myNodeHint.getSelectedValue() == object; + } + return false; + } + private static Object optimizeTarget(Object target) { if (target instanceof PsiDirectory && ((PsiDirectory)target).getFiles().length == 0) { final PsiDirectory[] subDir = ((PsiDirectory)target).getSubdirectories(); @@ -234,7 +245,7 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup public void moveRight() { shiftFocus(1); } - private void shiftFocus(int direction) { + void shiftFocus(int direction) { final int selectedIndex = myModel.getSelectedIndex(); final int index = myModel.getIndexByModel(selectedIndex + direction); myModel.setSelectedIndex(index); @@ -402,76 +413,63 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup icons[i] = NavBarPresentation.getIcon(siblings[i], false); } final NavBarItem item = getItem(index); - final BaseListPopupStep step = new BaseListPopupStep("", siblings, icons) { - public boolean isSpeedSearchEnabled() { - return true; + final BaseListPopupStep step; + if (Registry.is("navbar.newpopup")) { + myNodePopup = null; + myNodeHint = new NavBarPopup(this, siblings, index < myModel.size() - 1 ? objects.indexOf(myModel.getElement(index + 1)) : 0); + if (item != null && item.isShowing()) { + myNodeHint.show(item); } - - @NotNull - public String getTextFor(final Object value) { - return NavBarPresentation.getPresentableText(value, null); - } - - public boolean isSelectable(Object value) { - return true; - } - - public PopupStep onChosen(final Object selectedValue, final boolean finalChoice) { - return doFinalStep(new Runnable() { - public void run() { - navigateInsideBar(optimizeTarget(selectedValue)); - } - }); - } - }; - step.setDefaultOptionIndex(index < myModel.size() - 1 ? objects.indexOf(myModel.getElement(index + 1)) : 0); - myNodePopup = new ListPopupImpl(step) { - protected ListCellRenderer getListElementRenderer() { - return new NavBarListCellRenderer(myProject, NavBarPanel.this); - } - - @Override - public void cancel(InputEvent e) { - super.cancel(e); - } - }; - myNodePopup.registerAction("left", KeyEvent.VK_LEFT, 0, new AbstractAction() { - public void actionPerformed(ActionEvent e) { - myNodePopup.goBack(); - shiftFocus(-1); - restorePopup(); - } - }); - myNodePopup.registerAction("right", KeyEvent.VK_RIGHT, 0, new AbstractAction() { - public void actionPerformed(ActionEvent e) { - myNodePopup.goBack(); - shiftFocus(1); - restorePopup(); - } - }); - - ListenerUtil.addMouseListener(myNodePopup.getComponent(), new MouseAdapter() { - public void mouseReleased(final MouseEvent e) { - if (SystemInfo.isWindows) { - click(e); + } else { + myNodeHint = null; + step = new BaseListPopupStep("", siblings, icons) { + public boolean isSpeedSearchEnabled() { + return true; } - } - public void mousePressed(final MouseEvent e) { - if (!SystemInfo.isWindows) { - click(e); + @NotNull + public String getTextFor(final Object value) { + return NavBarPresentation.getPresentableText(value, null); } - } - private void click(final MouseEvent e) { - if (!e.isConsumed() && e.isPopupTrigger()) { - myModel.setSelectedIndex(index); - IdeFocusManager.getInstance(myProject).requestFocus(NavBarPanel.this, true); - rightClick(index); - e.consume(); + public boolean isSelectable(Object value) { + return true; } - } - }); + + public PopupStep onChosen(final Object selectedValue, final boolean finalChoice) { + return doFinalStep(new Runnable() { + public void run() { + navigateInsideBar(optimizeTarget(selectedValue)); + } + }); + } + }; + step.setDefaultOptionIndex(index < myModel.size() - 1 ? objects.indexOf(myModel.getElement(index + 1)) : 0); + myNodePopup = new ListPopupImpl(step) { + protected ListCellRenderer getListElementRenderer() { + return new NavBarListCellRenderer(myProject, NavBarPanel.this); + } + + @Override + public void cancel(InputEvent e) { + super.cancel(e); + } + }; + myNodePopup.registerAction("left", KeyEvent.VK_LEFT, 0, new AbstractAction() { + public void actionPerformed(ActionEvent e) { + myNodePopup.goBack(); + shiftFocus(-1); + restorePopup(); + } + }); + myNodePopup.registerAction("right", KeyEvent.VK_RIGHT, 0, new AbstractAction() { + public void actionPerformed(ActionEvent e) { + myNodePopup.goBack(); + shiftFocus(1); + restorePopup(); + } + }); + if (!isValid()) { validate(); @@ -480,11 +478,13 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup if (item != null && item.isShowing() && step.getValues().size() > 0) { myNodePopup.showUnderneathOf(item); } + } } } boolean isNodePopupShowing() { - return myNodePopup != null && myNodePopup.isVisible(); + return (myNodePopup != null && myNodePopup.isVisible()) + || (myNodeHint != null && myNodeHint.isVisible()); } private void navigateInsideBar(final Object object) { @@ -512,7 +512,7 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup }, NavBarUpdateQueue.ID.NAVIGATE_INSIDE); } - private void rightClick(final int index) { + void rightClick(final int index) { final ActionManager actionManager = ActionManager.getInstance(); final ActionGroup group = (ActionGroup)CustomActionsSchema.getInstance().getCorrectedAction(IdeActions.GROUP_NAVBAR_POPUP); final ActionPopupMenu popupMenu = actionManager.createActionPopupMenu(ActionPlaces.NAVIGATION_BAR, group); @@ -522,12 +522,16 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup } } - private void restorePopup() { + void restorePopup() { cancelPopup(); ctrlClick(myModel.getSelectedIndex()); } - private void cancelPopup() { + void cancelPopup() { + if (myNodeHint != null) { + myNodeHint.hide(); + myNodeHint = null; + } if (myNodePopup != null) { myNodePopup.cancel(); myNodePopup = null; @@ -535,6 +539,7 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup } void hideHint() { + cancelPopup(); if (myHint != null) { myHint.hide(); myHint = null; @@ -612,15 +617,18 @@ public class NavBarPanel extends OpaquePanel.List implements DataProvider, Popup @Nullable @SuppressWarnings({"unchecked"}) T getSelectedElement(Class klass) { - Object selectedValue1 = myModel.getSelectedValue(); - if (selectedValue1 == null) { + Object value = null; + if (myNodeHint != null) { + value = myNodeHint.getSelectedValue(); + } + if (value == null) value = myModel.getSelectedValue(); + if (value == null) { final int modelSize = myModel.size(); if (modelSize > 0) { - selectedValue1 = myModel.getElement(modelSize - 1); + value = myModel.getElement(modelSize - 1); } } - final Object selectedValue = selectedValue1; - return selectedValue != null && klass.isAssignableFrom(selectedValue.getClass()) ? (T)selectedValue : null; + return value != null && klass.isAssignableFrom(value.getClass()) ? (T)value : null; } public Point getBestPopupPosition() { diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPopup.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPopup.java new file mode 100644 index 000000000000..234f037e3d17 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPopup.java @@ -0,0 +1,146 @@ +/* + * 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.actionSystem.DataProvider; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.HintHint; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.LightweightHint; +import com.intellij.ui.ListenerUtil; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.components.JBList; +import com.intellij.util.NotNullFunction; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +/** + * @author Konstantin Bulenkov + */ +public class NavBarPopup extends LightweightHint { + private final NavBarPanel myPanel; + + public NavBarPopup(NavBarPanel panel, Object[] siblings, final int selectedIndex) { + super(createPopupContent(panel, siblings, selectedIndex)); + myPanel = panel; + setFocusRequestor(getComponent()); + setForceShowAsPopup(true); + ListenerUtil.addMouseListener(getComponent(), new MouseAdapter() { + public void mouseReleased(final MouseEvent e) { + if (SystemInfo.isWindows) { + click(e); + } + } + + public void mousePressed(final MouseEvent e) { + if (!SystemInfo.isWindows) { + click(e); + } + } + + private void click(final MouseEvent e) { + if (!e.isConsumed() && e.isPopupTrigger()) { + myPanel.getModel().setSelectedIndex(selectedIndex); + IdeFocusManager.getInstance(myPanel.getProject()).requestFocus(myPanel, true); + myPanel.rightClick(selectedIndex); + e.consume(); + } + } + }); + } + + public void show(final NavBarItem item) { + final RelativePoint point = new RelativePoint(item, new Point(0, item.getHeight())); + final Point p = point.getPoint(myPanel); + show(myPanel, p.x, p.y, myPanel, new HintHint(myPanel, p)); + } + + private static JBList createPopupContent(final NavBarPanel panel, Object[] siblings, int selectedIndex) { + final JBList list = new JBList(siblings); + list.setDataProvider(new DataProvider() { + @Override + public Object getData(@NonNls String dataId) { + return panel.getData(dataId); + } + }); + list.installCellRenderer(new NotNullFunction() { + @NotNull + @Override + public JComponent fun(Object obj) { + return new NavBarItem(panel, obj); + } + }); + list.setBorder(IdeBorderFactory.createEmptyBorder(5,5,5,5)); + list.setSelectedIndex(selectedIndex); + list.registerKeyboardAction(createMoveAction(panel, -1), KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), JComponent.WHEN_FOCUSED); + list.registerKeyboardAction(createMoveAction(panel, 1), KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), JComponent.WHEN_FOCUSED); + + list.addFocusListener(new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + panel.cancelPopup(); + } + }); + + return list; + } + + public Object getSelectedValue() { + return ((JBList)getComponent()).getSelectedValue(); + } + + private static Action createMoveAction(final NavBarPanel panel, final int direction) { + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + panel.cancelPopup(); + panel.shiftFocus(direction); + panel.restorePopup(); + } + }; + } + + private static class CancelNavBarPopup extends AbstractAction implements FocusListener { + private final NavBarPanel myPanel; + + private CancelNavBarPopup(NavBarPanel panel) { + myPanel = panel; + } + + @Override + public void actionPerformed(ActionEvent e) { + cancelPopup(); + } + + @Override + public void focusGained(FocusEvent e) { + } + + @Override + public void focusLost(FocusEvent e) { + cancelPopup(); + } + + private void cancelPopup() { + myPanel.cancelPopup(); + } + } +} diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 4703a5999a24..63bf0feab4bc 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -116,5 +116,6 @@ caches.indexerThreadsCount=-1 vcs.show.history.numbers=true navbar.updateMergeTime=250 navbar.userActivityMergeTime=500 +navbar.newpopup=false inspectionGadgets.telemetry.enabled=false