From 3a90f1a60b81bc9cddbc6e080c653f08d98c9d15 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 1 Mar 2013 15:22:30 +0100 Subject: [PATCH] recent files support --- .../ide/util/PropertiesComponent.java | 6 +- .../ide/util/PropertiesComponentImpl.java | 18 ++- .../fileChooser/ex/FileChooserDialogImpl.java | 103 ++++++++++++++++-- 3 files changed, 118 insertions(+), 9 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ide/util/PropertiesComponent.java b/platform/platform-api/src/com/intellij/ide/util/PropertiesComponent.java index 15065a1c2753..92f1e6b05f10 100644 --- a/platform/platform-api/src/com/intellij/ide/util/PropertiesComponent.java +++ b/platform/platform-api/src/com/intellij/ide/util/PropertiesComponent.java @@ -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,10 @@ public abstract class PropertiesComponent { public abstract void setValue(@NonNls String name, String value); + public abstract String[] getValues(@NonNls String name); + + public abstract void setValues(@NonNls String name, String[] values); + public static PropertiesComponent getInstance(Project project) { return ServiceManager.getService(project, PropertiesComponent.class); } diff --git a/platform/platform-impl/src/com/intellij/ide/util/PropertiesComponentImpl.java b/platform/platform-impl/src/com/intellij/ide/util/PropertiesComponentImpl.java index cb7f05533797..6c25713406bc 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/PropertiesComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/util/PropertiesComponentImpl.java @@ -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. @@ -16,6 +16,7 @@ package com.intellij.ide.util; import com.intellij.openapi.components.*; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.HashMap; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -83,4 +84,19 @@ public class PropertiesComponentImpl extends PropertiesComponent implements Pers public boolean isValueSet(String name) { return myMap.containsKey(name); } + + @Override + public String[] getValues(@NonNls String name) { + final String value = getValue(name); + return value != null ? value.split("\n") : null; + } + + @Override + public void setValues(@NonNls String name, String[] values) { + if (values == null) { + setValue(name, null); + } else { + setValue(name, StringUtil.join(values, "\n")); + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java index df93fe545ef7..cff57a7b6e6c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.fileChooser.ex; +import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; import com.intellij.ide.SaveAndSyncHandlerImpl; import com.intellij.ide.util.PropertiesComponent; @@ -30,19 +31,19 @@ import com.intellij.openapi.fileChooser.impl.FileChooserUtil; 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.util.Disposer; +import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.*; import com.intellij.openapi.wm.IdeFrame; -import com.intellij.ui.ScrollPaneFactory; -import com.intellij.ui.SideBorder; -import com.intellij.ui.UIBundle; +import com.intellij.ui.*; +import com.intellij.ui.components.JBList; import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; +import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; +import com.intellij.util.IconUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.MergingUpdateQueue; @@ -61,12 +62,17 @@ import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; public class FileChooserDialogImpl extends DialogWrapper implements FileChooserDialog, PathChooserDialog, FileLookup { + public static final String RECENT_FILES_KEY = "file.chooser.recent.files"; private final FileChooserDescriptor myChooserDescriptor; protected FileSystemTreeImpl myFileSystemTree; private Project myProject; @@ -153,8 +159,88 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD protected void storeSelection(@Nullable VirtualFile file) { FileChooserUtil.setLastOpenedFile(myProject, file); + if (file != null && file.getFileSystem() instanceof LocalFileSystem) { + saveRecent(file.getPath()); + } + } + protected void saveRecent(String path) { + final List files = new ArrayList(Arrays.asList(getRecentFiles())); + files.remove(path); + files.add(0, path); + while (files.size() > 30) { + files.remove(files.size() - 1); + } + PropertiesComponent.getInstance().setValues(RECENT_FILES_KEY, ArrayUtil.toStringArray(files)); + } + + @NotNull + private String[] getRecentFiles() { + final String[] recent = PropertiesComponent.getInstance().getValues(RECENT_FILES_KEY); + if (recent != null) { + if (recent.length > 0 && myPathTextField.getField().getText().replace('\\', '/').equals(recent[0])) { + final String[] pathes = new String[recent.length - 1]; + System.arraycopy(recent, 1, pathes, 0, recent.length - 1); + return pathes; + } + return recent; + } + return ArrayUtil.EMPTY_STRING_ARRAY; + } + + + protected JComponent createHistoryButton() { + JLabel label = new JLabel(AllIcons.Actions.Get); + label.setToolTipText("Recent files"); + new ClickListener() { + @Override + public boolean onClick(MouseEvent event, int clickCount) { + showRecentFilesPopup(); + return true; + } + }.installOn(label); + myPathTextField.getField().addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_DOWN) { + showRecentFilesPopup(); + e.consume(); + } + } + }); + return label; + } + + private void showRecentFilesPopup() { + final JBList files = new JBList(getRecentFiles()) { + @Override + public Dimension getPreferredSize() { + return new Dimension(myPathTextField.getField().getWidth(), super.getPreferredSize().height); + } + }; + files.setCellRenderer(new ColoredListCellRenderer() { + @Override + protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { + final String path = value.toString(); + append(path); + final VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(new File(path)); + if (file != null) { + setIcon(IconUtil.getIcon(file, Iconable.ICON_FLAG_READ_STATUS, null)); + } + } + }); + JBPopupFactory.getInstance() + .createListPopupBuilder(files) + .setItemChoosenCallback(new Runnable() { + @Override + public void run() { + myPathTextField.getField().setText(files.getSelectedValue().toString()); + } + }).createPopup().showUnderneathOf(myPathTextField.getField()); + } + + protected DefaultActionGroup createActionGroup() { registerFileChooserShortcut(IdeActions.ACTION_DELETE, "FileChooser.Delete"); registerFileChooserShortcut(IdeActions.ACTION_SYNCHRONIZE, "FileChooser.Refresh"); @@ -215,6 +301,9 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD }; Disposer.register(myDisposable, myPathTextField); myPathTextFieldWrapper.add(myPathTextField.getField(), BorderLayout.CENTER); + if (getRecentFiles().length > 0) { + myPathTextFieldWrapper.add(createHistoryButton(), BorderLayout.EAST); + } myNorthPanel = new JPanel(new BorderLayout()); myNorthPanel.add(toolbarPanel, BorderLayout.NORTH);