From b0cb2c4e529e1fa1651af23cd54e394053d8b775 Mon Sep 17 00:00:00 2001 From: Federico Fissore Date: Mon, 1 Jun 2015 17:08:10 +0200 Subject: [PATCH] Added File > Recent menu: shows last 5 opened sketches, sorted in reverse chronological order --- app/src/processing/app/Base.java | 81 +++++++++++++++++-- app/src/processing/app/Editor.java | 21 ++++- .../src/processing/app/PreferencesData.java | 52 ++++++------ 3 files changed, 121 insertions(+), 33 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 49b420a32..70906bf6c 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -86,6 +86,8 @@ public class Base { } }; + private static final int RECENT_SKETCHES_MAX_SIZE = 5; + private static boolean commandLine; public static volatile Base INSTANCE; @@ -117,6 +119,7 @@ public class Base { private volatile Action openBoardsManager; private final PdeKeywords pdeKeywords; + private final List recentSketchesMenuItems; static public void main(String args[]) throws Exception { System.setProperty("awt.useSystemAAFontSettings", "on"); @@ -269,6 +272,7 @@ public class Base { public Base(String[] args) throws Exception { BaseNoGui.notifier = new GUIUserNotifier(this); + this.recentSketchesMenuItems = new LinkedList(); String sketchbookPath = BaseNoGui.getSketchbookPath(); @@ -316,7 +320,7 @@ public class Base { boolean showEditor = parser.isGuiMode(); if (!parser.isForceSavePrefs()) PreferencesData.setDoSave(showEditor); - if (handleOpen(file, nextEditorLocation(), showEditor) == null) { + if (handleOpen(file, nextEditorLocation(), showEditor, false) == null) { String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path); // Open failure is fatal in upload/verify mode if (parser.isVerifyOrUploadMode()) @@ -547,7 +551,7 @@ public class Base { location = nextEditorLocation(); } // If file did not exist, null will be returned for the Editor - if (handleOpen(new File(path), location, true, false) != null) { + if (handleOpen(new File(path), location, true, false, false) != null) { opened++; } } @@ -594,12 +598,25 @@ public class Base { PreferencesData.setInteger("last.sketch.count", index); } + protected void storeRecentSketches(Sketch sketch) { + if (sketch.isUntitled()) { + return; + } + + Set sketches = new LinkedHashSet(); + sketches.add(sketch.getMainFilePath()); + sketches.addAll(PreferencesData.getCollection("recent.sketches")); + + PreferencesData.setCollection("recent.sketches", sketches); + } + // Because of variations in native windowing systems, no guarantees about // changes to the focused and active Windows can be made. Developers must // never assume that this Window is the focused or active Window until this // Window receives a WINDOW_GAINED_FOCUS or WINDOW_ACTIVATED event. protected void handleActivated(Editor whichEditor) { activeEditor = whichEditor; + activeEditor.rebuildRecentSketchesMenu(); // set the current window to be the console that's getting output EditorConsoleStream.setCurrent(activeEditor.console); @@ -728,8 +745,7 @@ public class Base { try { File file = createNewUntitled(); if (file != null) { - Editor editor = handleOpen(file); - editor.untitled = true; + Editor editor = handleOpen(file, true); } } catch (IOException e) { @@ -837,14 +853,18 @@ public class Base { * @throws Exception */ public Editor handleOpen(File file) throws Exception { - return handleOpen(file, nextEditorLocation(), true); + return handleOpen(file, false); } - protected Editor handleOpen(File file, int[] location, boolean showEditor) throws Exception { - return handleOpen(file, location, showEditor, true); + public Editor handleOpen(File file, boolean untitled) throws Exception { + return handleOpen(file, nextEditorLocation(), true, untitled); } - protected Editor handleOpen(File file, int[] location, boolean showEditor, boolean storeOpenedSketches) throws Exception { + protected Editor handleOpen(File file, int[] location, boolean showEditor, boolean untitled) throws Exception { + return handleOpen(file, location, showEditor, true, untitled); + } + + protected Editor handleOpen(File file, int[] location, boolean showEditor, boolean storeOpenedSketches, boolean untitled) throws Exception { if (!file.exists()) return null; // Cycle through open windows to make sure that it's not already open. @@ -863,12 +883,16 @@ public class Base { return null; // Just walk away quietly } + editor.untitled = untitled; + editors.add(editor); if (storeOpenedSketches) { // Store information on who's open and running // (in case there's a crash or something that can't be recovered) storeSketches(); + storeRecentSketches(editor.getSketch()); + rebuildRecentSketchesMenuItems(); PreferencesData.save(); } @@ -886,6 +910,42 @@ public class Base { return editor; } + protected void rebuildRecentSketchesMenuItems() { + Set recentSketches = new LinkedHashSet() { + + @Override + public boolean add(File file) { + if (size() >= RECENT_SKETCHES_MAX_SIZE) { + return false; + } + return super.add(file); + } + }; + + for (String path : PreferencesData.getCollection("recent.sketches")) { + File file = new File(path); + if (file.exists()) { + recentSketches.add(file); + } + } + + recentSketchesMenuItems.clear(); + for (final File recentSketch : recentSketches) { + JMenuItem recentSketchMenuItem = new JMenuItem(recentSketch.getParentFile().getName()); + recentSketchMenuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + try { + handleOpen(recentSketch); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + recentSketchesMenuItems.add(recentSketchMenuItem); + } + } + /** * Close a sketch as specified by its editor window. @@ -912,6 +972,7 @@ public class Base { //ignore } storeSketches(); + rebuildRecentSketchesMenuItems(); // Save out the current prefs state PreferencesData.save(); @@ -2463,4 +2524,8 @@ public class Base { public PdeKeywords getPdeKeywords() { return pdeKeywords; } + + public List getRecentSketchesMenuItems() { + return recentSketchesMenuItems; + } } diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 61d298c9d..044c1f464 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -71,6 +71,7 @@ import cc.arduino.packages.uploaders.SerialUploader; public class Editor extends JFrame implements RunnerListener { private final Platform platform; + private JMenu recentSketchesMenu; private static class ShouldSaveIfModified implements Predicate { @@ -523,10 +524,10 @@ public class Editor extends JFrame implements RunnerListener { public void menuSelected(MenuEvent e) { List components = Arrays.asList(fileMenu.getComponents()); if (!components.contains(sketchbookMenu)) { - fileMenu.insert(sketchbookMenu, 2); + fileMenu.insert(sketchbookMenu, 3); } if (!components.contains(sketchbookMenu)) { - fileMenu.insert(examplesMenu, 3); + fileMenu.insert(examplesMenu, 4); } fileMenu.revalidate(); validate(); @@ -603,6 +604,16 @@ public class Editor extends JFrame implements RunnerListener { }); fileMenu.add(item); + base.rebuildRecentSketchesMenuItems(); + recentSketchesMenu = new JMenu(_("Recent")); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + rebuildRecentSketchesMenu(); + } + }); + fileMenu.add(recentSketchesMenu); + if (sketchbookMenu == null) { sketchbookMenu = new JMenu(_("Sketchbook")); MenuScroller.setScrollerFor(sketchbookMenu); @@ -684,6 +695,12 @@ public class Editor extends JFrame implements RunnerListener { return fileMenu; } + public void rebuildRecentSketchesMenu() { + recentSketchesMenu.removeAll(); + for (JMenuItem recentSketchMenuItem : base.getRecentSketchesMenuItems()) { + recentSketchesMenu.add(recentSketchMenuItem); + } + } protected void buildSketchMenu(JMenu sketchMenu) { sketchMenu.removeAll(); diff --git a/arduino-core/src/processing/app/PreferencesData.java b/arduino-core/src/processing/app/PreferencesData.java index c3a0f9069..380070001 100644 --- a/arduino-core/src/processing/app/PreferencesData.java +++ b/arduino-core/src/processing/app/PreferencesData.java @@ -1,24 +1,23 @@ package processing.app; -import static processing.app.I18n._; - -import java.awt.*; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.util.Arrays; -import java.util.Iterator; -import java.util.MissingResourceException; - +import com.google.common.base.Joiner; import org.apache.commons.compress.utils.IOUtils; import processing.app.helpers.PreferencesHelper; import processing.app.helpers.PreferencesMap; import processing.app.legacy.PApplet; import processing.app.legacy.PConstants; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.MissingResourceException; + +import static processing.app.I18n._; + public class PreferencesData { @@ -51,14 +50,14 @@ public class PreferencesData { prefs.load(new File(BaseNoGui.getContentFile("lib"), PREFS_FILE)); } catch (IOException e) { BaseNoGui.showError(null, _("Could not read default settings.\n" + - "You'll need to reinstall Arduino."), e); + "You'll need to reinstall Arduino."), e); } // set some runtime constants (not saved on preferences file) File hardwareFolder = BaseNoGui.getHardwareFolder(); prefs.put("runtime.ide.path", hardwareFolder.getParentFile().getAbsolutePath()); prefs.put("runtime.ide.version", "" + BaseNoGui.REVISION); - + // clone the hash table defaults = new PreferencesMap(prefs); @@ -68,10 +67,10 @@ public class PreferencesData { prefs.load(preferencesFile); } catch (IOException ex) { BaseNoGui.showError(_("Error reading preferences"), - I18n.format(_("Error reading the preferences file. " - + "Please delete (or move)\n" - + "{0} and restart Arduino."), - preferencesFile.getAbsolutePath()), ex); + I18n.format(_("Error reading the preferences file. " + + "Please delete (or move)\n" + + "{0} and restart Arduino."), + preferencesFile.getAbsolutePath()), ex); } } @@ -197,8 +196,7 @@ public class PreferencesData { } // get a copy of the Preferences - static public PreferencesMap getMap() - { + static public PreferencesMap getMap() { return new PreferencesMap(prefs); } @@ -211,8 +209,7 @@ public class PreferencesData { // Decide wether changed preferences will be saved. When value is // false, Preferences.save becomes a no-op. - static public void setDoSave(boolean value) - { + static public void setDoSave(boolean value) { doSave = value; } @@ -225,4 +222,13 @@ public class PreferencesData { } return font; } + + public static Collection getCollection(String key) { + return Arrays.asList(get(key, "").split(",")); + } + + public static void setCollection(String key, Collection values) { + String value = Joiner.on(',').join(values); + set(key, value); + } }