diff --git a/app/.classpath b/app/.classpath
index f32ff129bf7..b3104a0644e 100644
--- a/app/.classpath
+++ b/app/.classpath
@@ -41,7 +41,7 @@
-
+
diff --git a/app/lib/rsyntaxtextarea-2.5.8.1+arduino.jar b/app/lib/rsyntaxtextarea-2.5.8.1+arduino.jar
deleted file mode 100644
index 66e48d20aa4..00000000000
Binary files a/app/lib/rsyntaxtextarea-2.5.8.1+arduino.jar and /dev/null differ
diff --git a/app/lib/rsyntaxtextarea-2.6.1.jar b/app/lib/rsyntaxtextarea-2.6.1.jar
new file mode 100644
index 00000000000..b834e2d412b
Binary files /dev/null and b/app/lib/rsyntaxtextarea-2.6.1.jar differ
diff --git a/app/src/processing/app/CaretAwareUndoableEdit.java b/app/src/processing/app/CaretAwareUndoableEdit.java
deleted file mode 100644
index b0983ad2f04..00000000000
--- a/app/src/processing/app/CaretAwareUndoableEdit.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package processing.app;
-
-import processing.app.syntax.SketchTextArea;
-
-import javax.swing.undo.CannotRedoException;
-import javax.swing.undo.CannotUndoException;
-import javax.swing.undo.UndoableEdit;
-
-public class CaretAwareUndoableEdit implements UndoableEdit {
-
- private final UndoableEdit undoableEdit;
- private final int caretPosition;
-
- public CaretAwareUndoableEdit(UndoableEdit undoableEdit, SketchTextArea textArea) {
- this.undoableEdit = undoableEdit;
- this.caretPosition = textArea.getCaretPosition();
- }
-
- @Override
- public void undo() throws CannotUndoException {
- undoableEdit.undo();
- }
-
- @Override
- public boolean canUndo() {
- return undoableEdit.canUndo();
- }
-
- @Override
- public void redo() throws CannotRedoException {
- undoableEdit.redo();
- }
-
- @Override
- public boolean canRedo() {
- return undoableEdit.canRedo();
- }
-
- @Override
- public void die() {
- undoableEdit.die();
- }
-
- @Override
- public boolean addEdit(UndoableEdit undoableEdit) {
- return this.undoableEdit.addEdit(undoableEdit);
- }
-
- @Override
- public boolean replaceEdit(UndoableEdit undoableEdit) {
- return this.undoableEdit.replaceEdit(undoableEdit);
- }
-
- @Override
- public boolean isSignificant() {
- return undoableEdit.isSignificant();
- }
-
- @Override
- public String getPresentationName() {
- return undoableEdit.getPresentationName();
- }
-
- @Override
- public String getUndoPresentationName() {
- return undoableEdit.getUndoPresentationName();
- }
-
- @Override
- public String getRedoPresentationName() {
- return undoableEdit.getRedoPresentationName();
- }
-
- public int getCaretPosition() {
- return caretPosition;
- }
-}
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index c7e60c35f2f..9ee54d8024c 100644
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -33,6 +33,7 @@
import jssc.SerialPortException;
import processing.app.debug.RunnerException;
import processing.app.forms.PasswordAuthorizationDialog;
+import processing.app.helpers.ActionWrapper;
import processing.app.helpers.Keys;
import processing.app.helpers.OSUtils;
import processing.app.helpers.PreferencesMapException;
@@ -44,9 +45,9 @@
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.BadLocationException;
-import javax.swing.undo.CannotRedoException;
-import javax.swing.undo.CannotUndoException;
-import javax.swing.undo.UndoManager;
+import org.fife.ui.rtextarea.RTextArea;
+import org.fife.ui.rtextarea.RecordableTextAction;
+
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
@@ -182,12 +183,6 @@ public boolean test(SketchController sketch) {
//boolean presenting;
private boolean uploading;
- // undo fellers
- private JMenuItem undoItem;
- private JMenuItem redoItem;
- protected UndoAction undoAction;
- protected RedoAction redoAction;
-
private FindReplace find;
Runnable runHandler;
@@ -1265,43 +1260,58 @@ public void actionPerformed(ActionEvent e) {
return menu;
}
+ /**
+ * Wrapper around RSyntaxTextArea's RecordableTextActions. Normally,
+ * these actions use the event source, or the most recently focused
+ * component to find the text area to work on, but this does not
+ * always work. This wrapper makes them always work on the currently
+ * selected tab instead.
+ */
+ class RstaActionWrapper extends ActionWrapper {
+ RstaActionWrapper(RecordableTextAction action) {
+ super(action);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ((RecordableTextAction) getWrappedAction()).actionPerformedImpl(e, getCurrentTab().getTextArea());
+ }
+ }
private JMenu buildEditMenu() {
JMenu menu = new JMenu(tr("Edit"));
menu.setName("menuEdit");
menu.setMnemonic(KeyEvent.VK_E);
- undoItem = newJMenuItem(tr("Undo"), 'Z');
+ // Create a dummy RTextArea, to force it to create the static list
+ // of actions accessible through RTextArea.getAction().
+ new RTextArea();
+
+ RecordableTextAction undoAction = RTextArea.getAction(RTextArea.UNDO_ACTION);
+ JMenuItem undoItem = new JMenuItem(new RstaActionWrapper(undoAction));
undoItem.setName("menuEditUndo");
- undoItem.addActionListener(undoAction = new UndoAction());
menu.add(undoItem);
- if (!OSUtils.isMacOS()) {
- redoItem = newJMenuItem(tr("Redo"), 'Y');
- } else {
- redoItem = newJMenuItemShift(tr("Redo"), 'Z');
- }
+ RecordableTextAction redoAction = RTextArea.getAction(RTextArea.REDO_ACTION);
+ JMenuItem redoItem = new JMenuItem(new RstaActionWrapper(redoAction));
redoItem.setName("menuEditRedo");
- redoItem.addActionListener(redoAction = new RedoAction());
menu.add(redoItem);
+ // RSTA defaults to Ctrl-Y for redo, but convention on OSX is Ctrl-Shift-Z
+ // This might not be the best place, but it works.
+ if (OSUtils.isMacOS()) {
+ int mods = SHORTCUT_KEY_MASK | ActionEvent.SHIFT_MASK;
+ redoAction.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, mods));
+ }
+
menu.addSeparator();
- JMenuItem cutItem = newJMenuItem(tr("Cut"), 'X');
- cutItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- getCurrentTab().handleCut();
- }
- });
- menu.add(cutItem);
+ RecordableTextAction cutAction = RTextArea.getAction(RTextArea.CUT_ACTION);
+ menu.add(new JMenuItem(new RstaActionWrapper(cutAction)));
+
+ RecordableTextAction copyAction = RTextArea.getAction(RTextArea.COPY_ACTION);
+ menu.add(new JMenuItem(new RstaActionWrapper(copyAction)));
- JMenuItem copyItem = newJMenuItem(tr("Copy"), 'C');
- copyItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- getCurrentTab().getTextArea().copy();
- }
- });
- menu.add(copyItem);
JMenuItem copyForumItem = newJMenuItemShift(tr("Copy for Forum"), 'C');
copyForumItem.addActionListener(new ActionListener() {
@@ -1319,21 +1329,11 @@ public void actionPerformed(ActionEvent e) {
});
menu.add(copyHTMLItem);
- JMenuItem pasteItem = newJMenuItem(tr("Paste"), 'V');
- pasteItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- getCurrentTab().handlePaste();
- }
- });
- menu.add(pasteItem);
+ RecordableTextAction pasteAction = RTextArea.getAction(RTextArea.PASTE_ACTION);
+ menu.add(new JMenuItem(new RstaActionWrapper(pasteAction)));
- JMenuItem selectAllItem = newJMenuItem(tr("Select All"), 'A');
- selectAllItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- getCurrentTab().handleSelectAll();
- }
- });
- menu.add(selectAllItem);
+ RecordableTextAction selectAllAction = RTextArea.getAction(RTextArea.SELECT_ALL_ACTION);
+ menu.add(new JMenuItem(new RstaActionWrapper(selectAllAction)));
JMenuItem gotoLine = newJMenuItem(tr("Go to line..."), 'L');
gotoLine.addActionListener(e -> {
@@ -1422,21 +1422,6 @@ public void actionPerformed(ActionEvent e) {
menu.add(useSelectionForFindItem);
}
- menu.addMenuListener(new MenuListener() {
- @Override
- public void menuSelected(MenuEvent e) {
- boolean enabled = getCurrentTab().getSelectedText() != null;
- cutItem.setEnabled(enabled);
- copyItem.setEnabled(enabled);
- }
-
- @Override
- public void menuDeselected(MenuEvent e) {}
-
- @Override
- public void menuCanceled(MenuEvent e) {}
- });
-
return menu;
}
@@ -1474,75 +1459,6 @@ private static JMenuItem newJMenuItemAlt(String title, int what) {
return menuItem;
}
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- class UndoAction extends AbstractAction {
- public UndoAction() {
- super("Undo");
- this.setEnabled(false);
- }
-
- public void actionPerformed(ActionEvent e) {
- try {
- getCurrentTab().handleUndo();
- } catch (CannotUndoException ex) {
- //System.out.println("Unable to undo: " + ex);
- //ex.printStackTrace();
- }
- }
-
- protected void updateUndoState() {
- UndoManager undo = getCurrentTab().getUndoManager();
-
- if (undo.canUndo()) {
- this.setEnabled(true);
- undoItem.setEnabled(true);
- undoItem.setText(undo.getUndoPresentationName());
- putValue(Action.NAME, undo.getUndoPresentationName());
- } else {
- this.setEnabled(false);
- undoItem.setEnabled(false);
- undoItem.setText(tr("Undo"));
- putValue(Action.NAME, "Undo");
- }
- }
- }
-
-
- class RedoAction extends AbstractAction {
- public RedoAction() {
- super("Redo");
- this.setEnabled(false);
- }
-
- public void actionPerformed(ActionEvent e) {
- try {
- getCurrentTab().handleRedo();
- } catch (CannotRedoException ex) {
- //System.out.println("Unable to redo: " + ex);
- //ex.printStackTrace();
- }
- }
-
- protected void updateRedoState() {
- UndoManager undo = getCurrentTab().getUndoManager();
-
- if (undo.canRedo()) {
- redoItem.setEnabled(true);
- redoItem.setText(undo.getRedoPresentationName());
- putValue(Action.NAME, undo.getRedoPresentationName());
- } else {
- this.setEnabled(false);
- redoItem.setEnabled(false);
- redoItem.setText(tr("Redo"));
- putValue(Action.NAME, "Redo");
- }
- }
- }
-
-
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -1610,8 +1526,6 @@ public List getTabs() {
*/
public void selectTab(final int index) {
currentTabIndex = index;
- undoAction.updateUndoState();
- redoAction.updateRedoState();
updateTitle();
header.rebuild();
getCurrentTab().activated();
diff --git a/app/src/processing/app/EditorTab.java b/app/src/processing/app/EditorTab.java
index 988b7813657..c44d2d51627 100644
--- a/app/src/processing/app/EditorTab.java
+++ b/app/src/processing/app/EditorTab.java
@@ -44,7 +44,6 @@
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.PlainDocument;
-import javax.swing.undo.UndoManager;
import javax.swing.text.DefaultCaret;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
@@ -52,7 +51,6 @@
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
import org.fife.ui.rtextarea.Gutter;
import org.fife.ui.rtextarea.RTextScrollPane;
-import org.fife.ui.rtextarea.RUndoManager;
import cc.arduino.UpdatableBoardsLibsFakeURLsHandler;
import processing.app.helpers.DocumentTextChangeListener;
@@ -107,10 +105,6 @@ public EditorTab(Editor editor, SketchFile file, String contents)
file.setStorage(this);
applyPreferences();
add(this.scrollPane, BorderLayout.CENTER);
-
- RUndoManager undo = new LastUndoableEditAwareUndoManager(this.textarea, this.editor);
- document.addUndoableEditListener(undo);
- textarea.setUndoManager(undo);
}
private RSyntaxDocument createDocument(String contents) {
@@ -406,14 +400,14 @@ public void setText(String what) {
int oldLength = doc.getLength();
// The undo manager already seems to group the insert and remove together
// automatically, but better be explicit about it.
- textarea.getUndoManager().beginInternalAtomicEdit();
+ textarea.beginAtomicEdit();
try {
doc.insertString(oldLength, what, null);
doc.remove(0, oldLength);
} catch (BadLocationException e) {
System.err.println("Unexpected failure replacing text");
} finally {
- textarea.getUndoManager().endInternalAtomicEdit();
+ textarea.endAtomicEdit();
}
} finally {
caret.setUpdatePolicy(policy);
@@ -553,10 +547,6 @@ void handleRedo() {
textarea.redoLastAction();
}
- public UndoManager getUndoManager() {
- return textarea.getUndoManager();
- }
-
public String getCurrentKeyword() {
String text = "";
if (textarea.getSelectedText() != null)
diff --git a/app/src/processing/app/LastUndoableEditAwareUndoManager.java b/app/src/processing/app/LastUndoableEditAwareUndoManager.java
deleted file mode 100644
index 736be42d39b..00000000000
--- a/app/src/processing/app/LastUndoableEditAwareUndoManager.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package processing.app;
-
-import javax.swing.undo.CannotRedoException;
-import javax.swing.undo.CannotUndoException;
-
-import org.fife.ui.rtextarea.RUndoManager;
-
-import processing.app.syntax.SketchTextArea;
-
-public class LastUndoableEditAwareUndoManager extends RUndoManager {
-
- private Editor editor;
-
- public LastUndoableEditAwareUndoManager(SketchTextArea textarea, Editor editor) {
- super(textarea);
- this.editor = editor;
- }
-
- @Override
- public synchronized void undo() throws CannotUndoException {
- super.undo();
- }
-
- @Override
- public synchronized void redo() throws CannotRedoException {
- super.redo();
- }
-
- @Override
- public void updateActions() {
- super.updateActions();
- editor.undoAction.updateUndoState();
- editor.redoAction.updateRedoState();
- }
-
-
-}
diff --git a/app/src/processing/app/helpers/ActionWrapper.java b/app/src/processing/app/helpers/ActionWrapper.java
new file mode 100644
index 00000000000..fdd34b7013e
--- /dev/null
+++ b/app/src/processing/app/helpers/ActionWrapper.java
@@ -0,0 +1,54 @@
+package processing.app.helpers;
+
+import java.awt.event.ActionEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.Action;
+
+public class ActionWrapper implements Action {
+ protected Action action;
+
+ public ActionWrapper(Action wrapped) {
+ this.action = wrapped;
+ }
+
+ public Action getWrappedAction() {
+ return this.action;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ this.action.actionPerformed(e);
+ }
+
+ @Override
+ public Object getValue(String key) {
+ return this.action.getValue(key);
+ }
+
+ @Override
+ public void putValue(String key, Object value) {
+ this.action.putValue(key, value);
+ }
+
+ @Override
+ public void setEnabled(boolean b) {
+ this.action.setEnabled(b);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return this.action.isEnabled();
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ this.action.addPropertyChangeListener(listener);
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ this.action.removePropertyChangeListener(listener);
+ }
+
+}
diff --git a/build/windows/launcher/config.xml b/build/windows/launcher/config.xml
index 7168db2e01b..0e511358505 100644
--- a/build/windows/launcher/config.xml
+++ b/build/windows/launcher/config.xml
@@ -47,7 +47,7 @@
%EXEDIR%/lib/jsch-0.1.50.jar
%EXEDIR%/lib/jssc-2.8.0.jar
%EXEDIR%/lib/pde.jar
- %EXEDIR%/lib/rsyntaxtextarea-2.5.8.1+arduino.jar
+ %EXEDIR%/lib/rsyntaxtextarea-2.6.1.jar
%EXEDIR%/lib/xml-apis-1.3.04.jar
%EXEDIR%/lib/xml-apis-ext-1.3.04.jar
%EXEDIR%/lib/xmlgraphics-commons-2.0.jar
diff --git a/build/windows/launcher/config_debug.xml b/build/windows/launcher/config_debug.xml
index 1710133024e..ac863160792 100644
--- a/build/windows/launcher/config_debug.xml
+++ b/build/windows/launcher/config_debug.xml
@@ -47,7 +47,7 @@
%EXEDIR%/lib/jsch-0.1.50.jar
%EXEDIR%/lib/jssc-2.8.0.jar
%EXEDIR%/lib/pde.jar
- %EXEDIR%/lib/rsyntaxtextarea-2.5.8.1+arduino.jar
+ %EXEDIR%/lib/rsyntaxtextarea-2.6.1.jar
%EXEDIR%/lib/xml-apis-1.3.04.jar
%EXEDIR%/lib/xml-apis-ext-1.3.04.jar
%EXEDIR%/lib/xmlgraphics-commons-2.0.jar