diff --git a/utilities/src/org/netbeans/modules/openfile/OpenFile.java b/utilities/src/org/netbeans/modules/openfile/OpenFile.java --- a/utilities/src/org/netbeans/modules/openfile/OpenFile.java +++ b/utilities/src/org/netbeans/modules/openfile/OpenFile.java @@ -43,8 +43,6 @@ import java.io.File; -import org.openide.DialogDisplayer; -import org.openide.NotifyDescriptor; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.Lookup; diff --git a/utilities/src/org/netbeans/modules/openfile/RecentFileAction.java b/utilities/src/org/netbeans/modules/openfile/RecentFileAction.java --- a/utilities/src/org/netbeans/modules/openfile/RecentFileAction.java +++ b/utilities/src/org/netbeans/modules/openfile/RecentFileAction.java @@ -43,9 +43,10 @@ import java.awt.Component; import java.awt.MouseInfo; import java.awt.Point; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.beans.BeanInfo; -import java.net.URL; +import java.io.File; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -65,7 +66,9 @@ import javax.swing.event.PopupMenuListener; import org.netbeans.modules.openfile.RecentFiles.HistoryItem; import org.openide.awt.DynamicMenuContent; +import org.openide.awt.StatusDisplayer; import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; import org.openide.util.NbBundle; @@ -80,7 +83,7 @@ public class RecentFileAction extends AbstractAction implements Presenter.Menu, PopupMenuListener, ChangeListener { /** property of menu items where we store fileobject to open */ - private static final String URL_PROP = "RecentFileAction.Recent_URL"; + private static final String PATH_PROP = "RecentFileAction.Recent_URL"; private JMenu menu; @@ -141,29 +144,26 @@ for (final HistoryItem hItem : files) { // create and configure menu item + File f = new File (hItem.getPath()); + if (!f.exists()) { + continue; + } final JMenuItem jmi = new JMenuItem(hItem.getFileName()); - jmi.putClientProperty(URL_PROP, hItem.getURL()); + jmi.putClientProperty(PATH_PROP, hItem.getPath()); jmi.addActionListener(this); menu.add(jmi); - - //get icon on another thread - new Runnable(){ - public void run() { - FileObject fo = RecentFiles.convertURL2File(hItem.getURL()); - Icon icon = null; - try { - DataObject dObj = DataObject.find(fo); - icon = new ImageIcon(dObj.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)); - } catch (DataObjectNotFoundException ex) { - // should not happen, log and skip to next - Logger.getLogger(RecentFiles.class.getName()).log( - Level.INFO, ex.getMessage(), ex); - } - jmi.setIcon(icon); - } - }.run(); + FileObject fo = RecentFiles.convertPath2File(hItem.getPath()); + Icon icon = null; + try { + DataObject dObj = DataObject.find(fo); + icon = new ImageIcon(dObj.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)); + } catch (DataObjectNotFoundException ex) { + // should not happen, log and skip to next + Logger.getLogger(RecentFiles.class.getName()).log( + Level.INFO, ex.getMessage(), ex); + } + jmi.setIcon(icon); } - ensureSelected(); } @@ -205,9 +205,21 @@ */ public void actionPerformed(ActionEvent evt) { JMenuItem source = (JMenuItem) evt.getSource(); - URL url = (URL) source.getClientProperty(URL_PROP); - if (url != null) { - OpenFile.open(RecentFiles.convertURL2File(url), -1); + String path = (String) source.getClientProperty(PATH_PROP); + boolean success = path != null; + if (success) { + File f = new File(path); + success = f.exists(); + if (success) { + String msg = OpenFile.open(FileUtil.toFileObject( + FileUtil.normalizeFile(f)), -1); + success = msg == null; + if (!success) { + StatusDisplayer.getDefault().setStatusText(msg); + Toolkit.getDefaultToolkit().beep(); + RecentFiles.pruneHistory(); + } + } } } diff --git a/utilities/src/org/netbeans/modules/openfile/RecentFiles.java b/utilities/src/org/netbeans/modules/openfile/RecentFiles.java --- a/utilities/src/org/netbeans/modules/openfile/RecentFiles.java +++ b/utilities/src/org/netbeans/modules/openfile/RecentFiles.java @@ -38,7 +38,6 @@ * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ - package org.netbeans.modules.openfile; import java.beans.PropertyChangeEvent; @@ -48,7 +47,7 @@ import org.openide.windows.CloneableTopComponent; import org.openide.windows.TopComponent; import java.beans.PropertyChangeListener; -import java.net.URL; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -57,7 +56,7 @@ import java.util.logging.Logger; import java.util.prefs.Preferences; import org.openide.filesystems.FileObject; -import org.openide.filesystems.URLMapper; +import org.openide.filesystems.FileUtil; import org.openide.util.NbPreferences; import org.openide.windows.WindowManager; @@ -70,30 +69,23 @@ /** List of recently closed files */ private static List history = new ArrayList(); - /** Preferences node for storing history info */ private static Preferences prefs; - private static final Object HISTORY_LOCK = new Object(); - /** Name of preferences node where we persist history */ private static final String PREFS_NODE = "RecentFilesHistory"; //NOI18N - /** Prefix of property for recent file URL*/ private static final String PROP_URL_PREFIX = "RecentFilesURL."; //NOI18N - - /** Separator to encode file path and time into one string in preferences */ - private static final String SEPARATOR = "; time="; - /** Boundary for items count in history */ static final int MAX_HISTORY_ITEMS = 15; - - private RecentFiles () { + + private RecentFiles() { } /** Starts to listen for recently closed files */ - public static void init () { + public static void init() { WindowManager.getDefault().invokeWhenUIReady(new Runnable() { + public void run() { List loaded = load(); synchronized (HISTORY_LOCK) { @@ -105,12 +97,13 @@ } /** Returns read-only list of recently closed files */ - public static List getRecentFiles () { + public static List getRecentFiles() { synchronized (HISTORY_LOCK) { - checkHistory(false); + checkHistory(); return Collections.unmodifiableList(history); } } + private static volatile boolean historyProbablyValid; /** * True if there are probably some recently closed files. @@ -118,35 +111,37 @@ * but this is much faster than calling {@link #getRecentFiles}. */ public static boolean hasRecentFiles() { - synchronized (HISTORY_LOCK) { - checkHistory(true); - return !history.isEmpty(); + if (!historyProbablyValid) { + synchronized (HISTORY_LOCK) { + checkHistory(); + return !history.isEmpty(); + } } + return historyProbablyValid; } /** Loads list of recent files stored in previous system sessions. * @return list of stored recent files */ - static List load () { + static List load() { String[] keys; Preferences _prefs = getPrefs(); try { keys = _prefs.keys(); - } - catch (BackingStoreException ex) { + } catch (BackingStoreException ex) { Logger.getLogger(RecentFiles.class.getName()).log(Level.FINE, ex.getMessage(), ex); return Collections.emptyList(); } - + List result = new ArrayList(); for (String curKey : keys) { String value = _prefs.get(curKey, null); - if (curKey.startsWith(PROP_URL_PREFIX) && (value != null)){ + if (value != null) { try { int id = new Integer(curKey.substring(PROP_URL_PREFIX.length())).intValue(); - HistoryItem hItem = new HistoryItem(id, new URL(value)); - int ind = result.indexOf(hItem); - if (ind == -1){ + HistoryItem hItem = new HistoryItem(id, value); + int ind = result.indexOf(hItem); + if (ind == -1) { result.add(hItem); } else { _prefs.remove(PROP_URL_PREFIX + Math.max(result.get(ind).id, id)); @@ -163,68 +158,70 @@ } Collections.sort(result); store(result); - - return result; + + return result; } - static void store () { + static void store() { store(history); } - static void store (List history) { + static void store(List history) { Preferences _prefs = getPrefs(); - for(int i = 0; i < history.size(); i++){ + for (int i = 0; i < history.size(); i++) { HistoryItem hi = history.get(i); - if ((hi.id != i) && (hi.id >= history.size())){ + if ((hi.id != i) && (hi.id >= history.size())) { _prefs.remove(PROP_URL_PREFIX + hi.id); } hi.id = i; - _prefs.put(PROP_URL_PREFIX + i, hi.getURL().toExternalForm()); + _prefs.put(PROP_URL_PREFIX + i, hi.getPath()); } } - - static Preferences getPrefs () { + + static Preferences getPrefs() { if (prefs == null) { prefs = NbPreferences.forModule(RecentFiles.class).node(PREFS_NODE); } return prefs; } - + /** Adds file represented by given TopComponent to the list, * if conditions are met. - */ - private static void addFile (TopComponent tc) { + */ + private static void addFile(TopComponent tc) { if (tc instanceof CloneableTopComponent) { - addFile(obtainURL(tc)); + addFile(obtainPath(tc)); } } - static void addFile (URL fileURL){ - if (fileURL != null) { - synchronized (HISTORY_LOCK) { - // avoid duplicates - HistoryItem hItem = null; - do{ - hItem = findHistoryItem(fileURL); - }while(history.remove(hItem)); + static void addFile(String path) { + if (path != null) { + historyProbablyValid = false; + synchronized (HISTORY_LOCK) { + // avoid duplicates + HistoryItem hItem = null; + do { + hItem = findHistoryItem(path); + } while (history.remove(hItem)); - hItem = new HistoryItem(0, fileURL); - history.add(0, hItem); - for(int i = MAX_HISTORY_ITEMS; i it = history.iterator(); - while (it.hasNext()) { - HistoryItem historyItem = it.next(); - FileObject fo = convertURL2File(historyItem.getURL()); - if (fo == null || !fo.isValid()) { - it.remove(); - } else if (checkOnlyForFirstValid) { - break; + historyProbablyValid = !history.isEmpty(); + } + + static void pruneHistory() { + synchronized (HISTORY_LOCK) { + Iterator it = history.iterator(); + while (it.hasNext()) { + HistoryItem historyItem = it.next(); + File f = new File(historyItem.getPath()); + if (!f.exists()) { + it.remove(); + } } } } - /** One item of the recently closed files history - * Comparable by the time field, ascending from most recent to older items. - */ - public static final class HistoryItem implements Comparable { + /** One item of the recently closed files history + * Comparable by the time field, ascending from most recent to older items. + */ + + static final class HistoryItem implements Comparable { + private int id; - private URL fileURL; + private String path; private String fileName; - - HistoryItem (int id, URL fileURL) { - this.fileURL = fileURL; + + HistoryItem(int id, String path) { + this.path = path; this.id = id; } - - public URL getURL () { - return fileURL; + + public String getPath() { + return path; } - public String getFileName () { - if (fileName == null){ - int pos = fileURL.getFile().lastIndexOf('/'); - if ((pos != -1) && (pos < fileURL.getFile().length())){ - fileName = fileURL.getFile().substring(pos+1); - }else{ - fileName = fileURL.getFile(); + public String getFileName() { + if (fileName == null) { + int pos = path.lastIndexOf(File.separatorChar); + if ((pos != -1) && (pos < path.length())) { + fileName = path.substring(pos + 1); + } else { + fileName = path; } } return fileName; @@ -322,17 +318,24 @@ @Override public boolean equals(Object obj) { - if (obj instanceof HistoryItem){ - return ((HistoryItem)obj).getURL().equals(fileURL); + if (obj instanceof HistoryItem) { + return ((HistoryItem) obj).getPath().equals(path); } return false; } + + @Override + public int hashCode() { + int hash = 7; + hash = 17 * hash + (this.path != null ? this.path.hashCode() : 0); + return hash; + } } - + /** Receives info about opened and closed TopComponents from window system. - */ + */ private static class WindowRegistryL implements PropertyChangeListener { - + public void propertyChange(PropertyChangeEvent evt) { if (TopComponent.Registry.PROP_TC_CLOSED.equals(evt.getPropertyName())) { addFile((TopComponent) evt.getNewValue()); @@ -341,7 +344,5 @@ removeFile((TopComponent) evt.getNewValue()); } } - } - } diff --git a/utilities/test/unit/src/org/netbeans/modules/openfile/RecentFilesTest.java b/utilities/test/unit/src/org/netbeans/modules/openfile/RecentFilesTest.java --- a/utilities/test/unit/src/org/netbeans/modules/openfile/RecentFilesTest.java +++ b/utilities/test/unit/src/org/netbeans/modules/openfile/RecentFilesTest.java @@ -107,7 +107,7 @@ List recentFiles = RecentFiles.getRecentFiles(); assertTrue("Expected " + files.length + " recent files, got " + recentFiles.size(), files.length == recentFiles.size()); for (FileObject fo : files) { - assertEquals(RecentFiles.convertFile2URL(fo), recentFiles.get(i).getURL()); + assertEquals(RecentFiles.convertFile2Path(fo), recentFiles.get(i).getPath()); i++; } @@ -132,7 +132,7 @@ // store, load and check for equality for (int i=0; i < files.length; i++) { FileObject file = files[i]; - RecentFiles.addFile(RecentFiles.convertFile2URL(file)); + RecentFiles.addFile(RecentFiles.convertFile2Path(file)); Thread.sleep(100); } RecentFiles.store(); @@ -141,7 +141,7 @@ int i = files.length - 1; for (FileObject fileObject : files) { assertTrue("File #" + (i + 1) + " differs", - fileObject.equals(RecentFiles.convertURL2File(loaded.get(i--).getURL()))); + fileObject.equals(RecentFiles.convertPath2File(loaded.get(i--).getPath()))); } } @@ -165,7 +165,7 @@ List recentFiles = RecentFiles.getRecentFiles(); boolean contained = false; for (HistoryItem historyItem : recentFiles) { - if (fo.equals(RecentFiles.convertURL2File(historyItem.getURL()))) { + if (fo.equals(RecentFiles.convertPath2File(historyItem.getPath()))) { contained = true; break; }