com.intellij.ide.actions.ShowFilePathAction.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.ide.actions.ShowFilePathAction.java

Source

/*
 * Copyright 2000-2014 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.actions;

import com.intellij.CommonBundle;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.util.ExecUtil;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeBundle;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.AtomicNotNullLazyValue;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.ArchiveFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.openapi.vfs.util.ArchiveVfsUtil;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Consumer;
import com.intellij.util.ui.EmptyIcon;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ShowFilePathAction extends AnAction {
    private static final Logger LOG = Logger.getInstance("#com.intellij.ide.actions.ShowFilePathAction");

    public static final NotificationListener FILE_SELECTING_LISTENER = new NotificationListener.Adapter() {
        @Override
        protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
            URL url = e.getURL();
            if (url != null)
                openFile(new File(url.getPath()));
            notification.expire();
        }
    };

    private static NotNullLazyValue<Boolean> canUseNautilus = new NotNullLazyValue<Boolean>() {
        @NotNull
        @Override
        protected Boolean compute() {
            if (!SystemInfo.isUnix || !SystemInfo.hasXdgMime() || !new File("/usr/bin/nautilus").canExecute()) {
                return false;
            }

            String appName = ExecUtil.execAndReadLine("xdg-mime", "query", "default", "inode/directory");
            if (appName == null || !appName.matches("nautilus.*\\.desktop"))
                return false;

            String version = ExecUtil.execAndReadLine("nautilus", "--version");
            if (version == null)
                return false;

            Matcher m = Pattern.compile("GNOME nautilus ([0-9.]+)").matcher(version);
            return m.find() && StringUtil.compareVersionNumbers(m.group(1), "3") >= 0;
        }
    };

    private static final NotNullLazyValue<String> fileManagerName = new AtomicNotNullLazyValue<String>() {
        @NotNull
        @Override
        protected String compute() {
            if (SystemInfo.isMac)
                return "Finder";
            if (SystemInfo.isWindows)
                return "Explorer";
            if (SystemInfo.isUnix && SystemInfo.hasXdgMime()) {
                String name = getUnixFileManagerName();
                if (name != null)
                    return name;
            }
            return "File Manager";
        }
    };

    @Nullable
    private static String getUnixFileManagerName() {
        String appName = ExecUtil.execAndReadLine("xdg-mime", "query", "default", "inode/directory");
        if (appName == null || !appName.matches(".+\\.desktop"))
            return null;

        String dirs = System.getenv("XDG_DATA_DIRS");
        if (dirs == null)
            return null;

        try {
            for (String dir : dirs.split(File.pathSeparator)) {
                File appFile = new File(dir, "applications/" + appName);
                if (appFile.exists()) {
                    BufferedReader reader = new BufferedReader(new FileReader(appFile));
                    try {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            if (line.startsWith("Name=")) {
                                return line.substring(5);
                            }
                        }
                    } finally {
                        reader.close();
                    }
                }
            }
        } catch (IOException e) {
            LOG.info("Cannot read desktop file", e);
        }

        return null;
    }

    @Override
    public void update(AnActionEvent e) {
        if (SystemInfo.isMac || !isSupported()) {
            e.getPresentation().setVisible(false);
            return;
        }
        e.getPresentation().setEnabled(getFile(e) != null);
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        show(getFile(e), new ShowAction() {
            @Override
            public void show(final ListPopup popup) {
                DataManager.getInstance().getDataContextFromFocus().doWhenDone(new Consumer<DataContext>() {
                    @Override
                    public void consume(DataContext context) {
                        popup.showInBestPositionFor(context);
                    }
                });
            }
        });
    }

    public static void show(final VirtualFile file, final MouseEvent e) {
        show(file, new ShowAction() {
            @Override
            public void show(final ListPopup popup) {
                if (e.getComponent().isShowing()) {
                    popup.show(new RelativePoint(e));
                }
            }
        });
    }

    public static void show(final VirtualFile file, final ShowAction show) {
        if (!isSupported())
            return;

        final ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
        final ArrayList<String> fileUrls = new ArrayList<String>();
        VirtualFile eachParent = file;
        while (eachParent != null) {
            final int index = files.size() == 0 ? 0 : files.size();
            files.add(index, eachParent);
            fileUrls.add(index, getPresentableUrl(eachParent));
            if (eachParent.getParent() == null && eachParent.getFileSystem() instanceof ArchiveFileSystem) {
                eachParent = ArchiveVfsUtil.getVirtualFileForArchive(eachParent);
                if (eachParent == null)
                    break;
            }
            eachParent = eachParent.getParent();
        }

        final ArrayList<Icon> icons = new ArrayList<Icon>();
        ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
            @Override
            public void run() {
                for (String each : fileUrls) {
                    final File ioFile = new File(each);
                    Icon eachIcon;
                    if (ioFile.exists()) {
                        eachIcon = FileSystemView.getFileSystemView().getSystemIcon(ioFile);
                    } else {
                        eachIcon = EmptyIcon.ICON_16;
                    }

                    icons.add(eachIcon);
                }

                ApplicationManager.getApplication().invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        show.show(createPopup(files, icons));
                    }
                });
            }
        });
    }

    private static String getPresentableUrl(final VirtualFile eachParent) {
        String url = eachParent.getPresentableUrl();
        if (eachParent.getParent() == null && SystemInfo.isWindows) {
            url += "\\";
        }
        return url;
    }

    interface ShowAction {
        void show(ListPopup popup);
    }

    private static ListPopup createPopup(final ArrayList<VirtualFile> files, final ArrayList<Icon> icons) {
        final BaseListPopupStep<VirtualFile> step = new BaseListPopupStep<VirtualFile>("File Path", files, icons) {
            @NotNull
            @Override
            public String getTextFor(final VirtualFile value) {
                return value.getPresentableName();
            }

            @Override
            public PopupStep onChosen(final VirtualFile selectedValue, final boolean finalChoice) {
                final File selectedFile = new File(getPresentableUrl(selectedValue));
                if (selectedFile.exists()) {
                    ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
                        @Override
                        public void run() {
                            openFile(selectedFile);
                        }
                    });
                }
                return FINAL_CHOICE;
            }
        };

        return JBPopupFactory.getInstance().createListPopup(step);
    }

    public static boolean isSupported() {
        return SystemInfo.isWindows
                || Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN)
                || SystemInfo.hasXdgOpen() || canUseNautilus.getValue();
    }

    @NotNull
    public static String getFileManagerName() {
        return fileManagerName.getValue();
    }

    /**
     * Shows system file manager with given file's parent directory open and the file highlighted in it<br/>
     * (note that not all platforms support highlighting).
     *
     * @param file a file or directory to show and highlight in a file manager.
     */
    public static void openFile(@NotNull File file) {
        if (!file.exists())
            return;
        file = file.getAbsoluteFile();
        File parent = file.getParentFile();
        if (parent == null) {
            return;
        }
        try {
            doOpen(parent, file);
        } catch (Exception e) {
            LOG.warn(e);
        }
    }

    /**
     * Shows system file manager with given directory open in it.
     *
     * @param directory a directory to show in a file manager.
     */
    @SuppressWarnings("UnusedDeclaration")
    public static void openDirectory(@NotNull final File directory) {
        if (!directory.isDirectory())
            return;
        try {
            doOpen(directory, null);
        } catch (Exception e) {
            LOG.warn(e);
        }
    }

    private static void doOpen(@NotNull File dir, @Nullable File toSelect) throws IOException, ExecutionException {
        dir = new File(FileUtil.toCanonicalPath(dir.getPath()));
        toSelect = toSelect == null ? null : new File(FileUtil.toCanonicalPath(toSelect.getPath()));

        if (SystemInfo.isWindows) {
            String cmd;
            if (toSelect != null) {
                cmd = "explorer /select," + toSelect.getAbsolutePath();
            } else {
                cmd = "explorer /root," + dir.getAbsolutePath();
            }
            // no quoting/escaping is needed
            Runtime.getRuntime().exec(cmd);
            return;
        }

        if (SystemInfo.isMac) {
            if (toSelect != null) {
                final String script = String.format("tell application \"Finder\"\n"
                        + "\treveal {\"%s\"} as POSIX file\n" + "\tactivate\n" + "end tell",
                        toSelect.getAbsolutePath());
                new GeneralCommandLine(ExecUtil.getOsascriptPath(), "-e", script).createProcess();
            } else {
                new GeneralCommandLine("open", dir.getAbsolutePath()).createProcess();
            }
            return;
        }

        if (canUseNautilus.getValue()) {
            new GeneralCommandLine("nautilus", (toSelect != null ? toSelect : dir).getAbsolutePath())
                    .createProcess();
            return;
        }

        String path = dir.getAbsolutePath();
        if (SystemInfo.hasXdgOpen()) {
            new GeneralCommandLine("/usr/bin/xdg-open", path).createProcess();
        } else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) {
            Desktop.getDesktop().open(new File(path));
        } else {
            Messages.showErrorDialog("This action isn't supported on the current platform", "Cannot Open File");
        }
    }

    @Nullable
    private static VirtualFile getFile(final AnActionEvent e) {
        return CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext());
    }

    public static Boolean showDialog(Project project, String message, String title, File file) {
        final Boolean[] ref = new Boolean[1];
        final DialogWrapper.DoNotAskOption option = new DialogWrapper.DoNotAskOption() {
            @Override
            public boolean isToBeShown() {
                return true;
            }

            @Override
            public void setToBeShown(boolean value, int exitCode) {
                if (!value) {
                    if (exitCode == 0) {
                        // yes
                        ref[0] = true;
                    } else {
                        ref[0] = false;
                    }
                }
            }

            @Override
            public boolean canBeHidden() {
                return true;
            }

            @Override
            public boolean shouldSaveOptionsOnCancel() {
                return true;
            }

            @NotNull
            @Override
            public String getDoNotShowMessage() {
                return CommonBundle.message("dialog.options.do.not.ask");
            }
        };
        showDialog(project, message, title, file, option);
        return ref[0];
    }

    public static void showDialog(Project project, String message, String title, File file,
            DialogWrapper.DoNotAskOption option) {
        if (Messages.showOkCancelDialog(project, message, title, RevealFileAction.getActionName(),
                IdeBundle.message("action.close"), Messages.getInformationIcon(), option) == Messages.OK) {
            openFile(file);
        }
    }

    @Nullable
    public static VirtualFile findLocalFile(@Nullable VirtualFile file) {
        if (file == null)
            return null;

        if (file.isInLocalFileSystem()) {
            return file;
        }

        VirtualFileSystem fs = file.getFileSystem();
        if (fs instanceof ArchiveFileSystem && file.getParent() == null) {
            return ((ArchiveFileSystem) fs).getLocalVirtualFileFor(file);
        }

        return null;
    }
}