From 745e2ce402b94620abb8bd12d80194a365a16d95 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 24 Apr 2012 11:59:16 +0400 Subject: [PATCH] IDEA-83733 project panel does not scroll to the current source file when it is opened --- .../src/com/package1/Class1.java | 30 ++++++ .../projectView/NavigateFromSourceTest.java | 38 +++++++- .../ide/impl/ProjectViewSelectInTarget.java | 10 +- .../intellij/ide/projectView/ProjectView.java | 2 + .../ide/projectView/impl/ProjectViewImpl.java | 33 ++++--- .../impl/ToolWindowHeadlessManagerImpl.java | 91 ++++++++++++++----- .../wm/impl/ToolWindowManagerImpl.java | 24 +++-- 7 files changed, 179 insertions(+), 49 deletions(-) create mode 100644 java/java-tests/testData/projectView/autoscrollFromSourceOnOpening/src/com/package1/Class1.java diff --git a/java/java-tests/testData/projectView/autoscrollFromSourceOnOpening/src/com/package1/Class1.java b/java/java-tests/testData/projectView/autoscrollFromSourceOnOpening/src/com/package1/Class1.java new file mode 100644 index 000000000000..54ff9da26b1b --- /dev/null +++ b/java/java-tests/testData/projectView/autoscrollFromSourceOnOpening/src/com/package1/Class1.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2012 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.package1; + +public class Class1 { + private boolean myField1; + public boolean myField2; + + public int getValue(){ + return 0; + } + + public class InnerClass{ + public int myInnerClassField; + } + +} diff --git a/java/java-tests/testSrc/com/intellij/projectView/NavigateFromSourceTest.java b/java/java-tests/testSrc/com/intellij/projectView/NavigateFromSourceTest.java index 14d321dc15c3..75e34223b6c2 100644 --- a/java/java-tests/testSrc/com/intellij/projectView/NavigateFromSourceTest.java +++ b/java/java-tests/testSrc/com/intellij/projectView/NavigateFromSourceTest.java @@ -31,12 +31,20 @@ */ package com.intellij.projectView; +import com.intellij.ide.DataManager; +import com.intellij.ide.projectView.ProjectView; import com.intellij.ide.projectView.impl.AbstractProjectViewPSIPane; +import com.intellij.ide.projectView.impl.ProjectViewImpl; +import com.intellij.ide.projectView.impl.ProjectViewPane; +import com.intellij.ide.projectView.impl.ProjectViewToolWindowFactory; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.JavaDirectoryService; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiJavaFile; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.psi.*; import com.intellij.testFramework.PlatformTestUtil; import javax.swing.*; @@ -92,6 +100,28 @@ public class NavigateFromSourceTest extends BaseProjectViewTestCase { doTestMultipleSelection(pane, ((PsiJavaFile)containingFile).getClasses()[0]); } + public void testAutoscrollFromSourceOnOpening() throws Exception { + final PsiClass[] classes = JavaDirectoryService.getInstance().getClasses(getPackageDirectory()); + PsiClass psiClass = classes[0]; + + FileEditorManager.getInstance(getProject()).openFile(psiClass.getContainingFile().getVirtualFile(), true); + + ProjectView projectView = ProjectView.getInstance(getProject()); + + ((ProjectViewImpl)projectView).setAutoscrollFromSource(true, ProjectViewPane.ID); + + ToolWindow toolWindow = ToolWindowManager.getInstance(getProject()).getToolWindow(ToolWindowId.PROJECT_VIEW); + + new ProjectViewToolWindowFactory().createToolWindowContent(getProject(), toolWindow); + + projectView.changeView(ProjectViewPane.ID); + + JComponent component = ((ProjectViewImpl)projectView).getComponent(); + DataContext context = DataManager.getInstance().getDataContext(component); + PsiElement element = LangDataKeys.PSI_ELEMENT.getData(context); + assertEquals("Class1.java", ((PsiJavaFile)element).getName()); + } + private static void doTestMultipleSelection(final AbstractProjectViewPSIPane pane, final PsiClass psiClass) { JTree tree = pane.getTree(); int rowCount = tree.getRowCount(); diff --git a/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInTarget.java b/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInTarget.java index edd31c429120..c2f4b8194c62 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInTarget.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInTarget.java @@ -23,6 +23,8 @@ import com.intellij.ide.projectView.ProjectView; import com.intellij.ide.projectView.SelectableTreeStructureProvider; import com.intellij.ide.projectView.TreeStructureProvider; import com.intellij.ide.projectView.impl.AbstractProjectViewPane; +import com.intellij.ide.projectView.impl.ProjectViewPane; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; @@ -62,7 +64,13 @@ public abstract class ProjectViewSelectInTarget extends SelectInTargetPsiWrapper final ProjectView projectView = ProjectView.getInstance(project); - ToolWindowManager windowManager=ToolWindowManager.getInstance(project); + if (ApplicationManager.getApplication().isUnitTestMode()) { + AbstractProjectViewPane pane = projectView.getProjectViewPaneById(ProjectViewPane.ID); + pane.select(toSelect, virtualFile, requestFocus); + return result; + } + + ToolWindowManager windowManager = ToolWindowManager.getInstance(project); final ToolWindow projectViewToolWindow = windowManager.getToolWindow(ToolWindowId.PROJECT_VIEW); final Runnable runnable = new Runnable() { public void run() { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectView.java b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectView.java index 2381d16795e2..cad0cf728c9a 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectView.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectView.java @@ -23,6 +23,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -35,6 +36,7 @@ public abstract class ProjectView { public abstract ActionCallback selectCB(Object element, VirtualFile file, boolean requestFocus); + @Nullable public abstract PsiElement getParentOfCurrentSelection(); // show pane identified by id using default(or currently selected) subId diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 9b63a06d17bc..46a08712b526 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -530,21 +530,15 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo if (toolWindow != null) { myContentManager = toolWindow.getContentManager(); - toolWindow.setContentUiType(ToolWindowContentUiType.getInstance("combo"), null); - ((ToolWindowEx)toolWindow).setAdditionalGearActions(myActionGroup); - toolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true"); + if (!ApplicationManager.getApplication().isUnitTestMode()) { + toolWindow.setContentUiType(ToolWindowContentUiType.getInstance("combo"), null); + ((ToolWindowEx)toolWindow).setAdditionalGearActions(myActionGroup); + toolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true"); + } } else { final ContentFactory contentFactory = ServiceManager.getService(ContentFactory.class); myContentManager = contentFactory.createContentManager(false, myProject); } - myContentManager.addContentManagerListener(new ContentManagerAdapter() { - @Override - public void selectionChanged(ContentManagerEvent event) { - if (event.getOperation() == ContentManagerEvent.ContentOperation.add) { - viewSelectionChanged(); - } - } - }); GuiUtils.replaceJSplitPaneWithIDEASplitter(myPanel); SwingUtilities.invokeLater(new Runnable() { @@ -558,6 +552,15 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo } isInitialized = true; doAddUninitializedPanes(); + + myContentManager.addContentManagerListener(new ContentManagerAdapter() { + @Override + public void selectionChanged(ContentManagerEvent event) { + if (event.getOperation() == ContentManagerEvent.ContentOperation.add) { + viewSelectionChanged(); + } + } + }); } private void ensurePanesLoaded() { @@ -590,6 +593,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo if (newPane == null) return false; newPane.setSubId(subId); showPane(newPane); + myAutoScrollFromSourceHandler.scrollFromSource(); return true; } @@ -919,6 +923,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo super(new BorderLayout()); } + @Nullable private Object getSelectedNodeElement() { final AbstractProjectViewPane currentProjectViewPane = getCurrentProjectViewPane(); if (currentProjectViewPane == null) { // can happen if not initialized yet @@ -962,7 +967,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo if (psiElements == null) return null; Set files = new LinkedHashSet(); for (PsiElement element : psiElements) { - final VirtualFile virtualFile = PsiUtilBase.getVirtualFile(element); + final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element); if (virtualFile != null) { files.add(virtualFile); } @@ -1061,6 +1066,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo return null; } + @Nullable private LibraryOrderEntry getSelectedLibrary() { final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); DefaultMutableTreeNode node = viewPane != null ? viewPane.getSelectedNode() : null; @@ -1154,6 +1160,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo } } + @Nullable private Module moduleByContentRoot(VirtualFile file) { if (ProjectRootsUtil.isModuleContentRoot(file, myProject)) { Module module = ProjectRootManager.getInstance(myProject).getFileIndex().getModuleForFile(file); @@ -1363,7 +1370,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo return getPaneOptionValue(myAutoscrollFromSource, paneId, ourAutoscrollFromSourceDefaults); } - private void setAutoscrollFromSource(boolean autoscrollMode, String paneId) { + public void setAutoscrollFromSource(boolean autoscrollMode, String paneId) { setPaneOption(myAutoscrollFromSource, autoscrollMode, paneId, false); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java index e81eaf4151d0..b4814b14ed62 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java @@ -23,15 +23,17 @@ package com.intellij.openapi.wm.impl; import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.util.ActionCallback; -import com.intellij.openapi.util.ActiveRunnable; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.*; +import com.intellij.openapi.wm.ex.ToolWindowEx; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; import com.intellij.openapi.wm.ex.ToolWindowManagerListener; import com.intellij.ui.content.Content; @@ -47,8 +49,10 @@ import javax.swing.*; import javax.swing.event.HyperlinkListener; import java.awt.*; import java.awt.event.InputEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; @SuppressWarnings({"ConstantConditions"}) @@ -57,7 +61,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public void notifyByBalloon(@NotNull final String toolWindowId, @NotNull final MessageType type, @NotNull final String htmlBody) { } - public static final ToolWindow HEADLESS_WINDOW = new ToolWindow(){ + public static final ToolWindow HEADLESS_WINDOW = new ToolWindowEx(){ public boolean isActive() { return false; } @@ -177,17 +181,61 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public ActionCallback getActivation() { return new ActionCallback.Done(); } + + @Override + public void removePropertyChangeListener(PropertyChangeListener l) { + } + + @Override + public ToolWindowType getInternalType() { + return ToolWindowType.DOCKED; + } + + @Override + public void stretchWidth(int value) { + } + + @Override + public void stretchHeight(int value) { + } + + @Override + public InternalDecorator getDecorator() { + return null; + } + + @Override + public void setAdditionalGearActions(ActionGroup additionalGearActions) { + } + + @Override + public void setTitleActions(AnAction... actions) { + } + + @Override + public void setUseLastFocusedOnActivation(boolean focus) { + } + + @Override + public boolean isUseLastFocusedOnActivation() { + return false; + } }; @NonNls private static final ContentManager MOCK_CONTENT_MANAGER = new ContentManager() { + private final ArrayList myContents = new ArrayList(); + private Content mySelected; + @Override public ActionCallback getReady(@NotNull Object requestor) { return new ActionCallback.Done(); } public void addContent(@NotNull final Content content) { } - public void addContent(@NotNull Content content, int order) { } + public void addContent(@NotNull Content content, int order) { + myContents.add(order, content); + } public void addContent(@NotNull final Content content, final Object constraints) { } public void addContentManagerListener(@NotNull final ContentManagerListener l) { } public void addDataProvider(@NotNull final DataProvider provider) { } @@ -215,15 +263,24 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public Content getContent(final int index) { return null; } public int getContentCount() { return 0; } @NotNull - public Content[] getContents() { return new Content[0]; } + public Content[] getContents() { return myContents.toArray(new Content[myContents.size()]); } public int getIndexOfContent(final Content content) { return -1; } @Nullable - public Content getSelectedContent() { return null; } + public Content getSelectedContent() { return mySelected; } @NotNull public Content[] getSelectedContents() { return new Content[0]; } public boolean isSelected(@NotNull final Content content) { return false; } - public void removeAllContents(final boolean dispose) { } - public boolean removeContent(@NotNull final Content content, final boolean dispose) { return false; } + public void removeAllContents(final boolean dispose) { + for (Iterator iterator = myContents.iterator(); iterator.hasNext(); ) { + Content content = iterator.next(); + Disposer.dispose(content); + iterator.remove(); + } + } + public boolean removeContent(@NotNull final Content content, final boolean dispose) { + Disposer.dispose(content); + return myContents.remove(content); + } public ActionCallback removeContent(@NotNull Content content, boolean dispose, boolean trackFocus, boolean implicitFocus) { return new ActionCallback.Done(); @@ -233,7 +290,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public void removeFromSelection(@NotNull final Content content) { } public ActionCallback selectNextContent() { return new ActionCallback.Done();} public ActionCallback selectPreviousContent() { return new ActionCallback.Done();} - public void setSelectedContent(@NotNull final Content content) { } + public void setSelectedContent(@NotNull final Content content) { mySelected = content; } public ActionCallback setSelectedContentCB(@NotNull Content content) { return new ActionCallback.Done(); } public void setSelectedContent(@NotNull final Content content, final boolean requestFocus) { } public ActionCallback setSelectedContentCB(@NotNull final Content content, final boolean requestFocus) { return new ActionCallback.Done();} @@ -253,7 +310,9 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { return new ActionCallback.Done(); } - public void dispose() {} + public void dispose() { + removeAllContents(true); + } public boolean isDisposed() { return false; @@ -318,18 +377,6 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { return false; } - public ActionCallback requestFocus(final Component c, final boolean forced) { - return new ActionCallback.Done(); - } - - public ActionCallback requestFocus(final ActiveRunnable command, final boolean forced) { - return new ActionCallback.Done(); - } - - public JComponent getFocusTargetFor(final JComponent comp) { - return null; - } - public String[] getToolWindowIds() { return ArrayUtil.EMPTY_STRING_ARRAY; } @@ -350,7 +397,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { } @Override - public void notifyByBalloon(@NotNull final String toolWindowId, final MessageType type, @NotNull final String text, @Nullable final Icon icon, + public void notifyByBalloon(@NotNull final String toolWindowId, @NotNull final MessageType type, @NotNull final String text, @Nullable final Icon icon, @Nullable final HyperlinkListener listener) { } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index 02ede71f0342..416e46a6c719 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -491,18 +491,24 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements final ActionCallback activation = toolWindow.setActivation(new ActionCallback()); - UiNotifyConnector.doWhenFirstShown(label, new Runnable() { + final DumbAwareRunnable runnable = new DumbAwareRunnable() { public void run() { - ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() { - public void run() { - if (toolWindow.isDisposed()) return; + if (toolWindow.isDisposed()) return; - toolWindow.ensureContentInitialized(); - activation.setDone(); - } - }); + toolWindow.ensureContentInitialized(); + activation.setDone(); } - }); + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + runnable.run(); + } + else { + UiNotifyConnector.doWhenFirstShown(label, new Runnable() { + public void run() { + ApplicationManager.getApplication().invokeLater(runnable); + } + }); + } } public void projectClosed() {