diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 410cbfeec..95b1650b9 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -1,24 +1,24 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* - Part of the Processing project - http://processing.org + Part of the Processing project - http://processing.org - Copyright (c) 2004-12 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology + Copyright (c) 2004-12 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ package processing.app; @@ -47,16 +47,15 @@ import javax.swing.undo.*; */ public abstract class Editor extends JFrame implements RunnerListener { protected Base base; - protected EditorState state; - protected Mode mode; // otherwise, if the window is resized with the message label // set to blank, it's preferredSize() will be fukered - static protected final String EMPTY = " " - + " " - + " "; + static protected final String EMPTY = + " " + + " " + + " "; /** * true if this file has not yet been given a name by the user @@ -64,31 +63,22 @@ public abstract class Editor extends JFrame implements RunnerListener { // private boolean untitled; private PageFormat pageFormat; - private PrinterJob printerJob; // file and sketch menus for re-inserting items private JMenu fileMenu; - // private JMenuItem saveMenuItem; // private JMenuItem saveAsMenuItem; private JMenu sketchMenu; protected EditorHeader header; - protected EditorToolbar toolbar; - protected JEditTextArea textarea; - protected EditorStatus status; - protected JSplitPane splitPane; - protected JPanel consolePanel; - protected EditorConsole console; - protected EditorLineStatus lineStatus; // currently opened program @@ -99,60 +89,48 @@ public abstract class Editor extends JFrame implements RunnerListener { // undo fellers private JMenuItem undoItem, redoItem; - protected UndoAction undoAction; - protected RedoAction redoAction; - /** the currently selected tab's undo manager */ private UndoManager undo; - // used internally for every edit. Groups hotkey-event text manipulations and // groups multi-character inputs into a single undos. private CompoundEdit compoundEdit; - // timer to decide when to group characters into an undo private Timer timer; - private TimerTask endUndoEvent; - // true if inserting text, false if removing text private boolean isInserting; - // maintain caret position during undo operations private final Stack caretUndoStack = new Stack(); - private final Stack caretRedoStack = new Stack(); private FindReplace find; - JMenu toolsMenu; - JMenu modeMenu; ArrayList coreTools; - public ArrayList contribTools; + // protected Editor(final Base base, String path, int[] location, final Mode mode) { - protected Editor(final Base base, String path, EditorState state, - final Mode mode) { + protected Editor(final Base base, String path, EditorState state, final Mode mode) { super("Processing", state.checkConfig()); this.base = base; this.state = state; this.mode = mode; - Toolkit.setIcon(this); // TODO should this be per-mode? + Toolkit.setIcon(this); // TODO should this be per-mode? // Install default actions for Run, Present, etc. // resetHandlers(); // add listener to handle window close box hit event addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - base.handleClose(Editor.this, false); - } - }); + public void windowClosing(WindowEvent e) { + base.handleClose(Editor.this, false); + } + }); // don't close the window when clicked, the app will take care // of that via the handleQuitInternal() methods // http://dev.processing.org/bugs/show_bug.cgi?id=440 @@ -160,29 +138,29 @@ public abstract class Editor extends JFrame implements RunnerListener { // When bringing a window to front, let the Base know addWindowListener(new WindowAdapter() { - public void windowActivated(WindowEvent e) { + public void windowActivated(WindowEvent e) { // EditorConsole.systemOut.println("editor window activated"); - base.handleActivated(Editor.this); + base.handleActivated(Editor.this); // mode.handleActivated(Editor.this); - fileMenu.insert(base.getSketchbookMenu(), 2); - fileMenu.insert(base.getRecentMenu(), 3); + fileMenu.insert(base.getSketchbookMenu(), 2); + fileMenu.insert(base.getRecentMenu(), 3); // fileMenu.insert(mode.getExamplesMenu(), 3); - sketchMenu.insert(mode.getImportMenu(), 4); - mode.insertToolbarRecentMenu(); - } + sketchMenu.insert(mode.getImportMenu(), 4); + mode.insertToolbarRecentMenu(); + } - // added for 1.0.5 - // http://dev.processing.org/bugs/show_bug.cgi?id=1260 - public void windowDeactivated(WindowEvent e) { + // added for 1.0.5 + // http://dev.processing.org/bugs/show_bug.cgi?id=1260 + public void windowDeactivated(WindowEvent e) { // EditorConsole.systemErr.println("editor window deactivated"); // mode.handleDeactivated(Editor.this); - fileMenu.remove(base.getSketchbookMenu()); - fileMenu.remove(base.getRecentMenu()); + fileMenu.remove(base.getSketchbookMenu()); + fileMenu.remove(base.getRecentMenu()); // fileMenu.remove(mode.getExamplesMenu()); - sketchMenu.remove(mode.getImportMenu()); - mode.removeToolbarRecentMenu(); - } - }); + sketchMenu.remove(mode.getImportMenu()); + mode.removeToolbarRecentMenu(); + } + }); timer = new Timer(); @@ -259,7 +237,6 @@ public abstract class Editor extends JFrame implements RunnerListener { // end an undo-chunk any time the caret moves unless it's when text is edited textarea.addCaretListener(new CaretListener() { String lastText = textarea.getText(); - public void caretUpdate(CaretEvent e) { String newText = textarea.getText(); if (lastText.equals(newText) && isDirectEdit()) { @@ -278,11 +255,8 @@ public abstract class Editor extends JFrame implements RunnerListener { state.apply(this); // Set the minimum size for the editor window - setMinimumSize(new Dimension( - Preferences - .getInteger("editor.window.width.min"), - Preferences - .getInteger("editor.window.height.min"))); + setMinimumSize(new Dimension(Preferences.getInteger("editor.window.width.min"), + Preferences.getInteger("editor.window.height.min"))); // Bring back the general options for the editor applyPreferences(); @@ -308,6 +282,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + /** * Broken out to get modes working for GSOC, but this needs a longer-term * solution where the listeners are handled properly. @@ -316,18 +291,22 @@ public abstract class Editor extends JFrame implements RunnerListener { return new JEditTextArea(new PdeTextAreaDefaults(mode)); } + public EditorState getEditorState() { return state; } + public void removeRecent() { base.removeRecent(this); } + public void addRecent() { base.handleRecent(this); } + /** * Handles files dragged & dropped from the desktop and into the editor * window. Dragging files into the editor window is the same as using @@ -343,12 +322,12 @@ public abstract class Editor extends JFrame implements RunnerListener { int successful = 0; try { - DataFlavor uriListFlavor = new DataFlavor( - "text/uri-list;class=java.lang.String"); + DataFlavor uriListFlavor = + new DataFlavor("text/uri-list;class=java.lang.String"); if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { - java.util.List list = (java.util.List) transferable - .getTransferData(DataFlavor.javaFileListFlavor); + java.util.List list = (java.util.List) + transferable.getTransferData(DataFlavor.javaFileListFlavor); for (int i = 0; i < list.size(); i++) { File file = (File) list.get(i); if (sketch.addFile(file)) { @@ -358,11 +337,10 @@ public abstract class Editor extends JFrame implements RunnerListener { } else if (transferable.isDataFlavorSupported(uriListFlavor)) { // Some platforms (Mac OS X and Linux, when this began) preferred // this method of moving files. - String data = (String) transferable.getTransferData(uriListFlavor); + String data = (String)transferable.getTransferData(uriListFlavor); String[] pieces = PApplet.splitTokens(data, "\r\n"); for (int i = 0; i < pieces.length; i++) { - if (pieces[i].startsWith("#")) - continue; + if (pieces[i].startsWith("#")) continue; String path = null; if (pieces[i].startsWith("file:///")) { @@ -376,10 +354,8 @@ public abstract class Editor extends JFrame implements RunnerListener { } } } catch (Exception e) { - Base - .showWarning("Drag & Drop Problem", - "An error occurred while trying to add files to the sketch.", - e); + Base.showWarning("Drag & Drop Problem", + "An error occurred while trying to add files to the sketch.", e); return false; } @@ -396,14 +372,17 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + public Base getBase() { return base; } + public Mode getMode() { return mode; } + protected void initModeMenu() { modeMenu = new JMenu(); ButtonGroup modeGroup = new ButtonGroup(); @@ -431,18 +410,24 @@ public abstract class Editor extends JFrame implements RunnerListener { modeMenu.add(addLib); } + public JMenu getModeMenu() { return modeMenu; } + + // public Settings getTheme() { // return mode.getTheme(); // } + abstract public EditorToolbar createToolbar(); + abstract public Formatter createFormatter(); + // protected void setPlacement(int[] location) { // setBounds(location[0], location[1], location[2], location[3]); // if (location[4] != 0) { @@ -467,59 +452,74 @@ public abstract class Editor extends JFrame implements RunnerListener { // return location; // } + protected void setDividerLocation(int pos) { splitPane.setDividerLocation(pos); } + protected int getDividerLocation() { return splitPane.getDividerLocation(); } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** - * Read and apply new values from the preferences, either because the app is - * just starting up, or the user just finished messing with things in the - * Preferences window. + * Read and apply new values from the preferences, either because + * the app is just starting up, or the user just finished messing + * with things in the Preferences window. */ protected void applyPreferences() { // Update fonts and other items controllable from the prefs textarea.getPainter().updateAppearance(); textarea.repaint(); - + console.updateAppearance(); - + // All of this code was specific to using an external editor. /* - * // // apply the setting for 'use external editor' // boolean external = - * Preferences.getBoolean("editor.external"); // - * textarea.setEditable(!external); // saveMenuItem.setEnabled(!external); - * // saveAsMenuItem.setEnabled(!external); - * - * TextAreaPainter painter = textarea.getPainter(); // if (external) { // // - * disable line highlight and turn off the caret when disabling // Color - * color = mode.getColor("editor.external.bgcolor"); // - * painter.setBackground(color); // painter.setLineHighlightEnabled(false); - * // textarea.setCaretVisible(false); // } else { Color color = - * mode.getColor("editor.bgcolor"); painter.setBackground(color); boolean - * highlight = Preferences.getBoolean("editor.linehighlight"); - * painter.setLineHighlightEnabled(highlight); - * textarea.setCaretVisible(true); // } - * - * // apply changes to the font size for the editor // - * painter.setFont(Preferences.getFont("editor.font")); - * - * // in case tab expansion stuff has changed // removing this, just - * checking prefs directly instead // listener.applyPreferences(); - * - * // in case moved to a new location // For 0125, changing to async version - * (to be implemented later) //sketchbook.rebuildMenus(); // For 0126, moved - * into Base, which will notify all editors. //base.rebuildMenusAsync(); +// // apply the setting for 'use external editor' +// boolean external = Preferences.getBoolean("editor.external"); +// textarea.setEditable(!external); +// saveMenuItem.setEnabled(!external); +// saveAsMenuItem.setEnabled(!external); + + TextAreaPainter painter = textarea.getPainter(); +// if (external) { +// // disable line highlight and turn off the caret when disabling +// Color color = mode.getColor("editor.external.bgcolor"); +// painter.setBackground(color); +// painter.setLineHighlightEnabled(false); +// textarea.setCaretVisible(false); +// } else { + Color color = mode.getColor("editor.bgcolor"); + painter.setBackground(color); + boolean highlight = Preferences.getBoolean("editor.linehighlight"); + painter.setLineHighlightEnabled(highlight); + textarea.setCaretVisible(true); +// } + + // apply changes to the font size for the editor +// painter.setFont(Preferences.getFont("editor.font")); + + // in case tab expansion stuff has changed + // removing this, just checking prefs directly instead +// listener.applyPreferences(); + + // in case moved to a new location + // For 0125, changing to async version (to be implemented later) + //sketchbook.rebuildMenus(); + // For 0126, moved into Base, which will notify all editors. + //base.rebuildMenusAsync(); */ } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + protected void buildMenuBar() { JMenuBar menubar = new JMenuBar(); menubar = new JMenuBar(); @@ -554,8 +554,10 @@ public abstract class Editor extends JFrame implements RunnerListener { setJMenuBar(menubar); } + abstract public JMenu buildFileMenu(); + // public JMenu buildFileMenu(Editor editor) { // return buildFileMenu(editor, null); // } @@ -564,24 +566,25 @@ public abstract class Editor extends JFrame implements RunnerListener { // // most of these items are per-mode // protected JMenu buildFileMenu(Editor editor, JMenuItem[] exportItems) { + protected JMenu buildFileMenu(JMenuItem[] exportItems) { JMenuItem item; JMenu fileMenu = new JMenu("File"); item = Toolkit.newJMenuItem("New", 'N'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - base.handleNew(); - } - }); + public void actionPerformed(ActionEvent e) { + base.handleNew(); + } + }); fileMenu.add(item); item = Toolkit.newJMenuItem("Open...", 'O'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - base.handleOpenPrompt(); - } - }); + public void actionPerformed(ActionEvent e) { + base.handleOpenPrompt(); + } + }); fileMenu.add(item); fileMenu.add(base.getSketchbookMenu()); @@ -670,14 +673,17 @@ public abstract class Editor extends JFrame implements RunnerListener { return fileMenu; } + // public void setSaveItem(JMenuItem item) { // saveMenuItem = item; // } + // public void setSaveAsItem(JMenuItem item) { // saveAsMenuItem = item; // } + protected JMenu buildEditMenu() { JMenu menu = new JMenu("Edit"); JMenuItem item; @@ -690,7 +696,7 @@ public abstract class Editor extends JFrame implements RunnerListener { // http://code.google.com/p/processing/issues/detail?id=363 if (Base.isWindows()) { redoItem = Toolkit.newJMenuItem("Redo", 'Y'); - } else { // Linux and OS X + } else { // Linux and OS X redoItem = Toolkit.newJMenuItemShift("Redo", 'Z'); } redoItem.addActionListener(redoAction = new RedoAction()); @@ -702,97 +708,106 @@ public abstract class Editor extends JFrame implements RunnerListener { // if some text is currently selected item = Toolkit.newJMenuItem("Cut", 'X'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCut(); - } - }); + public void actionPerformed(ActionEvent e) { + handleCut(); + } + }); menu.add(item); item = Toolkit.newJMenuItem("Copy", 'C'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - textarea.copy(); - } - }); + public void actionPerformed(ActionEvent e) { + textarea.copy(); + } + }); menu.add(item); item = Toolkit.newJMenuItemShift("Copy as HTML", 'C'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCopyAsHTML(); - } - }); + public void actionPerformed(ActionEvent e) { + handleCopyAsHTML(); + } + }); menu.add(item); item = Toolkit.newJMenuItem("Paste", 'V'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - textarea.paste(); - sketch.setModified(true); - } - }); + public void actionPerformed(ActionEvent e) { + textarea.paste(); + sketch.setModified(true); + } + }); menu.add(item); item = Toolkit.newJMenuItem("Select All", 'A'); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + textarea.selectAll(); + } + }); + menu.add(item); + + /* + menu.addSeparator(); + + item = Toolkit.newJMenuItem("Delete Selected Lines", 'D'); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - textarea.selectAll(); + handleDeleteLines(); } }); menu.add(item); - /* - * menu.addSeparator(); - * - * item = Toolkit.newJMenuItem("Delete Selected Lines", 'D'); - * item.addActionListener(new ActionListener() { public void - * actionPerformed(ActionEvent e) { handleDeleteLines(); } }); - * menu.add(item); - * - * item = new JMenuItem("Move Selected Lines Up"); - * item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, - * Event.ALT_MASK)); item.addActionListener(new ActionListener() { public - * void actionPerformed(ActionEvent e) { handleMoveLines(true); } }); - * menu.add(item); - * - * item = new JMenuItem("Move Selected Lines Down"); - * item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, - * Event.ALT_MASK)); item.addActionListener(new ActionListener() { public - * void actionPerformed(ActionEvent e) { handleMoveLines(false); } }); - * menu.add(item); + item = new JMenuItem("Move Selected Lines Up"); + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, Event.ALT_MASK)); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleMoveLines(true); + } + }); + menu.add(item); + + item = new JMenuItem("Move Selected Lines Down"); + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, Event.ALT_MASK)); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleMoveLines(false); + } + }); + menu.add(item); */ menu.addSeparator(); item = Toolkit.newJMenuItem("Auto Format", 'T'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleAutoFormat(); - } + public void actionPerformed(ActionEvent e) { + handleAutoFormat(); + } }); menu.add(item); item = Toolkit.newJMenuItem("Comment/Uncomment", '/'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCommentUncomment(); - } + public void actionPerformed(ActionEvent e) { + handleCommentUncomment(); + } }); menu.add(item); item = Toolkit.newJMenuItem("Increase Indent", ']'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleIndentOutdent(true); - } + public void actionPerformed(ActionEvent e) { + handleIndentOutdent(true); + } }); menu.add(item); item = Toolkit.newJMenuItem("Decrease Indent", '['); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleIndentOutdent(false); - } + public void actionPerformed(ActionEvent e) { + handleIndentOutdent(false); + } }); menu.add(item); @@ -800,55 +815,57 @@ public abstract class Editor extends JFrame implements RunnerListener { item = Toolkit.newJMenuItem("Find...", 'F'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (find == null) { - find = new FindReplace(Editor.this); + public void actionPerformed(ActionEvent e) { + if (find == null) { + find = new FindReplace(Editor.this); + } + //new FindReplace(Editor.this).show(); + find.setVisible(true); } - //new FindReplace(Editor.this).show(); - find.setVisible(true); - } - }); + }); menu.add(item); // TODO find next should only be enabled after a // search has actually taken place item = Toolkit.newJMenuItem("Find Next", 'G'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (find != null) { - find.findNext(); + public void actionPerformed(ActionEvent e) { + if (find != null) { + find.findNext(); + } } - } - }); + }); menu.add(item); item = Toolkit.newJMenuItemShift("Find Previous", 'G'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (find != null) { - find.findPrevious(); + public void actionPerformed(ActionEvent e) { + if (find != null) { + find.findPrevious(); + } } - } - }); + }); menu.add(item); // For Arduino and Mac, this should be command-E, but that currently conflicts with Export Applet item = Toolkit.newJMenuItemAlt("Use Selection for Find", 'F'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (find == null) { - find = new FindReplace(Editor.this); + public void actionPerformed(ActionEvent e) { + if (find == null) { + find = new FindReplace(Editor.this); + } + find.setFindText(getSelectedText()); } - find.setFindText(getSelectedText()); - } - }); + }); menu.add(item); return menu; } + abstract public JMenu buildSketchMenu(); + protected JMenu buildSketchMenu(JMenuItem[] runItems) { JMenuItem item; sketchMenu = new JMenu("Sketch"); @@ -863,26 +880,26 @@ public abstract class Editor extends JFrame implements RunnerListener { item = Toolkit.newJMenuItem("Show Sketch Folder", 'K'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - Base.openFolder(sketch.getFolder()); - } - }); + public void actionPerformed(ActionEvent e) { + Base.openFolder(sketch.getFolder()); + } + }); sketchMenu.add(item); item.setEnabled(Base.openFolderAvailable()); item = new JMenuItem("Add File..."); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - sketch.handleAddFile(); - } - }); + public void actionPerformed(ActionEvent e) { + sketch.handleAddFile(); + } + }); sketchMenu.add(item); sketchMenu.addSeparator(); // final Editor editorName = this; - - sketchMenu.addMenuListener(new MenuListener() { + + sketchMenu.addMenuListener(new MenuListener() { // Menu Listener that populates the menu only when the menu is opened List menuList = new ArrayList(); @@ -893,18 +910,17 @@ public abstract class Editor extends JFrame implements RunnerListener { JMenuItem item; for (final Editor editor : base.getEditors()) { //if (Editor.this.getSketch().getName().trim().contains(editor2.getSketch().getName().trim())) - if (getSketch().getMainFilePath().equals(editor.getSketch() - .getMainFilePath())) { + if (getSketch().getMainFilePath().equals(editor.getSketch().getMainFilePath())) { item = new JCheckBoxMenuItem(editor.getSketch().getName()); item.setSelected(true); } else { item = new JMenuItem(editor.getSketch().getName()); } - item.setText(editor.getSketch().getName() + " (" - + editor.getMode().getTitle() + ")"); + item.setText(editor.getSketch().getName() + + " (" + editor.getMode().getTitle() + ")"); // Action listener to bring the appropriate sketch in front - item.addActionListener(new ActionListener() { + item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -937,8 +953,10 @@ public abstract class Editor extends JFrame implements RunnerListener { return sketchMenu; } + abstract public void handleImportLibrary(String jarPath); + public JMenu getToolMenu() { if (toolsMenu == null) { rebuildToolMenu(); @@ -946,11 +964,13 @@ public abstract class Editor extends JFrame implements RunnerListener { return toolsMenu; } + // protected void rebuildToolList() { // coreTools = ToolContribution.list(Base.getToolsFolder(), true); // contribTools = ToolContribution.list(Base.getSketchbookToolsFolder(), true); // } + public void rebuildToolMenu() { if (toolsMenu == null) { toolsMenu = new JMenu("Tools"); @@ -976,6 +996,7 @@ public abstract class Editor extends JFrame implements RunnerListener { toolsMenu.add(item); } + // /** // * Attempt to init or run a Tool from the safety of a try/catch block that // * will report errors to the user. @@ -1007,7 +1028,8 @@ public abstract class Editor extends JFrame implements RunnerListener { // } // return false; // } - + + void addToolItem(final Tool tool, HashMap toolItems) { String title = tool.getMenuTitle(); final JMenuItem item = new JMenuItem(title); @@ -1018,24 +1040,24 @@ public abstract class Editor extends JFrame implements RunnerListener { tool.run(); } catch (NoSuchMethodError nsme) { - statusError("\"" + tool.getMenuTitle() + "\" is not" - + "compatible with this version of Processing"); + statusError("\"" + tool.getMenuTitle() + "\" is not" + + "compatible with this version of Processing"); //nsme.printStackTrace(); Base.log("Incompatible tool found during tool.run()", nsme); item.setEnabled(false); } catch (Exception ex) { - statusError("An error occurred inside \"" + tool.getMenuTitle() - + "\""); + statusError("An error occurred inside \"" + tool.getMenuTitle() + "\""); ex.printStackTrace(); item.setEnabled(false); - } + } } }); //menu.add(item); toolItems.put(title, item); } + protected void addTools(JMenu menu, ArrayList tools) { HashMap toolItems = new HashMap(); @@ -1044,35 +1066,31 @@ public abstract class Editor extends JFrame implements RunnerListener { tool.init(Editor.this); // If init() fails, the item won't be added to the menu addToolItem(tool, toolItems); - + // With the exceptions, we can't call statusError because the window // isn't completely set up yet. Also not gonna pop up a warning because // people may still be running different versions of Processing. // TODO Once the dust settles on 2.x, change this to Base.showError() // and open the Tools folder instead of showing System.err.println(). - + } catch (NoSuchMethodError nsme) { - System.err.println("\"" + tool.getMenuTitle() + "\" is not " - + "compatible with this version of Processing"); - System.err.println("The " + nsme.getMessage() - + " method no longer exists."); + System.err.println("\"" + tool.getMenuTitle() + "\" is not " + + "compatible with this version of Processing"); + System.err.println("The " + nsme.getMessage() + " method no longer exists."); Base.log("Incompatible Tool found during tool.init()", nsme); } catch (NoClassDefFoundError ncdfe) { - System.err.println("\"" + tool.getMenuTitle() + "\" is not " - + "compatible with this version of Processing"); - System.err.println("The " + ncdfe.getMessage() - + " class is no longer available."); + System.err.println("\"" + tool.getMenuTitle() + "\" is not " + + "compatible with this version of Processing"); + System.err.println("The " + ncdfe.getMessage() + " class is no longer available."); Base.log("Incompatible Tool found during tool.init()", ncdfe); } catch (Error err) { - System.err.println("An error occurred inside \"" + tool.getMenuTitle() - + "\""); + System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\""); err.printStackTrace(); } catch (Exception ex) { - System.err.println("An exception occurred inside \"" - + tool.getMenuTitle() + "\""); + System.err.println("An exception occurred inside \"" + tool.getMenuTitle() + "\""); ex.printStackTrace(); } } @@ -1087,6 +1105,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + /** * Override this if you want a special menu for your particular 'mode'. */ @@ -1094,6 +1113,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return null; } + protected void addToolMenuItem(JMenu menu, String className) { try { Class toolClass = Class.forName(className); @@ -1117,6 +1137,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + protected JMenu addInternalTools(JMenu menu) { // JMenuItem item; // item = createToolMenuItem("processing.app.tools.AutoFormatTool"); @@ -1154,37 +1175,54 @@ public abstract class Editor extends JFrame implements RunnerListener { return menu; } - /* - * // testing internal web server to serve up docs from a zip file item = new - * JMenuItem("Web Server Test"); item.addActionListener(new ActionListener() { - * public void actionPerformed(ActionEvent e) { //WebServer ws = new - * WebServer(); SwingUtilities.invokeLater(new Runnable() { public void run() - * { try { int port = - * WebServer.launch("/Users/fry/coconut/processing/build/shared/reference.zip" - * ); Base.openURL("http://127.0.0.1:" + port + "/reference/setup_.html"); - * - * } catch (IOException e1) { e1.printStackTrace(); } } }); } }); - * menu.add(item); - */ /* - * item = new JMenuItem("Browser Test"); item.addActionListener(new - * ActionListener() { public void actionPerformed(ActionEvent e) { - * //Base.openURL("http://processing.org/learning/gettingstarted/"); //JFrame - * browserFrame = new JFrame("Browser"); BrowserStartup bs = new - * BrowserStartup( - * "jar:file:/Users/fry/coconut/processing/build/shared/reference.zip!/reference/setup_.html" - * ); bs.initUI(); bs.launch(); } }); menu.add(item); - */ + // testing internal web server to serve up docs from a zip file + item = new JMenuItem("Web Server Test"); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + //WebServer ws = new WebServer(); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + int port = WebServer.launch("/Users/fry/coconut/processing/build/shared/reference.zip"); + Base.openURL("http://127.0.0.1:" + port + "/reference/setup_.html"); + + } catch (IOException e1) { + e1.printStackTrace(); + } + } + }); + } + }); + menu.add(item); + */ + + /* + item = new JMenuItem("Browser Test"); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + //Base.openURL("http://processing.org/learning/gettingstarted/"); + //JFrame browserFrame = new JFrame("Browser"); + BrowserStartup bs = new BrowserStartup("jar:file:/Users/fry/coconut/processing/build/shared/reference.zip!/reference/setup_.html"); + bs.initUI(); + bs.launch(); + } + }); + menu.add(item); + */ + abstract public JMenu buildHelpMenu(); + public void showReference(String filename) { File file = new File(mode.getReferenceFolder(), filename); // Prepend with file:// and also encode spaces & other characters Base.openURL(file.toURI().toString()); } + static public void showChanges() { // http://code.google.com/p/processing/issues/detail?id=1520 if (!Base.isCommandLine()) { @@ -1192,8 +1230,10 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + class UndoAction extends AbstractAction { public UndoAction() { super("Undo"); @@ -1219,8 +1259,7 @@ public abstract class Editor extends JFrame implements RunnerListener { updateUndoState(); redoAction.updateRedoState(); if (sketch != null) { - sketch.setModified(!getText().equals(sketch.getCurrentCode() - .getSavedProgram())); + sketch.setModified(!getText().equals(sketch.getCurrentCode().getSavedProgram())); } } @@ -1245,6 +1284,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + class RedoAction extends AbstractAction { public RedoAction() { super("Redo"); @@ -1269,8 +1309,7 @@ public abstract class Editor extends JFrame implements RunnerListener { updateRedoState(); undoAction.updateUndoState(); if (sketch != null) { - sketch.setModified(!getText().equals(sketch.getCurrentCode() - .getSavedProgram())); + sketch.setModified(!getText().equals(sketch.getCurrentCode().getSavedProgram())); } } @@ -1288,13 +1327,16 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + // these will be done in a more generic way soon, more like: // setHandler("action name", Runnable); // but for the time being, working out the kinks of how many things to // abstract from the editor in this fashion. + // public void setHandlers(Runnable runHandler, Runnable presentHandler, // Runnable stopHandler, // Runnable exportHandler, Runnable exportAppHandler) { @@ -1305,6 +1347,7 @@ public abstract class Editor extends JFrame implements RunnerListener { // this.exportAppHandler = exportAppHandler; // } + // public void resetHandlers() { // runHandler = new DefaultRunHandler(); // presentHandler = new DefaultPresentHandler(); @@ -1313,8 +1356,10 @@ public abstract class Editor extends JFrame implements RunnerListener { // exportAppHandler = new DefaultExportAppHandler(); // } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** * Gets the current sketch object. */ @@ -1322,9 +1367,10 @@ public abstract class Editor extends JFrame implements RunnerListener { return sketch; } + /** - * Get the JEditTextArea object for use (not recommended). This should only be - * used in obscure cases that really need to hack the internals of the + * Get the JEditTextArea object for use (not recommended). This should only + * be used in obscure cases that really need to hack the internals of the * JEditTextArea. Most tools should only interface via the get/set functions * found in this class. This will maintain compatibility with future releases, * which will not use JEditTextArea. @@ -1333,6 +1379,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea; } + /** * Get the contents of the current buffer. Used by the Sketch class. */ @@ -1340,6 +1387,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.getText(); } + /** * Get a range of text from the current buffer. */ @@ -1347,6 +1395,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.getText(start, stop - start); } + /** * Replace the entire contents of the front-most tab. */ @@ -1356,6 +1405,7 @@ public abstract class Editor extends JFrame implements RunnerListener { stopCompoundEdit(); } + public void insertText(String what) { startCompoundEdit(); int caret = getCaretOffset(); @@ -1364,9 +1414,10 @@ public abstract class Editor extends JFrame implements RunnerListener { stopCompoundEdit(); } + /** - * Called to update the text but not switch to a different set of code (which - * would affect the undo manager). + * Called to update the text but not switch to a different set of code + * (which would affect the undo manager). */ // public void setText2(String what, int start, int stop) { // beginCompoundEdit(); @@ -1381,14 +1432,17 @@ public abstract class Editor extends JFrame implements RunnerListener { // textarea.requestFocus(); // get the caret blinking // } + public String getSelectedText() { return textarea.getSelectedText(); } + public void setSelectedText(String what) { textarea.setSelectedText(what); } + public void setSelection(int start, int stop) { // make sure that a tool isn't asking for a bad location start = PApplet.constrain(start, 0, textarea.getDocumentLength()); @@ -1397,16 +1451,18 @@ public abstract class Editor extends JFrame implements RunnerListener { textarea.select(start, stop); } + /** - * Get the position (character offset) of the caret. With text selected, this - * will be the last character actually selected, no matter the direction of - * the selection. That is, if the user clicks and drags to select lines 7 up - * to 4, then the caret position will be somewhere on line four. + * Get the position (character offset) of the caret. With text selected, + * this will be the last character actually selected, no matter the direction + * of the selection. That is, if the user clicks and drags to select lines + * 7 up to 4, then the caret position will be somewhere on line four. */ public int getCaretOffset() { return textarea.getCaretPosition(); } + /** * True if some text is currently selected. */ @@ -1414,6 +1470,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.isSelectionActive(); } + /** * Get the beginning point of the current selection. */ @@ -1421,6 +1478,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.getSelectionStart(); } + /** * Get the end point of the current selection. */ @@ -1428,6 +1486,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.getSelectionStop(); } + /** * Get text for a specified line. */ @@ -1435,6 +1494,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.getLineText(line); } + /** * Replace the text on a specified line. */ @@ -1445,6 +1505,7 @@ public abstract class Editor extends JFrame implements RunnerListener { stopCompoundEdit(); } + /** * Get character offset for the start of a given line of text. */ @@ -1452,6 +1513,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.getLineStartOffset(line); } + /** * Get character offset for end of a given line of text. */ @@ -1459,6 +1521,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.getLineStopOffset(line); } + /** * Get the number of lines in the currently displayed buffer. */ @@ -1466,6 +1529,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return textarea.getLineCount(); } + /** * Use before a manipulating text to group editing operations together as a * single undo. Use stopCompoundEdit() once finished. @@ -1475,6 +1539,7 @@ public abstract class Editor extends JFrame implements RunnerListener { compoundEdit = new CompoundEdit(); } + /** * Use with startCompoundEdit() to group edit operations in a single undo. */ @@ -1490,20 +1555,23 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + public int getScrollPosition() { return textarea.getVerticalScrollPosition(); } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** - * Switch between tabs, this swaps out the Document object that's currently - * being manipulated. + * Switch between tabs, this swaps out the Document object + * that's currently being manipulated. */ protected void setCode(SketchCode code) { SyntaxDocument document = (SyntaxDocument) code.getDocument(); - if (document == null) { // this document not yet inited + if (document == null) { // this document not yet inited document = new SyntaxDocument(); code.setDocument(document); @@ -1544,33 +1612,34 @@ public abstract class Editor extends JFrame implements RunnerListener { // connect the undo listener to the editor document.addUndoableEditListener(new UndoableEditListener() { - public void undoableEditHappened(UndoableEditEvent e) { - // if an edit is in progress, reset the timer - if (endUndoEvent != null) { - endUndoEvent.cancel(); - endUndoEvent = null; - startTimerEvent(); - } + public void undoableEditHappened(UndoableEditEvent e) { + // if an edit is in progress, reset the timer + if (endUndoEvent != null) { + endUndoEvent.cancel(); + endUndoEvent = null; + startTimerEvent(); + } - // if this edit is just getting started, create a compound edit - if (compoundEdit == null) { - startCompoundEdit(); - startTimerEvent(); - } + // if this edit is just getting started, create a compound edit + if (compoundEdit == null) { + startCompoundEdit(); + startTimerEvent(); + } - compoundEdit.addEdit(e.getEdit()); - undoAction.updateUndoState(); - redoAction.updateRedoState(); - } - }); + compoundEdit.addEdit(e.getEdit()); + undoAction.updateUndoState(); + redoAction.updateRedoState(); + } + }); } // update the document object that's in use - textarea.setDocument(document, code.getSelectionStart(), - code.getSelectionStop(), code.getScrollPosition()); + textarea.setDocument(document, + code.getSelectionStart(), code.getSelectionStop(), + code.getScrollPosition()); // textarea.requestFocus(); // get the caret blinking - textarea.requestFocusInWindow(); // required for caret blinking + textarea.requestFocusInWindow(); // required for caret blinking this.undo = code.getUndo(); undoAction.updateUndoState(); @@ -1606,6 +1675,7 @@ public abstract class Editor extends JFrame implements RunnerListener { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** * Implements Edit → Cut. */ @@ -1614,6 +1684,7 @@ public abstract class Editor extends JFrame implements RunnerListener { sketch.setModified(true); } + /** * Implements Edit → Copy. */ @@ -1621,11 +1692,13 @@ public abstract class Editor extends JFrame implements RunnerListener { textarea.copy(); } + public void handleCopyAsHTML() { textarea.copyAsHTML(); statusNotice("Code formatted as HTML has been copied to the clipboard."); } + /** * Implements Edit → Paste. */ @@ -1634,6 +1707,7 @@ public abstract class Editor extends JFrame implements RunnerListener { sketch.setModified(true); } + /** * Implements Edit → Select All. */ @@ -1647,69 +1721,88 @@ public abstract class Editor extends JFrame implements RunnerListener { // * with the line beneath // */ /* - * public void handleMoveLines(boolean moveUp) { startCompoundEdit(); - * - * int startLine = textarea.getSelectionStartLine(); int stopLine = - * textarea.getSelectionStopLine(); - * - * // if more than one line is selected and none of the characters of the end - * // line are selected, don't move that line if (startLine != stopLine && - * textarea.getSelectionStop() == textarea.getLineStartOffset(stopLine)) - * stopLine--; - * - * int replacedLine = moveUp ? startLine - 1 : stopLine + 1; if (replacedLine - * < 0 || replacedLine >= textarea.getLineCount()) return; - * - * final String source = getText(); - * - * int replaceStart = textarea.getLineStartOffset(replacedLine); int - * replaceEnd = textarea.getLineStopOffset(replacedLine); if (replaceEnd == - * source.length() + 1) replaceEnd--; - * - * int selectionStart = textarea.getLineStartOffset(startLine); int - * selectionEnd = textarea.getLineStopOffset(stopLine); if (selectionEnd == - * source.length() + 1) selectionEnd--; - * - * String replacedText = source.substring(replaceStart, replaceEnd); String - * selectedText = source.substring(selectionStart, selectionEnd); if - * (replacedLine == textarea.getLineCount() - 1) { replacedText += "\n"; - * selectedText = selectedText.substring(0, selectedText.length() - 1); } else - * if (stopLine == textarea.getLineCount() - 1) { selectedText += "\n"; - * replacedText = replacedText.substring(0, replacedText.length() - 1); } - * - * int newSelectionStart, newSelectionEnd; if (moveUp) { // Change the - * selection, then change the line above textarea.select(selectionStart, - * selectionEnd); textarea.setSelectedText(replacedText); - * - * textarea.select(replaceStart, replaceEnd); - * textarea.setSelectedText(selectedText); - * - * newSelectionStart = textarea.getLineStartOffset(startLine - 1); - * newSelectionEnd = textarea.getLineStopOffset(stopLine - 1) - 1; } else { // - * Change the line beneath, then change the selection - * textarea.select(replaceStart, replaceEnd); - * textarea.setSelectedText(selectedText); - * - * textarea.select(selectionStart, selectionEnd); - * textarea.setSelectedText(replacedText); - * - * newSelectionStart = textarea.getLineStartOffset(startLine + 1); - * newSelectionEnd = textarea.getLineStopOffset(stopLine + 1) - 1; } - * - * textarea.select(newSelectionStart, newSelectionEnd); stopCompoundEdit(); } - */ + public void handleMoveLines(boolean moveUp) { + startCompoundEdit(); + + int startLine = textarea.getSelectionStartLine(); + int stopLine = textarea.getSelectionStopLine(); + + // if more than one line is selected and none of the characters of the end + // line are selected, don't move that line + if (startLine != stopLine + && textarea.getSelectionStop() == textarea.getLineStartOffset(stopLine)) + stopLine--; + + int replacedLine = moveUp ? startLine - 1 : stopLine + 1; + if (replacedLine < 0 || replacedLine >= textarea.getLineCount()) + return; + + final String source = getText(); + + int replaceStart = textarea.getLineStartOffset(replacedLine); + int replaceEnd = textarea.getLineStopOffset(replacedLine); + if (replaceEnd == source.length() + 1) + replaceEnd--; + + int selectionStart = textarea.getLineStartOffset(startLine); + int selectionEnd = textarea.getLineStopOffset(stopLine); + if (selectionEnd == source.length() + 1) + selectionEnd--; + + String replacedText = source.substring(replaceStart, replaceEnd); + String selectedText = source.substring(selectionStart, selectionEnd); + if (replacedLine == textarea.getLineCount() - 1) { + replacedText += "\n"; + selectedText = selectedText.substring(0, selectedText.length() - 1); + } else if (stopLine == textarea.getLineCount() - 1) { + selectedText += "\n"; + replacedText = replacedText.substring(0, replacedText.length() - 1); + } + + int newSelectionStart, newSelectionEnd; + if (moveUp) { + // Change the selection, then change the line above + textarea.select(selectionStart, selectionEnd); + textarea.setSelectedText(replacedText); + + textarea.select(replaceStart, replaceEnd); + textarea.setSelectedText(selectedText); + + newSelectionStart = textarea.getLineStartOffset(startLine - 1); + newSelectionEnd = textarea.getLineStopOffset(stopLine - 1) - 1; + } else { + // Change the line beneath, then change the selection + textarea.select(replaceStart, replaceEnd); + textarea.setSelectedText(selectedText); + + textarea.select(selectionStart, selectionEnd); + textarea.setSelectedText(replacedText); + + newSelectionStart = textarea.getLineStartOffset(startLine + 1); + newSelectionEnd = textarea.getLineStopOffset(stopLine + 1) - 1; + } + + textarea.select(newSelectionStart, newSelectionEnd); + stopCompoundEdit(); + } + */ + /* - * public void handleDeleteLines() { int startLine = - * textarea.getSelectionStartLine(); int stopLine = - * textarea.getSelectionStopLine(); - * - * int start = textarea.getLineStartOffset(startLine); int end = - * textarea.getLineStopOffset(stopLine); if (end == getText().length() + 1) - * end--; - * - * textarea.select(start, end); textarea.setSelectedText(""); } - */ + public void handleDeleteLines() { + int startLine = textarea.getSelectionStartLine(); + int stopLine = textarea.getSelectionStopLine(); + + int start = textarea.getLineStartOffset(startLine); + int end = textarea.getLineStopOffset(stopLine); + if (end == getText().length() + 1) + end--; + + textarea.select(start, end); + textarea.setSelectedText(""); + } + */ + public void handleAutoFormat() { final String source = getText(); @@ -1718,7 +1811,7 @@ public abstract class Editor extends JFrame implements RunnerListener { final String formattedText = createFormatter().format(source); // save current (rough) selection point int selectionEnd = getSelectionStop(); - + // boolean wasVisible = // textarea.getSelectionStopLine() >= textarea.getFirstLine() && // textarea.getSelectionStopLine() < textarea.getLastLine(); @@ -1736,7 +1829,7 @@ public abstract class Editor extends JFrame implements RunnerListener { int scrollPos = textarea.getVerticalScrollPosition(); setText(formattedText); setSelection(selectionEnd, selectionEnd); - + // Put the scrollbar position back, otherwise it jumps on each format. // Since we're not doing a good job of maintaining position anyway, // a more complicated workaround here is fairly pointless. @@ -1761,8 +1854,10 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + abstract public String getCommentPrefix(); + protected void handleCommentUncomment() { startCompoundEdit(); @@ -1822,14 +1917,17 @@ public abstract class Editor extends JFrame implements RunnerListener { sketch.setModified(true); } + public void handleIndent() { handleIndentOutdent(true); } + public void handleOutdent() { handleIndentOutdent(false); } + public void handleIndentOutdent(boolean indent) { int tabSize = Preferences.getInteger("editor.tabs.size"); String tabString = Editor.EMPTY.substring(0, tabSize); @@ -1857,7 +1955,7 @@ public abstract class Editor extends JFrame implements RunnerListener { textarea.select(location, location); textarea.setSelectedText(tabString); - } else { // outdent + } else { // outdent int last = Math.min(location + tabSize, textarea.getDocumentLength()); textarea.select(location, last); // Don't eat code if it's not indented @@ -1874,6 +1972,7 @@ public abstract class Editor extends JFrame implements RunnerListener { sketch.setModified(true); } + static public boolean checkParen(char[] array, int index, int stop) { // boolean paren = false; // int stepper = i + 1; @@ -1910,14 +2009,15 @@ public abstract class Editor extends JFrame implements RunnerListener { return false; } + protected boolean functionable(char c) { return (c == '_') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } + /** - * Check the current selection for reference. If no selection is active, + * Check the current selection for reference. If no selection is active, * expand the current selection. - * * @return */ protected String referenceCheck(boolean selectIfFound) { @@ -1929,7 +2029,7 @@ public abstract class Editor extends JFrame implements RunnerListener { start = temp; } char[] c = textarea.getText().toCharArray(); - + // System.out.println("checking reference"); if (start == stop) { while (start > 0 && functionable(c[start - 1])) { @@ -1951,7 +2051,8 @@ public abstract class Editor extends JFrame implements RunnerListener { } return ref; } - + + protected void handleFindReference() { String ref = referenceCheck(true); if (ref != null) { @@ -1965,38 +2066,55 @@ public abstract class Editor extends JFrame implements RunnerListener { } } } - + + /* - * protected void handleFindReference() { String text = - * textarea.getSelectedText().trim(); - * - * if (text.length() == 0) { - * statusNotice("First select a word to find in the reference."); - * - * } else { char[] c = textarea.getText().toCharArray(); int after = - * Math.max(textarea.getSelectionStart(), textarea.getSelectionStop()); if - * (checkParen(c, after, c.length)) { text += "_"; - * System.out.println("looking up ref for " + text); } String referenceFile = - * mode.lookupReference(text); System.out.println("reference file is " + - * referenceFile); if (referenceFile == null) { - * statusNotice("No reference available for \"" + text + "\""); } else { - * showReference(referenceFile + ".html"); } } } - * - * - * protected void handleFindReference() { String text = - * textarea.getSelectedText().trim(); - * - * if (text.length() == 0) { - * statusNotice("First select a word to find in the reference."); - * - * } else { String referenceFile = mode.lookupReference(text); - * //System.out.println("reference file is " + referenceFile); if - * (referenceFile == null) { statusNotice("No reference available for \"" + - * text + "\""); } else { showReference(referenceFile + ".html"); } } } - */ + protected void handleFindReference() { + String text = textarea.getSelectedText().trim(); + + if (text.length() == 0) { + statusNotice("First select a word to find in the reference."); + + } else { + char[] c = textarea.getText().toCharArray(); + int after = Math.max(textarea.getSelectionStart(), textarea.getSelectionStop()); + if (checkParen(c, after, c.length)) { + text += "_"; + System.out.println("looking up ref for " + text); + } + String referenceFile = mode.lookupReference(text); + System.out.println("reference file is " + referenceFile); + if (referenceFile == null) { + statusNotice("No reference available for \"" + text + "\""); + } else { + showReference(referenceFile + ".html"); + } + } + } + + + protected void handleFindReference() { + String text = textarea.getSelectedText().trim(); + + if (text.length() == 0) { + statusNotice("First select a word to find in the reference."); + + } else { + String referenceFile = mode.lookupReference(text); + //System.out.println("reference file is " + referenceFile); + if (referenceFile == null) { + statusNotice("No reference available for \"" + text + "\""); + } else { + showReference(referenceFile + ".html"); + } + } + } + */ + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** * Set the location of the sketch run window. Used by Runner to update the * Editor about window drag events while the sketch is running. @@ -2005,6 +2123,7 @@ public abstract class Editor extends JFrame implements RunnerListener { sketchWindowLocation = p; } + /** * Get the last location of the sketch's run window. Used by Runner to make * the window show up in the same location as when it was last closed. @@ -2013,45 +2132,42 @@ public abstract class Editor extends JFrame implements RunnerListener { return sketchWindowLocation; } + // public void internalCloseRunner() { // mode.internalCloseRunner(this); // } + /** * Check if the sketch is modified and ask user to save changes. - * * @return false if canceling the close/quit operation */ protected boolean checkModified() { - boolean ret; - if (!sketch.isModified()){ - stopReloadThread = true; - return true; - } + if (!sketch.isModified()) return true; // As of Processing 1.0.10, this always happens immediately. // http://dev.processing.org/bugs/show_bug.cgi?id=1456 // With Java 7u40 on OS X, need to bring the window forward. toFront(); - + String prompt = "Save changes to " + sketch.getName() + "? "; if (!Base.isMacOS()) { - int result = JOptionPane - .showConfirmDialog(this, prompt, "Close", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE); + int result = + JOptionPane.showConfirmDialog(this, prompt, "Close", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); if (result == JOptionPane.YES_OPTION) { - ret = handleSave(true); + return handleSave(true); } else if (result == JOptionPane.NO_OPTION) { - ret = true; // ok to continue + return true; // ok to continue - } else if (result == JOptionPane.CANCEL_OPTION - || result == JOptionPane.CLOSED_OPTION) { - ret = false; + } else if (result == JOptionPane.CANCEL_OPTION || + result == JOptionPane.CLOSED_OPTION) { + return false; } else { throw new IllegalStateException(); @@ -2068,17 +2184,20 @@ public abstract class Editor extends JFrame implements RunnerListener { // Pane formatting adapted from the quaqua guide // http://www.randelshofer.ch/quaqua/guide/joptionpane.html - JOptionPane pane = new JOptionPane(" " - + " " - + "Do you want to save changes to this sketch
" - + " before closing?
" - + "

If you don't save, your changes will be lost.", - JOptionPane.QUESTION_MESSAGE); + JOptionPane pane = + new JOptionPane(" " + + " " + + "Do you want to save changes to this sketch
" + + " before closing?
" + + "

If you don't save, your changes will be lost.", + JOptionPane.QUESTION_MESSAGE); - String[] options = new String[] { "Save", "Cancel", "Don't Save" }; + String[] options = new String[] { + "Save", "Cancel", "Don't Save" + }; pane.setOptions(options); // highlight the safest option ala apple hig @@ -2093,26 +2212,22 @@ public abstract class Editor extends JFrame implements RunnerListener { dialog.setVisible(true); Object result = pane.getValue(); - if (result == options[0]) { // save (and close/quit) - ret = handleSave(true); + if (result == options[0]) { // save (and close/quit) + return handleSave(true); - } else if (result == options[2]) { // don't save (still close/quit) - ret = true; + } else if (result == options[2]) { // don't save (still close/quit) + return true; - } else { // cancel? - ret = false; + } else { // cancel? + return false; } } - if (ret) { - //the sketch is closing - stopReloadThread = true; - } - return ret; } + /** - * Open a sketch from a particular path, but don't check to save changes. Used - * by Sketch.saveAs() to re-open a sketch after the "Save As" + * Open a sketch from a particular path, but don't check to save changes. + * Used by Sketch.saveAs() to re-open a sketch after the "Save As" */ // protected void handleOpenUnchecked(String path, int codeIndex, // int selStart, int selStop, int scrollPos) { @@ -2127,6 +2242,7 @@ public abstract class Editor extends JFrame implements RunnerListener { // textarea.setScrollPosition(scrollPos); // } + /** * Second stage of open, occurs after having checked to see if the * modifications (if any) to the previous sketch need to be saved. @@ -2155,32 +2271,37 @@ public abstract class Editor extends JFrame implements RunnerListener { + mode.getDefaultExtension(), null); return false; } else { - final String properParent = file.getName().substring(0, - file.getName() - .lastIndexOf('.')); - + final String properParent = + file.getName().substring(0, file.getName().lastIndexOf('.')); + Object[] options = { "OK", "Cancel" }; - String prompt = "The file \"" + file.getName() - + "\" needs to be inside\n" + "a sketch folder named \"" + properParent - + "\".\n" + "Create this folder, move the file, and continue?"; + String prompt = + "The file \"" + file.getName() + "\" needs to be inside\n" + + "a sketch folder named \"" + properParent + "\".\n" + + "Create this folder, move the file, and continue?"; - int result = JOptionPane.showOptionDialog(this, prompt, "Moving", + int result = JOptionPane.showOptionDialog(this, + prompt, + "Moving", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, - null, options, options[0]); + null, + options, + options[0]); if (result == JOptionPane.YES_OPTION) { // create properly named folder File properFolder = new File(file.getParent(), properParent); if (properFolder.exists()) { - Base.showWarning("Error", "A folder named \"" + properParent + "\" " - + "already exists. Can't open sketch.", null); + Base.showWarning("Error", + "A folder named \"" + properParent + "\" " + + "already exists. Can't open sketch.", null); return false; } if (!properFolder.mkdirs()) { //throw new IOException("Couldn't create sketch folder"); - Base - .showWarning("Error", "Could not create the sketch folder.", null); + Base.showWarning("Error", + "Could not create the sketch folder.", null); return false; } // copy the sketch inside @@ -2211,7 +2332,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return false; } initFileChangeListener(); - + header.rebuild(); updateTitle(); // Disable untitled setting from previous document, if any @@ -2231,29 +2352,14 @@ public abstract class Editor extends JFrame implements RunnerListener { // return false; // } } - - //true when the file is saved, before the next scan for updates - private boolean saved; + private boolean didReload; - - //TODO set to appropriate value - private boolean reloadEnabled=true; - - //the time between polls in ms - private final long FILE_CHECK_DELAY = 1000; - - private boolean stopReloadThread = false; - + //the key which is being used to poll the fs for changes private WatchKey key = null; private void initFileChangeListener() { - //if it is disabled, don't bother starting one - if (!reloadEnabled) { - return; - } - try { WatchService watchService = FileSystems.getDefault().newWatchService(); key = sketch.getFolder().toPath() @@ -2270,38 +2376,24 @@ public abstract class Editor extends JFrame implements RunnerListener { //if the key is null for some reason, don't bother attaching a listener to it, they can deal without one if (finKey != null) { //the key can now be polled for changes in the files - stopReloadThread = false; - Thread th = new Thread(new Runnable() { + addFocusListener(new FocusListener() { @Override - public void run() { - //polls for changes to the directory - while (true) { - try { - //check every .1s if the file has changed - Thread.sleep(FILE_CHECK_DELAY); - } catch (InterruptedException e) { - } - List> events = finKey.pollEvents(); - - //called when a sketch is closed - if (stopReloadThread) { - break; - } - //if it is disabled after being started, stop it - if (!reloadEnabled) { - break; - } - - processFileEvents(events); - - //if the directory was deleted, then quit the loop - if (!finKey.isValid()) { - break; - } + public void focusLost(FocusEvent e) { + //do nothing + } + + @Override + public void focusGained(FocusEvent e) { + //if the directory was deleted, then don't scan + if (!finKey.isValid()) { + return; } + + List> events = finKey.pollEvents(); + processFileEvents(events); } }); - th.start(); + } } @@ -2319,12 +2411,9 @@ public abstract class Editor extends JFrame implements RunnerListener { //due to some weird shit, if a file was editted in gedit, the context is .goutputstream-XXXXX //this makes things.... complicated //System.out.println(e.context()); - - //if the file was saved, don't prompt anything - if (saved) - break; + //if we already reloaded in this cycle, then don't reload again - if (didReload) { + if (didReload){ break; } if (e.kind().equals(StandardWatchEventKinds.ENTRY_MODIFY)) { @@ -2346,12 +2435,12 @@ public abstract class Editor extends JFrame implements RunnerListener { //for now, do nothing } } - saved = false; } + /** - * Set the title of the PDE window based on the current sketch, i.e. something - * like "sketch_070752a - Processing 0126" + * Set the title of the PDE window based on the current sketch, i.e. + * something like "sketch_070752a - Processing 0126" */ public void updateTitle() { setTitle(sketch.getName() + " | Processing " + Base.getVersionName()); @@ -2366,14 +2455,15 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + /** - * Actually handle the save command. If 'immediately' is set to false, this - * will happen in another thread so that the message area will update and the - * save button will stay highlighted while the save is happening. If - * 'immediately' is true, then it will happen immediately. This is used during - * a quit, because invokeLater() won't run properly while a quit is happening. - * This fixes Bug - * 276. + * Actually handle the save command. If 'immediately' is set to false, + * this will happen in another thread so that the message area + * will update and the save button will stay highlighted while the + * save is happening. If 'immediately' is true, then it will happen + * immediately. This is used during a quit, because invokeLater() + * won't run properly while a quit is happening. This fixes + * Bug 276. */ public boolean handleSave(boolean immediately) { // handleStop(); // 0136 @@ -2387,19 +2477,19 @@ public abstract class Editor extends JFrame implements RunnerListener { } else { EventQueue.invokeLater(new Runnable() { - public void run() { - handleSaveImpl(); - } - }); + public void run() { + handleSaveImpl(); + } + }); } return true; } + protected void handleSaveImpl() { statusNotice("Saving..."); try { if (sketch.save()) { - saved = true; statusNotice("Done Saving."); } else { statusEmpty(); @@ -2416,6 +2506,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } } + public boolean handleSaveAs() { statusNotice("Saving..."); try { @@ -2436,6 +2527,7 @@ public abstract class Editor extends JFrame implements RunnerListener { return true; } + /** * Handler for File → Page Setup. */ @@ -2451,6 +2543,7 @@ public abstract class Editor extends JFrame implements RunnerListener { //System.out.println("page format is " + pageFormat); } + /** * Handler for File → Print. */ @@ -2484,17 +2577,17 @@ public abstract class Editor extends JFrame implements RunnerListener { //printerJob = null; // clear this out? } + /** - * Grab current contents of the sketch window, advance the console, stop any - * other running sketches... not in that order. + * Grab current contents of the sketch window, advance the console, + * stop any other running sketches... not in that order. */ public void prepareRun() { internalCloseRunner(); statusEmpty(); // do this to advance/clear the terminal window / dos prompt / etc - for (int i = 0; i < 10; i++) - System.out.println(); + for (int i = 0; i < 10; i++) System.out.println(); // clear the console on each run, unless the user doesn't want to if (Preferences.getBoolean("console.auto_clear")) { @@ -2515,16 +2608,20 @@ public abstract class Editor extends JFrame implements RunnerListener { // } } + /** - * Halt the current runner for whatever reason. Might be the VM dying, the - * window closing, an error... + * Halt the current runner for whatever reason. Might be the VM dying, + * the window closing, an error... */ abstract public void internalCloseRunner(); + abstract public void deactivateRun(); + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** * Show an error in the status bar. */ @@ -2534,6 +2631,7 @@ public abstract class Editor extends JFrame implements RunnerListener { // toolbar.deactivate(EditorToolbar.RUN); } + /** * Show an exception in the editor status bar. */ @@ -2588,6 +2686,7 @@ public abstract class Editor extends JFrame implements RunnerListener { // e.printStackTrace(); } + /** * Show a notice message in the editor status bar. */ @@ -2595,25 +2694,29 @@ public abstract class Editor extends JFrame implements RunnerListener { status.notice(msg); } + public void clearNotice(String msg) { if (status.message.equals(msg)) { statusEmpty(); } } + /** * Returns the current notice message in the editor status bar. */ - public String getStatusMessage() { + public String getStatusMessage(){ return status.message; } - + + /** - * Returns the current mode of the editor status bar: NOTICE, ERR or EDIT. + * Returns the current mode of the editor status bar: NOTICE, ERR or EDIT. */ - public int getStatusMode() { + public int getStatusMode(){ return status.mode; } + /** * Clear the status area. @@ -2622,69 +2725,73 @@ public abstract class Editor extends JFrame implements RunnerListener { statusNotice(EMPTY); } + public void startIndeterminate() { status.startIndeterminate(); } + public void stopIndeterminate() { status.stopIndeterminate(); } + public void statusHalt() { // stop called by someone else } + public boolean isHalted() { return false; } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** * Returns the edit popup menu. */ class TextAreaPopup extends JPopupMenu { JMenuItem cutItem; - JMenuItem copyItem; - JMenuItem discourseItem; - JMenuItem referenceItem; + public TextAreaPopup() { JMenuItem item; cutItem = new JMenuItem("Cut"); cutItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCut(); - } + public void actionPerformed(ActionEvent e) { + handleCut(); + } }); this.add(cutItem); copyItem = new JMenuItem("Copy"); copyItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCopy(); - } - }); + public void actionPerformed(ActionEvent e) { + handleCopy(); + } + }); this.add(copyItem); discourseItem = new JMenuItem("Copy as HTML"); discourseItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCopyAsHTML(); - } - }); + public void actionPerformed(ActionEvent e) { + handleCopyAsHTML(); + } + }); this.add(discourseItem); item = new JMenuItem("Paste"); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handlePaste(); - } - }); + public void actionPerformed(ActionEvent e) { + handlePaste(); + } + }); this.add(item); item = new JMenuItem("Select All"); @@ -2699,25 +2806,25 @@ public abstract class Editor extends JFrame implements RunnerListener { item = new JMenuItem("Comment/Uncomment"); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCommentUncomment(); - } + public void actionPerformed(ActionEvent e) { + handleCommentUncomment(); + } }); this.add(item); item = new JMenuItem("Increase Indent"); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleIndentOutdent(true); - } + public void actionPerformed(ActionEvent e) { + handleIndentOutdent(true); + } }); this.add(item); item = new JMenuItem("Decrease Indent"); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleIndentOutdent(false); - } + public void actionPerformed(ActionEvent e) { + handleIndentOutdent(false); + } }); this.add(item); @@ -2725,10 +2832,10 @@ public abstract class Editor extends JFrame implements RunnerListener { referenceItem = new JMenuItem("Find in Reference"); referenceItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleFindReference(); - } - }); + public void actionPerformed(ActionEvent e) { + handleFindReference(); + } + }); this.add(referenceItem); } @@ -2753,7 +2860,7 @@ public abstract class Editor extends JFrame implements RunnerListener { cutItem.setEnabled(active); copyItem.setEnabled(active); discourseItem.setEnabled(active); - + referenceItem.setEnabled(referenceCheck(false) != null); super.show(component, x, y); }