cleanup (inspection "Java | Class structure | Utility class is not 'final'")
[idea/community.git] / platform / platform-api / src / com / intellij / util / OpenSourceUtil.java
index d96813fd1550970499b79b797f355421dd1341aa..630b71f2058d0bf4372a11b64de2b3cd95402f0d 100644 (file)
-/*
- * 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.
- */
+// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.util;
 
+import com.intellij.openapi.actionSystem.CommonDataKeys;
 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;
+import com.intellij.pom.StatePreservingNavigatable;
+import org.jetbrains.annotations.Nullable;
 
-public class OpenSourceUtil {
+import static java.util.Arrays.asList;
+
+public final class OpenSourceUtil {
 
   private OpenSourceUtil() {
   }
 
   public static void openSourcesFrom(DataContext context, boolean requestFocus) {
-    navigate(requestFocus, PlatformDataKeys.NAVIGATABLE_ARRAY.getData(context));
+    navigate(requestFocus, CommonDataKeys.NAVIGATABLE_ARRAY.getData(context));
   }
 
   public static void openSourcesFrom(DataProvider context, boolean requestFocus) {
-    navigate(requestFocus, PlatformDataKeys.NAVIGATABLE_ARRAY.getData(context));
+    navigate(requestFocus, CommonDataKeys.NAVIGATABLE_ARRAY.getData(context));
   }
 
   /**
-   * Equivalent to navigate(true, navigatables)
-   *
-   * @param navigatables elements navigate to
-   * 
-   * @see OpenSourceUtil#navigate(boolean, com.intellij.pom.Navigatable...)  
+   * @return {@code true} if the specified {@code object} is {@link Navigatable} and supports navigation
+   */
+  public static boolean canNavigate(@Nullable Object object) {
+    return object instanceof Navigatable && ((Navigatable)object).canNavigate();
+  }
+
+  /**
+   * @return {@code true} if the specified {@code object} is {@link Navigatable} and supports navigation to source
+   */
+  public static boolean canNavigateToSource(@Nullable Object object) {
+    return object instanceof Navigatable && ((Navigatable)object).canNavigateToSource();
+  }
+
+  /**
+   * Invokes {@link #navigate(boolean, Navigatable...)} that always requests focus.
    */
-  public static void navigate(final Navigatable...navigatables) {
+  public static void navigate(Navigatable @Nullable ... navigatables) {
     navigate(true, navigatables);
   }
 
-  public static void navigate(final boolean requestFocus, final Navigatable...navigatables) {
-    if (navigatables == null) return;
+  /**
+   * Invokes {@link #navigate(boolean, boolean, Navigatable...)} that does not try to preserve a state of a corresponding editor.
+   */
+  public static void navigate(boolean requestFocus, Navigatable @Nullable ... navigatables) {
+    navigate(requestFocus, false, navigatables);
+  }
+
+  /**
+   * Invokes {@link #navigate(boolean, boolean, Iterable)} if at least one navigatable exists
+   */
+  public static void navigate(boolean requestFocus, boolean tryNotToScroll, Navigatable @Nullable ... navigatables) {
+    if (navigatables != null && navigatables.length > 0) navigate(requestFocus, tryNotToScroll, asList(navigatables));
+  }
+
+  /**
+   * Navigates to all available sources or to the first navigatable that represents non-source navigation.
+   *
+   * @param requestFocus   specifies whether a focus should be requested or not
+   * @param tryNotToScroll specifies whether a corresponding editor should preserve its state if it is possible
+   * @param navigatables   an iterable collection of navigatables
+   * @return {@code true} if at least one navigatable was processed, {@code false} otherwise
+   */
+  public static boolean navigate(boolean requestFocus, boolean tryNotToScroll, @Nullable Iterable<? extends Navigatable> navigatables) {
+    if (navigatables == null) return false;
+    Navigatable nonSourceNavigatable = null;
+    boolean alreadyNavigatedToSource = false;
     for (Navigatable navigatable : navigatables) {
-      if (navigatable.canNavigate()) {
-        navigatable.navigate(requestFocus);
+      if (navigateToSource(requestFocus, tryNotToScroll, navigatable)) {
+        alreadyNavigatedToSource = true;
+      }
+      else if (!alreadyNavigatedToSource && nonSourceNavigatable == null && canNavigate(navigatable)) {
+        nonSourceNavigatable = navigatable;
       }
     }
+    if (alreadyNavigatedToSource) return true;
+    if (nonSourceNavigatable == null) return false;
+    nonSourceNavigatable.navigate(requestFocus);
+    return true;
   }
 
-  public static void navigate(final boolean requestFocus, final boolean tryNotToScroll, final Navigatable...navigatables) {
-    if (navigatables == null) return;
+  /**
+   * Navigates to all available sources of the specified navigatables.
+   *
+   * @param requestFocus   specifies whether a focus should be requested or not
+   * @param tryNotToScroll specifies whether a corresponding editor should preserve its state if it is possible
+   * @param navigatables   an iterable collection of navigatables
+   * @return {@code true} if at least one navigatable was processed, {@code false} otherwise
+   */
+  public static boolean navigateToSource(boolean requestFocus, boolean tryNotToScroll, @Nullable Iterable<? extends Navigatable> navigatables) {
+    if (navigatables == null) return false;
+    boolean alreadyNavigatedToSource = false;
     for (Navigatable navigatable : navigatables) {
-      if (navigatable.canNavigate()) {
-        if (tryNotToScroll && navigatable instanceof AutoScrollFriendlyNavigatable) {
-          ((AutoScrollFriendlyNavigatable)navigatable).navigate(requestFocus, true);
-        } else {
-          navigatable.navigate(requestFocus);
-        }
+      if (navigateToSource(requestFocus, tryNotToScroll, navigatable)) {
+        alreadyNavigatedToSource = true;
       }
     }
+    return alreadyNavigatedToSource;
+  }
+
+  /**
+   * Navigates to source of the specified navigatable.
+   *
+   * @param requestFocus   specifies whether a focus should be requested or not
+   * @param tryNotToScroll specifies whether a corresponding editor should preserve its state if it is possible
+   * @return {@code true} if navigation is done, {@code false} otherwise
+   */
+  public static boolean navigateToSource(boolean requestFocus, boolean tryNotToScroll, @Nullable Navigatable navigatable) {
+    if (!canNavigateToSource(navigatable)) return false;
+    if (tryNotToScroll && navigatable instanceof StatePreservingNavigatable) {
+      ((StatePreservingNavigatable)navigatable).navigate(requestFocus, true);
+    }
+    else {
+      navigatable.navigate(requestFocus);
+    }
+    return true;
   }
 }