IDEA-79278 Autoscroll to source doesn't preserve file position
authorKonstantin Bulenkov <kb@jetbrains.com>
Thu, 11 Jul 2013 19:15:58 +0000 (21:15 +0200)
committerKonstantin Bulenkov <kb@jetbrains.com>
Thu, 11 Jul 2013 19:18:26 +0000 (21:18 +0200)
IDEA-75349 Switching editor tabs with Structure pane open causes editor to jump to the top of file

platform/core-api/src/com/intellij/pom/AutoScrollFriendlyNavigatable.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java
platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/AbstractPsiBasedNode.java
platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.java
platform/platform-api/src/com/intellij/util/OpenSourceUtil.java

diff --git a/platform/core-api/src/com/intellij/pom/AutoScrollFriendlyNavigatable.java b/platform/core-api/src/com/intellij/pom/AutoScrollFriendlyNavigatable.java
new file mode 100644 (file)
index 0000000..e341aec
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2013 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.pom;
+
+/**
+ * Navigatable that saves cursor position in the editor when navigating to
+ * already opened documents
+ *
+ * @author Konstantin Bulenkov
+ */
+public interface AutoScrollFriendlyNavigatable extends Navigatable {
+  void navigate(boolean requestFocus, boolean tryToKeepState);
+}
index 82ed3a5e27d97f65ace5b7549d13ac17530e4a6c..0025cdfdc236a9f9ce2b53621063f9ecb8b08a12 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2013 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.
@@ -122,32 +122,36 @@ public final class NavigationUtil {
   }
 
   public static boolean activateFileWithPsiElement(@NotNull PsiElement elt, boolean searchForOpen) {
+    return openFileWithPsiElement(elt, searchForOpen, true);
+  }
+
+  public static boolean openFileWithPsiElement(PsiElement element, boolean searchForOpen, boolean requestFocus) {
     boolean openAsNative = false;
-    if (elt instanceof PsiFile) {
-      VirtualFile virtualFile = ((PsiFile)elt).getVirtualFile();
+    if (element instanceof PsiFile) {
+      VirtualFile virtualFile = ((PsiFile)element).getVirtualFile();
       if (virtualFile != null) {
         openAsNative = ElementBase.isNativeFileType(virtualFile.getFileType());
       }
     }
 
     if (searchForOpen) {
-      elt.putUserData(FileEditorManager.USE_CURRENT_WINDOW, null);
+      element.putUserData(FileEditorManager.USE_CURRENT_WINDOW, null);
     }
     else {
-      elt.putUserData(FileEditorManager.USE_CURRENT_WINDOW, true);
+      element.putUserData(FileEditorManager.USE_CURRENT_WINDOW, true);
     }
 
-    if (openAsNative || !activatePsiElementIfOpen(elt, searchForOpen)) {
-      ((NavigationItem)elt).navigate(true);
+    if (openAsNative || !activatePsiElementIfOpen(element, searchForOpen, requestFocus)) {
+      ((NavigationItem)element).navigate(requestFocus);
       return true;
     }
 
-    elt.putUserData(FileEditorManager.USE_CURRENT_WINDOW, null);
+    element.putUserData(FileEditorManager.USE_CURRENT_WINDOW, null);
     return false;
   }
 
 
-  private static boolean activatePsiElementIfOpen(@NotNull PsiElement elt, boolean searchForOpen) {
+  private static boolean activatePsiElementIfOpen(@NotNull PsiElement elt, boolean searchForOpen, boolean requestFocus) {
     if (!elt.isValid()) return false;
     elt = elt.getNavigationElement();
     final PsiFile file = elt.getContainingFile();
@@ -160,7 +164,7 @@ public final class NavigationUtil {
 
     final FileEditorManager fem = FileEditorManager.getInstance(elt.getProject());
     if (!fem.isFileOpen(vFile)) {
-      fem.openFile(vFile, true, searchForOpen);
+      fem.openFile(vFile, requestFocus, searchForOpen);
     }
 
     final TextRange range = elt.getTextRange();
@@ -174,7 +178,7 @@ public final class NavigationUtil {
 
         if (range.containsOffset(offset)) {
           // select the file
-          fem.openFile(vFile, true, searchForOpen);
+          fem.openFile(vFile, requestFocus, searchForOpen);
           return true;
         }
       }
index e8d0ec6852b9423b70961bef2258ef654975eb72..0ed502a6c8b063dd267dd0179f84c092b684e3a8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2013 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.
@@ -35,6 +35,7 @@ import com.intellij.openapi.util.Iconable;
 import com.intellij.openapi.vcs.FileStatus;
 import com.intellij.openapi.vcs.FileStatusManager;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.pom.AutoScrollFriendlyNavigatable;
 import com.intellij.psi.PsiDirectory;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
@@ -52,7 +53,7 @@ import java.util.Collections;
  * method that extract PsiElement from Value.
  * @param <Value> Value of node descriptor
  */
-public abstract class AbstractPsiBasedNode<Value> extends ProjectViewNode<Value> implements ValidateableNode {
+public abstract class AbstractPsiBasedNode<Value> extends ProjectViewNode<Value> implements ValidateableNode, AutoScrollFriendlyNavigatable {
   private static final Logger LOG = Logger.getInstance(AbstractPsiBasedNode.class.getName());
 
   protected AbstractPsiBasedNode(final Project project,
@@ -200,10 +201,10 @@ public abstract class AbstractPsiBasedNode<Value> extends ProjectViewNode<Value>
   }
 
   @Override
-  public void navigate(boolean requestFocus) {
+  public void navigate(boolean requestFocus, boolean tryToKeepState) {
     if (canNavigate()) {
-      if (requestFocus) {
-        NavigationUtil.activateFileWithPsiElement(extractPsiFromValue(), true);
+      if (requestFocus || tryToKeepState) {
+        NavigationUtil.openFileWithPsiElement(extractPsiFromValue(), requestFocus, requestFocus);
       }
       else {
         getNavigationItem().navigate(requestFocus);
@@ -212,6 +213,11 @@ public abstract class AbstractPsiBasedNode<Value> extends ProjectViewNode<Value>
   }
 
   @Override
+  public void navigate(boolean requestFocus) {
+    navigate(requestFocus, false);
+  }
+
+  @Override
   public boolean canNavigate() {
     final NavigationItem item = getNavigationItem();
     return item != null && item.canNavigate();
index 9c66a0d9bb57c8d8b02eb47684658a5ac2b438ad..b7a152f53be112c14c758c4639d08dd6574b05ab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2013 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.
@@ -207,7 +207,7 @@ public abstract class AutoScrollToSourceHandler {
             if (!navigatable.canNavigateToSource()) return;
           }
         }
-        OpenSourceUtil.openSourcesFrom(context, false);
+        OpenSourceUtil.navigate(false, true, navigatables);
       }
     });
   }
index f85f2babbe79065c0b6843997bca929af793da36..d96813fd1550970499b79b797f355421dd1341aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2013 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.
@@ -18,6 +18,7 @@ package com.intellij.util;
 import com.intellij.openapi.actionSystem.DataContext;
 import com.intellij.openapi.actionSystem.DataProvider;
 import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.pom.AutoScrollFriendlyNavigatable;
 import com.intellij.pom.Navigatable;
 
 public class OpenSourceUtil {
@@ -52,4 +53,17 @@ public class OpenSourceUtil {
       }
     }
   }
+
+  public static void navigate(final boolean requestFocus, final boolean tryNotToScroll, final Navigatable...navigatables) {
+    if (navigatables == null) return;
+    for (Navigatable navigatable : navigatables) {
+      if (navigatable.canNavigate()) {
+        if (tryNotToScroll && navigatable instanceof AutoScrollFriendlyNavigatable) {
+          ((AutoScrollFriendlyNavigatable)navigatable).navigate(requestFocus, true);
+        } else {
+          navigatable.navigate(requestFocus);
+        }
+      }
+    }
+  }
 }