From 67559781d4f54c988ca19a81a9a15e3a1bcc667a Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 24 Jan 2015 10:11:01 -0500 Subject: [PATCH] merging DebugEditor into JavaEditor --- .../mode/java/{debug => }/DebugToolbar.java | 7 +- .../mode/java/{debug => }/Debugger.java | 21 +- java/src/processing/mode/java/JavaEditor.java | 1928 ++++++++++++++- java/src/processing/mode/java/JavaMode.java | 9 +- .../mode/java/debug/DebugEditor.java | 2061 ----------------- .../mode/java/debug/LineBreakpoint.java | 1 + .../mode/java/debug/LineHighlight.java | 91 +- .../mode/java/debug/VariableInspector.java | 6 +- .../mode/java/pdex/ASTGenerator.java | 20 +- .../mode/java/pdex/CompletionPanel.java | 6 +- .../processing/mode/java/pdex/ErrorBar.java | 8 +- .../mode/java/pdex/ErrorCheckerService.java | 16 +- .../mode/java/pdex/ErrorWindow.java | 6 +- .../mode/java/pdex/JavaTextArea.java | 10 +- .../mode/java/pdex/JavaTextAreaPainter.java | 4 +- .../mode/java/pdex/SketchOutline.java | 4 +- .../processing/mode/java/pdex/TabOutline.java | 11 +- .../mode/java/pdex/XQConsoleToggle.java | 6 +- .../mode/java/pdex/XQErrorTable.java | 4 +- 19 files changed, 2025 insertions(+), 2194 deletions(-) rename java/src/processing/mode/java/{debug => }/DebugToolbar.java (98%) rename java/src/processing/mode/java/{debug => }/Debugger.java (98%) delete mode 100644 java/src/processing/mode/java/debug/DebugEditor.java diff --git a/java/src/processing/mode/java/debug/DebugToolbar.java b/java/src/processing/mode/java/DebugToolbar.java similarity index 98% rename from java/src/processing/mode/java/debug/DebugToolbar.java rename to java/src/processing/mode/java/DebugToolbar.java index 03cd0868e..bf7f8162d 100644 --- a/java/src/processing/mode/java/debug/DebugToolbar.java +++ b/java/src/processing/mode/java/DebugToolbar.java @@ -18,7 +18,7 @@ along with this program; if not, write to the Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package processing.mode.java.debug; +package processing.mode.java; import java.awt.Graphics; import java.awt.Image; @@ -31,9 +31,10 @@ import processing.app.Base; import processing.app.Editor; import processing.app.Language; import processing.app.Toolkit; -import processing.mode.java.JavaToolbar; + import processing.mode.java.pdex.XQConsoleToggle; + /** * Custom toolbar for the editor window. Preserves original button numbers * ({@link JavaToolbar#RUN}, {@link JavaToolbar#STOP}, {@link JavaToolbar#NEW}, @@ -190,7 +191,7 @@ public class DebugToolbar extends JavaToolbar { @Override public void handlePressed(MouseEvent e, int idx) { boolean shift = e.isShiftDown(); - DebugEditor deditor = (DebugEditor) editor; + JavaEditor deditor = (JavaEditor) editor; int id = buttonId(idx); // convert index/position to button id switch (id) { diff --git a/java/src/processing/mode/java/debug/Debugger.java b/java/src/processing/mode/java/Debugger.java similarity index 98% rename from java/src/processing/mode/java/debug/Debugger.java rename to java/src/processing/mode/java/Debugger.java index 08bc9cecc..462fa1c68 100644 --- a/java/src/processing/mode/java/debug/Debugger.java +++ b/java/src/processing/mode/java/Debugger.java @@ -18,7 +18,7 @@ along with this program; if not, write to the Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package processing.mode.java.debug; +package processing.mode.java; import com.sun.jdi.*; import com.sun.jdi.event.*; @@ -41,21 +41,28 @@ import javax.swing.tree.DefaultMutableTreeNode; import processing.app.Sketch; import processing.app.SketchCode; -import processing.mode.java.JavaBuild; +import processing.mode.java.debug.ArrayFieldNode; +import processing.mode.java.debug.ClassLoadListener; +import processing.mode.java.debug.FieldNode; +import processing.mode.java.debug.LineBreakpoint; +import processing.mode.java.debug.LineID; +import processing.mode.java.debug.LocalVariableNode; +import processing.mode.java.debug.VariableInspector; +import processing.mode.java.debug.VariableNode; import processing.mode.java.pdex.VMEventListener; import processing.mode.java.pdex.VMEventReader; import processing.mode.java.runner.Runner; /** - * Main controller class for debugging mode. Mainly works with DebugEditor as + * Main controller class for debugging mode. Mainly works with JavaEditor as * the corresponding "view". Uses DebugRunner to launch a VM. * * @author Martin Leopold */ public class Debugger implements VMEventListener { - protected DebugEditor editor; // editor window, acting as main view + protected JavaEditor editor; // editor window, acting as main view protected Runner runtime; // the runtime, contains debuggee VM protected boolean started = false; // debuggee vm has started, VMStartEvent received, main class loaded protected boolean paused = false; // currently paused at breakpoint or step @@ -75,7 +82,7 @@ public class Debugger implements VMEventListener { * * @param editor The Editor that will act as primary view */ - public Debugger(DebugEditor editor) { + public Debugger(JavaEditor editor) { this.editor = editor; } @@ -97,7 +104,7 @@ public class Debugger implements VMEventListener { * * @return the editor object */ - public DebugEditor editor() { + public JavaEditor editor() { return editor; } @@ -1057,7 +1064,7 @@ public class Debugger implements VMEventListener { * @param maxDepth max recursion depth. 0 will give only direct children * @return list of child fields of the given value */ - protected List getFields(Value value, int maxDepth, boolean includeInherited) { + public List getFields(Value value, int maxDepth, boolean includeInherited) { return getFields(value, 0, maxDepth, includeInherited); } diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index 48ddab29d..3a758c4ae 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -4,20 +4,45 @@ import java.awt.*; import java.awt.event.*; import java.beans.*; import java.io.*; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; +import javax.swing.table.TableModel; +import javax.swing.text.Document; + +import org.eclipse.jdt.core.compiler.IProblem; import processing.app.*; import processing.app.Toolkit; import processing.app.contrib.ToolContribution; import processing.app.syntax.JEditTextArea; import processing.app.syntax.PdeTextAreaDefaults; +import processing.core.PApplet; +import processing.mode.java.debug.LineBreakpoint; +import processing.mode.java.debug.LineHighlight; +import processing.mode.java.debug.LineID; +import processing.mode.java.debug.VariableInspector; +import processing.mode.java.pdex.ErrorBar; +import processing.mode.java.pdex.ErrorCheckerService; +import processing.mode.java.pdex.ErrorMessageSimplifier; +import processing.mode.java.pdex.JavaTextArea; +import processing.mode.java.pdex.Problem; +import processing.mode.java.pdex.XQConsoleToggle; +import processing.mode.java.pdex.XQErrorTable; import processing.mode.java.runner.Runner; +import processing.mode.java.tweak.ColorControlBox; +import processing.mode.java.tweak.Handle; +import processing.mode.java.tweak.SketchParser; +import processing.mode.java.tweak.UDPTweakClient; public class JavaEditor extends Editor { @@ -34,11 +59,74 @@ public class JavaEditor extends Editor { super(base, path, state, mode); jmode = (JavaMode) mode; + dmode = (JavaMode) mode; + dbg = new Debugger(this); + vi = new VariableInspector(this); + + // access to customized (i.e. subclassed) text area + ta = (JavaTextArea) textarea; + + // Add show usage option + JMenuItem showUsageItem = new JMenuItem("Show Usage..."); + showUsageItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleShowUsage(); + } + }); + ta.getRightClickPopup().add(showUsageItem); + + // add refactor option + JMenuItem renameItem = new JMenuItem("Rename..."); + renameItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleRefactor(); + } + }); + + // TODO: Add support for word select on right click and rename. + // ta.customPainter.addMouseListener(new MouseAdapter() { + // public void mouseClicked(MouseEvent evt) { + // System.out.println(evt); + // } + // }); + ta.getRightClickPopup().add(renameItem); + // set action on frame close + // addWindowListener(new WindowAdapter() { + // @Override + // public void windowClosing(WindowEvent e) { + // onWindowClosing(e); + // } + // }); + + Toolkit.setMenuMnemonics(ta.getRightClickPopup()); + + // load settings from theme.txt + breakpointColor = mode.getColor("breakpoint.bgcolor"); //, breakpointColor); + breakpointMarkerColor = mode.getColor("breakpoint.marker.color"); //, breakpointMarkerColor); + currentLineColor = mode.getColor("currentline.bgcolor"); //, currentLineColor); + currentLineMarkerColor = mode.getColor("currentline.marker.color"); //, currentLineMarkerColor); + + // set breakpoints from marker comments + for (LineID lineID : stripBreakpointComments()) { + //System.out.println("setting: " + lineID); + dbg.setBreakpoint(lineID); + } + getSketch().setModified(false); // setting breakpoints will flag sketch as modified, so override this here + + checkForJavaTabs(); + initializeErrorChecker(); + + ta.setECSandThemeforTextArea(errorCheckerService, dmode); + + addXQModeUI(); + debugToolbarEnabled = new AtomicBoolean(false); + //log("Sketch Path: " + path); } protected JEditTextArea createTextArea() { - return new JEditTextArea(new PdeTextAreaDefaults(mode), new JavaInputHandler(this)); + //return new JEditTextArea(new PdeTextAreaDefaults(mode), new JavaInputHandler(this)); + return new JavaTextArea(new PdeTextAreaDefaults(mode), this); } @@ -98,10 +186,22 @@ public class JavaEditor extends Editor { handleStop(); } }); - return buildSketchMenu(new JMenuItem[] { runItem, presentItem, stopItem }); + + JMenuItem tweakItem = Toolkit.newJMenuItemShift(Language.text("menu.sketch.tweak"), 'T'); + tweakItem.setSelected(JavaMode.enableTweak); + tweakItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JavaMode.enableTweak = true; + handleRun(); + } + }); + + return buildSketchMenu(new JMenuItem[] { + runItem, presentItem, tweakItem, stopItem + }); } - + public JMenu buildHelpMenu() { JMenu menu = new JMenu(Language.text("menu.help")); JMenuItem item; @@ -911,29 +1011,38 @@ public class JavaEditor extends Editor { } + /** + * Event handler called when hitting the stop button. Stops a running debug + * session or performs standard stop action if not currently debugging. + */ public void handleStop() { - toolbar.activate(JavaToolbar.STOP); + if (dbg.isStarted()) { + dbg.stopDebug(); + + } else { + toolbar.activate(JavaToolbar.STOP); - try { - //jmode.handleStop(); - if (runtime != null) { - runtime.close(); // kills the window - runtime = null; -// } else { -// System.out.println("runtime is null"); + try { + //jmode.handleStop(); + if (runtime != null) { + runtime.close(); // kills the window + runtime = null; + // } else { + // System.out.println("runtime is null"); + } + } catch (Exception e) { + statusError(e); } - } catch (Exception e) { - statusError(e); + + toolbar.deactivate(JavaToolbar.RUN); + toolbar.deactivate(JavaToolbar.STOP); + + // focus the PDE again after quitting presentation mode [toxi 030903] + toFront(); } - - toolbar.deactivate(JavaToolbar.RUN); - toolbar.deactivate(JavaToolbar.STOP); - - // focus the PDE again after quitting presentation mode [toxi 030903] - toFront(); } - - + + public void handleSave() { // toolbar.activate(JavaToolbar.SAVE); super.handleSave(true); @@ -942,10 +1051,32 @@ public class JavaEditor extends Editor { public boolean handleSaveAs() { -// toolbar.activate(JavaToolbar.SAVE); - boolean result = super.handleSaveAs(); -// toolbar.deactivate(JavaToolbar.SAVE); - return result; + //System.out.println("handleSaveAs"); + String oldName = getSketch().getCode(0).getFileName(); + //System.out.println("old name: " + oldName); + boolean saved = super.handleSaveAs(); + if (saved) { + // re-set breakpoints in first tab (name has changed) + List bps = dbg.getBreakpoints(oldName); + dbg.clearBreakpoints(oldName); + String newName = getSketch().getCode(0).getFileName(); + //System.out.println("new name: " + newName); + for (LineBreakpoint bp : bps) { + LineID line = new LineID(newName, bp.lineID().lineIdx()); + //System.out.println("setting: " + line); + dbg.setBreakpoint(line); + } + // add breakpoint marker comments to source file + for (int i = 0; i < getSketch().getCodeCount(); i++) { + addBreakpointComments(getSketch().getCode(i).getFileName()); + } + + // set new name of variable inspector + vi.setTitle(getSketch().getName()); + } + // if file location has changed, update autosaver + // autosaver.reloadAutosaveDir(); + return saved; } @@ -1009,7 +1140,11 @@ public class JavaEditor extends Editor { * To initiate a "stop" action, call handleStop() instead. */ public void deactivateRun() { - toolbar.deactivate(JavaToolbar.RUN); + if (toolbar instanceof DebugToolbar){ + toolbar.deactivate(DebugToolbar.RUN); + } else { + toolbar.deactivate(JavaToolbar.RUN); + } } @@ -1019,7 +1154,1746 @@ public class JavaEditor extends Editor { public void internalCloseRunner() { - //jmode.handleStop(); + // Added temporarily to dump error log. TODO: Remove this later [mk29] + if (JavaMode.errorLogsEnabled) { + writeErrorsToFile(); + } handleStop(); } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + // Additions from PDE X, Debug Mode, Twerk Mode... + + protected Color breakpointColor; // = new Color(240, 240, 240); // the background color for highlighting lines + protected Color currentLineColor; // = new Color(255, 255, 150); // the background color for highlighting lines + protected Color breakpointMarkerColor; // = new Color(74, 84, 94); // the color of breakpoint gutter markers + protected Color currentLineMarkerColor; // = new Color(226, 117, 0); // the color of current line gutter markers + protected List breakpointedLines = new ArrayList(); // breakpointed lines + protected LineHighlight currentLine; // line the debugger is currently suspended at + protected final String breakpointMarkerComment = " //<>//"; // breakpoint marker comment + + protected JMenu debugMenu; // the debug menu + + protected JMenuItem debugMenuItem; + protected JMenuItem continueMenuItem; + protected JMenuItem stopMenuItem; + + protected JMenuItem toggleBreakpointMenuItem; + protected JMenuItem listBreakpointsMenuItem; + + protected JMenuItem stepOverMenuItem; + protected JMenuItem stepIntoMenuItem; + protected JMenuItem stepOutMenuItem; + + protected JMenuItem printStackTraceMenuItem; + protected JMenuItem printLocalsMenuItem; + protected JMenuItem printThisMenuItem; + protected JMenuItem printSourceMenuItem; + protected JMenuItem printThreads; + + protected JMenuItem toggleVariableInspectorMenuItem; + + public JavaMode dmode; // the mode + protected Debugger dbg; // the debugger + protected VariableInspector vi; // the variable inspector frame + + public JavaTextArea ta; // the text area + public ErrorBar errorBar; + + protected XQConsoleToggle btnShowConsole; + protected XQConsoleToggle btnShowErrors; + protected JScrollPane errorTableScrollPane; + protected JPanel consoleProblemsPane; + protected XQErrorTable errorTable; + + public boolean compilationCheckEnabled = true; + + protected JCheckBoxMenuItem showWarnings; + public JCheckBoxMenuItem problemWindowMenuCB; + protected JCheckBoxMenuItem debugMessagesEnabled; + protected JMenuItem showOutline, showTabOutline; + protected JCheckBoxMenuItem writeErrorLog; + protected JCheckBoxMenuItem completionsEnabled; + + // TODO no way should this be public; make an accessor or protected + public boolean hasJavaTabs; + + + private void addXQModeUI(){ + + // Adding ErrorBar + JPanel textAndError = new JPanel(); + Box box = (Box) textarea.getParent(); + box.remove(2); // Remove textArea from it's container, i.e Box + textAndError.setLayout(new BorderLayout()); + errorBar = new ErrorBar(this, textarea.getMinimumSize().height, dmode); + textAndError.add(errorBar, BorderLayout.EAST); + textarea.setBounds(0, 0, errorBar.getX() - 1, textarea.getHeight()); + textAndError.add(textarea); + box.add(textAndError); + + // Adding Error Table in a scroll pane + errorTableScrollPane = new JScrollPane(); + errorTable = new XQErrorTable(errorCheckerService); + // errorTableScrollPane.setBorder(new EmptyBorder(2, 2, 2, 2)); + errorTableScrollPane.setBorder(new EtchedBorder()); + errorTableScrollPane.setViewportView(errorTable); + + // Adding toggle console button + consolePanel.remove(2); + JPanel lineStatusPanel = new JPanel(); + lineStatusPanel.setLayout(new BorderLayout()); + btnShowConsole = new XQConsoleToggle(this, + XQConsoleToggle.CONSOLE, lineStatus.getHeight()); + btnShowErrors = new XQConsoleToggle(this, + XQConsoleToggle.ERRORSLIST, lineStatus.getHeight()); + btnShowConsole.addMouseListener(btnShowConsole); + + // lineStatusPanel.add(btnShowConsole, BorderLayout.EAST); + // lineStatusPanel.add(btnShowErrors); + btnShowErrors.addMouseListener(btnShowErrors); + + JPanel toggleButtonPanel = new JPanel(new BorderLayout()); + toggleButtonPanel.add(btnShowConsole, BorderLayout.EAST); + toggleButtonPanel.add(btnShowErrors, BorderLayout.WEST); + lineStatusPanel.add(toggleButtonPanel, BorderLayout.EAST); + lineStatus.setBounds(0, 0, toggleButtonPanel.getX() - 1, + toggleButtonPanel.getHeight()); + lineStatusPanel.add(lineStatus); + consolePanel.add(lineStatusPanel, BorderLayout.SOUTH); + lineStatusPanel.repaint(); + + // Adding JPanel with CardLayout for Console/Problems Toggle + consolePanel.remove(1); + consoleProblemsPane = new JPanel(new CardLayout()); + consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.ERRORSLIST); + consoleProblemsPane.add(console, XQConsoleToggle.CONSOLE); + consolePanel.add(consoleProblemsPane, BorderLayout.CENTER); + + // ensure completion gets hidden on editor losing focus + addWindowFocusListener(new WindowFocusListener() { + public void windowLostFocus(WindowEvent e) { + ta.hideSuggestion(); + } + public void windowGainedFocus(WindowEvent e) { + + } + }); + } + +// /** +// * Event handler called when closing the editor window. Kills the variable +// * inspector window. +// * +// * @param e the event object +// */ +// protected void onWindowClosing(WindowEvent e) { +// // remove var.inspector +// vi.dispose(); +// // quit running debug session +// dbg.stopDebug(); +// } + /** + * Used instead of the windowClosing event handler, since it's not called on + * mode switch. Called when closing the editor window. Stops running debug + * sessions and kills the variable inspector window. + */ + @Override + public void dispose() { + //System.out.println("window dispose"); + // quit running debug session + dbg.stopDebug(); + // remove var.inspector + vi.dispose(); + errorCheckerService.stopThread(); + // original dispose + super.dispose(); + } + + + /** + * Writes all error messages to a csv file. + * For analytics purposes only. + */ + private void writeErrorsToFile() { + if (errorCheckerService.tempErrorLog.size() == 0) return; + + try { + System.out.println("Writing errors"); + StringBuilder sb = new StringBuilder(); + sb.append("Sketch: " + getSketch().getFolder() + ", " + + new java.sql.Timestamp(new java.util.Date().getTime()) + + "\nComma in error msg is substituted with ^ symbol\nFor separating arguments in error args | symbol is used\n"); + sb.append("ERROR TYPE, ERROR ARGS, ERROR MSG\n"); + + for (String errMsg : errorCheckerService.tempErrorLog.keySet()) { + IProblem ip = errorCheckerService.tempErrorLog.get(errMsg); + if (ip != null) { + sb.append(ErrorMessageSimplifier.getIDName(ip.getID())); + sb.append(','); + sb.append("{"); + for (int i = 0; i < ip.getArguments().length; i++) { + sb.append(ip.getArguments()[i]); + if (i < ip.getArguments().length-1) + sb.append("| "); + } + sb.append("}"); + sb.append(','); + sb.append(ip.getMessage().replace(',', '^')); + sb.append("\n"); + } + } + System.out.println(sb); + File opFile = new File(getSketch().getFolder(), "ErrorLogs" + + File.separator + "ErrorLog_" + System.currentTimeMillis() + ".csv"); + PApplet.saveStream(opFile, new ByteArrayInputStream(sb.toString() + .getBytes(Charset.defaultCharset()))); + } catch (Exception e) { + System.err.println("Failed to save log file for sketch " + getSketch().getName()); + e.printStackTrace(); + } + } + + + private AtomicBoolean debugToolbarEnabled; + + public boolean isDebugToolbarEnabled() { + return debugToolbarEnabled != null && debugToolbarEnabled.get(); + } + + + protected EditorToolbar javaToolbar, debugToolbar; + + /** + * Toggles between java mode and debug mode toolbar + */ + protected void switchToolbars(){ + final EditorToolbar nextToolbar; + if(debugToolbarEnabled.get()){ + // switch to java + if(javaToolbar == null) + javaToolbar = createToolbar(); + nextToolbar = javaToolbar; + debugToolbarEnabled.set(false); + Base.log("Switching to Java Mode Toolbar"); + } + else{ + // switch to debug + if(debugToolbar == null) + debugToolbar = new DebugToolbar(this, getBase()); + nextToolbar = debugToolbar; + debugToolbarEnabled.set(true); + Base.log("Switching to Debugger Toolbar"); + } + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + Box upper = (Box)splitPane.getComponent(0); + upper.remove(0); + upper.add(nextToolbar, 0); + upper.validate(); + nextToolbar.repaint(); + toolbar = nextToolbar; + // The toolbar responds to shift down/up events + // in order to show the alt version of toolbar buttons. + // With toolbar switch, KeyListener has to be changed as well + for (KeyListener kl : textarea.getKeyListeners()) { + if(kl instanceof EditorToolbar) + { + textarea.removeKeyListener(kl); + textarea.addKeyListener(toolbar); + break; + } + } + ta.repaint(); + } + }); + } + + /** + * Creates the debug menu. Includes ActionListeners for the menu items. + * Intended for adding to the menu bar. + * + * @return The debug menu + */ + protected JMenu buildDebugMenu() { + debugMenu = new JMenu(Language.text("menu.debug")); + //debugMenu = new JMenu("PDE X"); + + JCheckBoxMenuItem toggleDebugger = new JCheckBoxMenuItem(Language.text("menu.debug.show_debug_toolbar")); + toggleDebugger.setSelected(false); + toggleDebugger.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + switchToolbars(); + } + }); + debugMenu.add(toggleDebugger); + debugMenuItem = Toolkit.newJMenuItemAlt(Language.text("menu.debug.debug"), KeyEvent.VK_R); + debugMenuItem.addActionListener(this); + continueMenuItem = Toolkit.newJMenuItem(Language.text("menu.debug.continue"), KeyEvent.VK_U); + continueMenuItem.addActionListener(this); + stopMenuItem = new JMenuItem(Language.text("menu.debug.stop")); + stopMenuItem.addActionListener(this); + + toggleBreakpointMenuItem = Toolkit.newJMenuItem(Language.text("menu.debug.toggle_breakpoint"), KeyEvent.VK_B); + toggleBreakpointMenuItem.addActionListener(this); + listBreakpointsMenuItem = new JMenuItem(Language.text("menu.debug.list_breakpoints")); + listBreakpointsMenuItem.addActionListener(this); + + stepOverMenuItem = Toolkit.newJMenuItem(Language.text("menu.debug.step"), KeyEvent.VK_J); + stepOverMenuItem.addActionListener(this); + stepIntoMenuItem = Toolkit.newJMenuItemShift(Language.text("menu.debug.step_into"), KeyEvent.VK_J); + stepIntoMenuItem.addActionListener(this); + stepOutMenuItem = Toolkit.newJMenuItemAlt(Language.text("menu.debug.step_out"), KeyEvent.VK_J); + stepOutMenuItem.addActionListener(this); + + printStackTraceMenuItem = new JMenuItem(Language.text("menu.debug.print_stack_trace")); + printStackTraceMenuItem.addActionListener(this); + printLocalsMenuItem = new JMenuItem(Language.text("menu.debug.print_locals")); + printLocalsMenuItem.addActionListener(this); + printThisMenuItem = new JMenuItem(Language.text("menu.debug.print_fields")); + printThisMenuItem.addActionListener(this); + printSourceMenuItem = new JMenuItem(Language.text("menu.debug.print_source_location")); + printSourceMenuItem.addActionListener(this); + printThreads = new JMenuItem(Language.text("menu.debug.print_threads")); + printThreads.addActionListener(this); + + toggleVariableInspectorMenuItem = Toolkit.newJMenuItem(Language.text("menu.debug.toggle_variable_inspector"), KeyEvent.VK_I); + toggleVariableInspectorMenuItem.addActionListener(this); + + debugMenu.add(debugMenuItem); + debugMenu.add(continueMenuItem); + debugMenu.add(stopMenuItem); + debugMenu.addSeparator(); + debugMenu.add(toggleBreakpointMenuItem); + debugMenu.add(listBreakpointsMenuItem); + debugMenu.addSeparator(); + debugMenu.add(stepOverMenuItem); + debugMenu.add(stepIntoMenuItem); + debugMenu.add(stepOutMenuItem); + debugMenu.addSeparator(); + debugMenu.add(printStackTraceMenuItem); + debugMenu.add(printLocalsMenuItem); + debugMenu.add(printThisMenuItem); + debugMenu.add(printSourceMenuItem); + debugMenu.add(printThreads); + debugMenu.addSeparator(); + debugMenu.add(toggleVariableInspectorMenuItem); + // debugMenu.addSeparator(); + + // XQMode menu items + /* + JCheckBoxMenuItem item; + item = new JCheckBoxMenuItem("Error Checker Enabled"); + item.setSelected(ExperimentalMode.errorCheckEnabled); + item.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + ExperimentalMode.errorCheckEnabled = ((JCheckBoxMenuItem) e.getSource()).isSelected(); + errorCheckerService.handleErrorCheckingToggle(); + dmode.savePreferences(); + } + }); + debugMenu.add(item); + + problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); + // problemWindowMenuCB.setSelected(true); + problemWindowMenuCB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (errorCheckerService.errorWindow == null) { + return; + } + errorCheckerService.errorWindow + .setVisible(((JCheckBoxMenuItem) e.getSource()) + .isSelected()); + // switch to console, now that Error Window is open + showProblemListView(XQConsoleToggle.CONSOLE); + } + }); + debugMenu.add(problemWindowMenuCB); + + showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); + showWarnings.setSelected(ExperimentalMode.warningsEnabled); + showWarnings.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + ExperimentalMode.warningsEnabled = ((JCheckBoxMenuItem) e + .getSource()).isSelected(); + errorCheckerService.runManualErrorCheck(); + dmode.savePreferences(); + } + }); + debugMenu.add(showWarnings); + + completionsEnabled = new JCheckBoxMenuItem("Code Completion Enabled"); + completionsEnabled.setSelected(ExperimentalMode.codeCompletionsEnabled); + completionsEnabled.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ExperimentalMode.codeCompletionsEnabled = (((JCheckBoxMenuItem) e + .getSource()).isSelected()); + dmode.savePreferences(); + } + }); + debugMenu.add(completionsEnabled); + + debugMessagesEnabled = new JCheckBoxMenuItem("Show Debug Messages"); + debugMessagesEnabled.setSelected(ExperimentalMode.DEBUG); + debugMessagesEnabled.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ExperimentalMode.DEBUG = ((JCheckBoxMenuItem) e + .getSource()).isSelected(); + dmode.savePreferences(); + } + }); + debugMenu.add(debugMessagesEnabled); + + + writeErrorLog = new JCheckBoxMenuItem("Write Errors to Log"); + writeErrorLog.setSelected(ExperimentalMode.errorLogsEnabled); + writeErrorLog.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ExperimentalMode.errorLogsEnabled = ((JCheckBoxMenuItem) e + .getSource()).isSelected(); + dmode.savePreferences(); + } + }); + debugMenu.add(writeErrorLog); + + debugMenu.addSeparator(); + JMenuItem jitem = new JMenuItem("PDE X on GitHub"); + jitem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Base.openURL("https://github.com/processing/processing-experimental"); + } + }); + debugMenu.add(jitem); + */ + showOutline = Toolkit.newJMenuItem(Language.text("menu.debug.show_sketch_outline"), KeyEvent.VK_L); + showOutline.addActionListener(this); + debugMenu.add(showOutline); + + showTabOutline = Toolkit.newJMenuItem(Language.text("menu.debug.show_tabs_list"), KeyEvent.VK_Y); + showTabOutline.addActionListener(this); + debugMenu.add(showTabOutline); + + return debugMenu; + } + + @Override + public JMenu buildModeMenu() { + return buildDebugMenu(); + } + + /** + * Callback for menu items. Implementation of Swing ActionListener. + * + * @param ae Action event + */ + @Override + public void actionPerformed(ActionEvent ae) { + //System.out.println("ActionEvent: " + ae.toString()); + + JMenuItem source = (JMenuItem) ae.getSource(); + if (source == debugMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Debug' menu item"); + //dmode.handleDebug(sketch, this); + dbg.startDebug(); + } else if (source == stopMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Stop' menu item"); + //dmode.handleDebug(sketch, this); + dbg.stopDebug(); + } else if (source == continueMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Continue' menu item"); + //dmode.handleDebug(sketch, this); + dbg.continueDebug(); + } else if (source == stepOverMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Step Over' menu item"); + dbg.stepOver(); + } else if (source == stepIntoMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Step Into' menu item"); + dbg.stepInto(); + } else if (source == stepOutMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Step Out' menu item"); + dbg.stepOut(); + } else if (source == printStackTraceMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print Stack Trace' menu item"); + dbg.printStackTrace(); + } else if (source == printLocalsMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print Locals' menu item"); + dbg.printLocals(); + } else if (source == printThisMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print This' menu item"); + dbg.printThis(); + } else if (source == printSourceMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print Source' menu item"); + dbg.printSource(); + } else if (source == printThreads) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print Threads' menu item"); + dbg.printThreads(); + } else if (source == toggleBreakpointMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' menu item"); + dbg.toggleBreakpoint(); + } else if (source == listBreakpointsMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'List Breakpoints' menu item"); + dbg.listBreakpoints(); + } else if (source == toggleVariableInspectorMenuItem) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item"); + toggleVariableInspector(); + } else if (source.equals(showOutline)){ + Base.log("Show Sketch Outline:"); + errorCheckerService.getASTGenerator().showSketchOutline(); + } + else if (source.equals(showTabOutline)){ + Base.log("Show Tab Outline:"); + errorCheckerService.getASTGenerator().showTabOutline(); + } + } + + + + /** + * Event handler called when loading another sketch in this editor. Clears + * breakpoints of previous sketch. + * + * @param path + * @return true if a sketch was opened, false if aborted + */ + @Override + protected boolean handleOpenInternal(String path) { + // log("handleOpenInternal, path: " + path); + boolean didOpen = super.handleOpenInternal(path); + if (didOpen && dbg != null) { + // should already been stopped (open calls handleStop) + dbg.clearBreakpoints(); + clearBreakpointedLines(); // force clear breakpoint highlights + variableInspector().reset(); // clear contents of variable inspector + } + //if(didOpen){ + // autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); // this is used instead of loadAutosaver(), temp measure + // loadAutoSaver(); + // viewingAutosaveBackup = autosaver.isAutoSaveBackup(); + // log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); + //} + return didOpen; + } + + /** + * Extract breakpointed lines from source code marker comments. This removes + * marker comments from the editor text. Intended to be called on loading a + * sketch, since re-setting the sketches contents after removing the markers + * will clear all breakpoints. + * + * @return the list of {@link LineID}s where breakpoint marker comments were + * removed from. + */ + protected List stripBreakpointComments() { + List bps = new ArrayList(); + // iterate over all tabs + Sketch sketch = getSketch(); + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode tab = sketch.getCode(i); + String code = tab.getProgram(); + String lines[] = code.split("\\r?\\n"); // newlines not included + //System.out.println(code); + + // scan code for breakpoint comments + int lineIdx = 0; + for (String line : lines) { + //System.out.println(line); + if (line.endsWith(breakpointMarkerComment)) { + LineID lineID = new LineID(tab.getFileName(), lineIdx); + bps.add(lineID); + //System.out.println("found breakpoint: " + lineID); + // got a breakpoint + //dbg.setBreakpoint(lineID); + int index = line.lastIndexOf(breakpointMarkerComment); + lines[lineIdx] = line.substring(0, index); + } + lineIdx++; + } + //tab.setProgram(code); + code = PApplet.join(lines, "\n"); + setTabContents(tab.getFileName(), code); + } + return bps; + } + + /** + * Add breakpoint marker comments to the source file of a specific tab. This + * acts on the source file on disk, not the editor text. Intended to be + * called just after saving the sketch. + * + * @param tabFilename the tab file name + */ + protected void addBreakpointComments(String tabFilename) { + SketchCode tab = getTab(tabFilename); + if(tab == null) { + // this method gets called twice when saving sketch for the first time + // once with new name and another with old(causing NPE). Keep an eye out + // for potential issues. See #2675. TODO: + Base.loge("Illegal tab name to addBreakpointComments() " + tabFilename); + return; + } + List bps = dbg.getBreakpoints(tab.getFileName()); + + // load the source file + File sourceFile = new File(sketch.getFolder(), tab.getFileName()); + //System.out.println("file: " + sourceFile); + try { + String code = Base.loadFile(sourceFile); + //System.out.println("code: " + code); + String lines[] = code.split("\\r?\\n"); // newlines not included + for (LineBreakpoint bp : bps) { + //System.out.println("adding bp: " + bp.lineID()); + lines[bp.lineID().lineIdx()] += breakpointMarkerComment; + } + code = PApplet.join(lines, "\n"); + //System.out.println("new code: " + code); + Base.saveFile(code, sourceFile); + } catch (IOException ex) { + Logger.getLogger(JavaEditor.class.getName()).log(Level.SEVERE, null, ex); + } + } + + @Override + public boolean handleSave(boolean immediately) { + //System.out.println("handleSave " + immediately); + + //log("handleSave, viewing autosave? " + viewingAutosaveBackup); + /* If user wants to save a backup, the backup sketch should get + * copied to the main sketch directory, simply reload the main sketch. + */ + if(viewingAutosaveBackup){ + /* + File files[] = autosaver.getSketchBackupFolder().listFiles(); + File src = autosaver.getSketchBackupFolder(), dst = autosaver + .getActualSketchFolder(); + for (File f : files) { + log("Copying " + f.getAbsolutePath() + " to " + dst.getAbsolutePath()); + try { + if (f.isFile()) { + f.delete(); + Base.copyFile(f, new File(dst + File.separator + f.getName())); + } else { + Base.removeDir(f); + Base.copyDir(f, new File(dst + File.separator + f.getName())); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + File sk = autosaver.getActualSketchFolder(); + Base.removeDir(autosaver.getAutoSaveDir()); + //handleOpenInternal(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde"); + getBase().handleOpen(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde"); + //viewingAutosaveBackup = false; + */ + } + + // note modified tabs + final List modified = new ArrayList(); + for (int i = 0; i < getSketch().getCodeCount(); i++) { + SketchCode tab = getSketch().getCode(i); + if (tab.isModified()) { + modified.add(tab.getFileName()); + } + } + + boolean saved = super.handleSave(immediately); + if (saved) { + if (immediately) { + for (String tabFilename : modified) { + addBreakpointComments(tabFilename); + } + } else { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + for (String tabFilename : modified) { + addBreakpointComments(tabFilename); + } + } + }); + } + } + // if file location has changed, update autosaver + // autosaver.reloadAutosaveDir(); + return saved; + } + + + private boolean viewingAutosaveBackup; + + + /** + * Set text contents of a specific tab. Updates underlying document and text + * area. Clears Breakpoints. + * + * @param tabFilename the tab file name + * @param code the text to set + */ + protected void setTabContents(String tabFilename, String code) { + // remove all breakpoints of this tab + dbg.clearBreakpoints(tabFilename); + + SketchCode currentTab = getCurrentTab(); + + // set code of tab + SketchCode tab = getTab(tabFilename); + if (tab != null) { + tab.setProgram(code); + // this updates document and text area + // TODO: does this have any negative effects? (setting the doc to null) + tab.setDocument(null); + setCode(tab); + + // switch back to original tab + setCode(currentTab); + } + } + + /** + * Clear the console. + */ + public void clearConsole() { + console.clear(); + } + + /** + * Clear current text selection. + */ + public void clearSelection() { + setSelection(getCaretOffset(), getCaretOffset()); + } + + /** + * Select a line in the current tab. + * + * @param lineIdx 0-based line number + */ + public void selectLine(int lineIdx) { + setSelection(getLineStartOffset(lineIdx), getLineStopOffset(lineIdx)); + } + + /** + * Set the cursor to the start of a line. + * + * @param lineIdx 0-based line number + */ + public void cursorToLineStart(int lineIdx) { + setSelection(getLineStartOffset(lineIdx), getLineStartOffset(lineIdx)); + } + + /** + * Set the cursor to the end of a line. + * + * @param lineIdx 0-based line number + */ + public void cursorToLineEnd(int lineIdx) { + setSelection(getLineStopOffset(lineIdx), getLineStopOffset(lineIdx)); + } + + /** + * Switch to a tab. + * + * @param tabFileName the file name identifying the tab. (as in + * {@link SketchCode#getFileName()}) + */ + public void switchToTab(String tabFileName) { + Sketch s = getSketch(); + for (int i = 0; i < s.getCodeCount(); i++) { + if (tabFileName.equals(s.getCode(i).getFileName())) { + s.setCurrentCode(i); + break; + } + } + } + + + /** + * Access the debugger. + * + * @return the debugger controller object + */ + public Debugger dbg() { + return dbg; + } + + + /** + * Access the mode. + * + * @return the mode object + */ + public JavaMode mode() { + return dmode; + } + + /** + * Access the custom text area object. + * + * @return the text area object + */ + public JavaTextArea textArea() { + return ta; + } + + + /** + * Grab current contents of the sketch window, advance the console, stop any + * other running sketches, auto-save the user's code... not in that order. + */ + @Override + public void prepareRun() { + autoSave(); + super.prepareRun(); + } + + /** + * Displays a JDialog prompting the user to save when the user hits + * run/present/etc. + */ + protected void autoSave() { + if (!JavaMode.autoSaveEnabled) + return; + + try { + // if (sketch.isUntitled() && + // ExperimentalMode.untitledAutoSaveEnabled) { + // if (handleSave(true)) + // statusTimedNotice("Saved. Running...", 5); + // else + // statusTimedNotice("Save Canceled. Running anyway...", 5); + // } + // else + if (sketch.isModified() && !sketch.isUntitled()) { + if (JavaMode.autoSavePromptEnabled) { + final JDialog autoSaveDialog = new JDialog( + base.getActiveEditor(), this.getSketch().getName(), + true); + Container container = autoSaveDialog.getContentPane(); + + JPanel panelMain = new JPanel(); + panelMain.setBorder(BorderFactory.createEmptyBorder(4, 0, + 2, 2)); + panelMain.setLayout(new BoxLayout(panelMain, + BoxLayout.PAGE_AXIS)); + + JPanel panelLabel = new JPanel(new FlowLayout( + FlowLayout.LEFT)); + JLabel label = new JLabel( + " There are unsaved" + + " changes in your sketch.
" + + "    Do you want to save it before" + + " running? "); + label.setFont(new Font(label.getFont().getName(), + Font.PLAIN, label.getFont().getSize() + 1)); + panelLabel.add(label); + panelMain.add(panelLabel); + final JCheckBox dontRedisplay = new JCheckBox( + "Remember this decision"); + + JPanel panelButtons = new JPanel(new FlowLayout( + FlowLayout.CENTER, 8, 2)); + JButton btnRunSave = new JButton("Save and Run"); + btnRunSave.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + handleSave(true); + if (dontRedisplay.isSelected()) { + JavaMode.autoSavePromptEnabled = !dontRedisplay.isSelected(); + JavaMode.defaultAutoSaveEnabled = true; + dmode.savePreferences(); + } + autoSaveDialog.dispose(); + } + }); + panelButtons.add(btnRunSave); + JButton btnRunNoSave = new JButton("Run, Don't Save"); + btnRunNoSave.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (dontRedisplay.isSelected()) { + JavaMode.autoSavePromptEnabled = !dontRedisplay.isSelected(); + JavaMode.defaultAutoSaveEnabled = false; + dmode.savePreferences(); + } + autoSaveDialog.dispose(); + } + }); + panelButtons.add(btnRunNoSave); + panelMain.add(panelButtons); + + JPanel panelCheck = new JPanel(); + panelCheck + .setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); + panelCheck.add(dontRedisplay); + panelMain.add(panelCheck); + + container.add(panelMain); + + autoSaveDialog.setResizable(false); + autoSaveDialog.pack(); + autoSaveDialog + .setLocationRelativeTo(base.getActiveEditor()); + autoSaveDialog.setVisible(true); + + } else if (JavaMode.defaultAutoSaveEnabled) { + handleSave(true); + } + } + } catch (Exception e) { + statusError(e); + } + + } + + /** + * Access variable inspector window. + * + * @return the variable inspector object + */ + public VariableInspector variableInspector() { + return vi; + } + + public DebugToolbar toolbar() { + if(toolbar instanceof DebugToolbar) + return (DebugToolbar) toolbar; + return null; + } + + /** + * Show the variable inspector window. + */ + public void showVariableInspector() { + vi.setVisible(true); + } + + /** + * Set visibility of the variable inspector window. + * + * @param visible true to set the variable inspector visible, false for + * invisible. + */ + public void showVariableInspector(boolean visible) { + vi.setVisible(visible); + } + + /** + * Hide the variable inspector window. + */ + public void hideVariableInspector() { + vi.setVisible(true); + } + + /** + * Toggle visibility of the variable inspector window. + */ + public void toggleVariableInspector() { + vi.setFocusableWindowState(false); // to not get focus when set visible + vi.setVisible(!vi.isVisible()); + vi.setFocusableWindowState(true); // allow to get focus again + } + + + /** + * Set the line to highlight as currently suspended at. Will override the + * breakpoint color, if set. Switches to the appropriate tab and scroll to + * the line by placing the cursor there. + * + * @param line the line to highlight as current suspended line + */ + public void setCurrentLine(LineID line) { + clearCurrentLine(); + if (line == null) { + return; // safety, e.g. when no line mapping is found and the null line is used. + } + switchToTab(line.fileName()); + // scroll to line, by setting the cursor + cursorToLineStart(line.lineIdx()); + // highlight line + currentLine = new LineHighlight(line.lineIdx(), currentLineColor, this); + currentLine.setMarker(ta.currentLineMarker, currentLineMarkerColor); + currentLine.setPriority(10); // fixes current line being hidden by the breakpoint when moved down + } + + /** + * Clear the highlight for the debuggers current line. + */ + public void clearCurrentLine() { + if (currentLine != null) { + currentLine.clear(); + currentLine.dispose(); + + // revert to breakpoint color if any is set on this line + for (LineHighlight hl : breakpointedLines) { + if (hl.getLineID().equals(currentLine.getLineID())) { + hl.paint(); + break; + } + } + currentLine = null; + } + } + + /** + * Add highlight for a breakpointed line. + * + * @param lineID the line id to highlight as breakpointed + */ + public void addBreakpointedLine(LineID lineID) { + LineHighlight hl = new LineHighlight(lineID, breakpointColor, this); + hl.setMarker(ta.breakpointMarker, breakpointMarkerColor); + breakpointedLines.add(hl); + // repaint current line if it's on this line + if (currentLine != null && currentLine.getLineID().equals(lineID)) { + currentLine.paint(); + } + } + + /** + * Add highlight for a breakpointed line on the current tab. + * + * @param lineIdx the line index on the current tab to highlight as + * breakpointed + */ + //TODO: remove and replace by {@link #addBreakpointedLine(LineID lineID)} + public void addBreakpointedLine(int lineIdx) { + addBreakpointedLine(getLineIDInCurrentTab(lineIdx)); + } + + /** + * Remove a highlight for a breakpointed line. Needs to be on the current + * tab. + * + * @param lineIdx the line index on the current tab to remove a breakpoint + * highlight from + */ + public void removeBreakpointedLine(int lineIdx) { + LineID line = getLineIDInCurrentTab(lineIdx); + //System.out.println("line id: " + line.fileName() + " " + line.lineIdx()); + LineHighlight foundLine = null; + for (LineHighlight hl : breakpointedLines) { + if (hl.getLineID().equals(line)) { + foundLine = hl; + break; + } + } + if (foundLine != null) { + foundLine.clear(); + breakpointedLines.remove(foundLine); + foundLine.dispose(); + // repaint current line if it's on this line + if (currentLine != null && currentLine.getLineID().equals(line)) { + currentLine.paint(); + } + } + } + + /** + * Remove all highlights for breakpointed lines. + */ + public void clearBreakpointedLines() { + for (LineHighlight hl : breakpointedLines) { + hl.clear(); + hl.dispose(); + } + breakpointedLines.clear(); // remove all breakpoints + // fix highlights not being removed when tab names have changed due to opening a new sketch in same editor + ta.clearLineBgColors(); // force clear all highlights + ta.clearGutterText(); + + // repaint current line + if (currentLine != null) { + currentLine.paint(); + } + } + + /** + * Retrieve a {@link LineID} object for a line on the current tab. + * + * @param lineIdx the line index on the current tab + * @return the {@link LineID} object representing a line index on the + * current tab + */ + public LineID getLineIDInCurrentTab(int lineIdx) { + return new LineID(getSketch().getCurrentCode().getFileName(), lineIdx); + } + + /** + * Retrieve line of sketch where the cursor currently resides. + * + * @return the current {@link LineID} + */ + protected LineID getCurrentLineID() { + String tab = getSketch().getCurrentCode().getFileName(); + int lineNo = getTextArea().getCaretLine(); + return new LineID(tab, lineNo); + } + + /** + * Check whether a {@link LineID} is on the current tab. + * + * @param line the {@link LineID} + * @return true, if the {@link LineID} is on the current tab. + */ + public boolean isInCurrentTab(LineID line) { + return line.fileName().equals(getSketch().getCurrentCode().getFileName()); + } + + /** + * Event handler called when switching between tabs. Loads all line + * background colors set for the tab. + * + * @param code tab to switch to + */ + @Override + protected void setCode(SketchCode code) { + //System.out.println("tab switch: " + code.getFileName()); + super.setCode(code); // set the new document in the textarea, etc. need to do this first + + // set line background colors for tab + if (ta != null) { // can be null when setCode is called the first time (in constructor) + // clear all line backgrounds + ta.clearLineBgColors(); + // clear all gutter text + ta.clearGutterText(); + // load appropriate line backgrounds for tab + // first paint breakpoints + for (LineHighlight hl : breakpointedLines) { + if (isInCurrentTab(hl.getLineID())) { + hl.paint(); + } + } + // now paint current line (if any) + if (currentLine != null) { + if (isInCurrentTab(currentLine.getLineID())) { + currentLine.paint(); + } + } + } + if (dbg() != null && dbg().isStarted()) { + dbg().startTrackingLineChanges(); + } + } + + /** + * Get a tab by its file name. + * + * @param fileName the filename to search for. + * @return the {@link SketchCode} object representing the tab, or null if + * not found + */ + public SketchCode getTab(String fileName) { + Sketch s = getSketch(); + for (SketchCode c : s.getCode()) { + if (c.getFileName().equals(fileName)) { + return c; + } + } + return null; + } + + /** + * Retrieve the current tab. + * + * @return the {@link SketchCode} representing the current tab + */ + public SketchCode getCurrentTab() { + return getSketch().getCurrentCode(); + } + + /** + * Access the currently edited document. + * + * @return the document object + */ + public Document currentDocument() { + //return ta.getDocument(); + return getCurrentTab().getDocument(); + } + + /** + * Factory method for the editor toolbar. Instantiates the customized + * toolbar. + * + * @return the toolbar + */ + /*@Override + public EditorToolbar createToolbar() { + return new DebugToolbar(this, base); + }*/ + + /** + * Event Handler for double clicking in the left hand gutter area. + * + * @param lineIdx the line (0-based) that was double clicked + */ + public void gutterDblClicked(int lineIdx) { + if (dbg != null) { + dbg.toggleBreakpoint(lineIdx); + } + } + + public void statusBusy() { + statusNotice("Debugger busy..."); + } + + public void statusHalted() { + statusNotice("Debugger halted."); + } + + public static final int STATUS_EMPTY = 100, STATUS_COMPILER_ERR = 200, + STATUS_WARNING = 300, STATUS_INFO = 400, STATUS_ERR = 500; + public int statusMessageType = STATUS_EMPTY; + public String statusMessage; + public void statusMessage(final String what, int type){ + // Don't re-display the old message again + if(type != STATUS_EMPTY) { + if(what.equals(statusMessage) && type == statusMessageType) { + return; + } + } + statusMessage = new String(what); + statusMessageType = type; + switch (type) { + case STATUS_COMPILER_ERR: + case STATUS_ERR: + super.statusError(what); + break; + case STATUS_INFO: + case STATUS_WARNING: + statusNotice(what); + break; + } + // Don't need to clear compiler error messages + if(type == STATUS_COMPILER_ERR) return; + + // Clear the message after a delay + SwingWorker s = new SwingWorker() { + @Override + protected Object doInBackground() throws Exception { + try { + Thread.sleep(2 * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + statusEmpty(); + return null; + } + }; + s.execute(); + } + + public void statusEmpty(){ + statusMessage = null; + statusMessageType = STATUS_EMPTY; + super.statusEmpty(); + } + + public ErrorCheckerService errorCheckerService; + + /** + * Initializes and starts Error Checker Service + */ + private void initializeErrorChecker() { + Thread errorCheckerThread = null; + + if (errorCheckerThread == null) { + errorCheckerService = new ErrorCheckerService(this); + errorCheckerThread = new Thread(errorCheckerService); + try { + errorCheckerThread.start(); + } catch (Exception e) { + System.err + .println("Error Checker Service not initialized [XQEditor]: " + + e); + // e.printStackTrace(); + } + // System.out.println("Error Checker Service initialized."); + } + + } + + /** + * Updates the error bar + * @param problems + */ + public void updateErrorBar(ArrayList problems) { + errorBar.updateErrorPoints(problems); + } + + /** + * Toggle between Console and Errors List + * + * @param buttonName + * - Button Label + */ + public void showProblemListView(String buttonName) { + CardLayout cl = (CardLayout) consoleProblemsPane.getLayout(); + cl.show(consoleProblemsPane, buttonName); + } + + /** + * Updates the error table + * @param tableModel + * @return + */ + synchronized public boolean updateTable(final TableModel tableModel) { + return errorTable.updateTable(tableModel); + } + + + /** + * Handle whether the tiny red error indicator is shown near the error button + * at the bottom of the PDE + */ + public void updateErrorToggle(){ + btnShowErrors.updateMarker(JavaMode.errorCheckEnabled && + errorCheckerService.hasErrors(), + errorBar.errorColor); + } + + + /** + * Handle refactor operation + */ + private void handleRefactor() { + Base.log("Caret at:" + ta.getLineText(ta.getCaretLine())); + errorCheckerService.getASTGenerator().handleRefactor(); + } + + + /** + * Handle show usage operation + */ + private void handleShowUsage() { + Base.log("Caret at:" + ta.getLineText(ta.getCaretLine())); + errorCheckerService.getASTGenerator().handleShowUsage(); + } + + + /** + * Checks if the sketch contains java tabs. If it does, the editor ain't built + * for it, yet. Also, user should really start looking at more powerful IDEs + * likeEclipse. Disable compilation check and some more features. + */ + private void checkForJavaTabs() { + hasJavaTabs = false; + for (int i = 0; i < this.getSketch().getCodeCount(); i++) { + if (this.getSketch().getCode(i).getExtension().equals("java")) { + compilationCheckEnabled = false; + hasJavaTabs = true; + JOptionPane.showMessageDialog(new Frame(), this + .getSketch().getName() + + " contains .java tabs. Some editor features are not supported " + + "for .java tabs and will be disabled."); + break; + } + } + } + + + protected void applyPreferences() { + super.applyPreferences(); + if (dmode != null) { + dmode.loadPreferences(); + Base.log("Applying prefs"); + // trigger it once to refresh UI + errorCheckerService.runManualErrorCheck(); + } + } + + + // TweakMode code + /** + * Show warnings menu item + */ + //protected JCheckBoxMenuItem enableTweakCB; + + public static final String prefTweakPort = "tweak.port"; + public static final String prefTweakShowCode = "tweak.showcode"; + + public String[] baseCode; + + final static int SPACE_AMOUNT = 0; + + UDPTweakClient tweakClient; + + public void startInteractiveMode() + { + ta.startInteractiveMode(); + } + + //public void stopInteractiveMode(ArrayList handles[]) { + public void stopInteractiveMode(List> handles) { + tweakClient.shutdown(); + ta.stopInteractiveMode(); + + // remove space from the code (before and after) + removeSpacesFromCode(); + + // check which tabs were modified + boolean modified = false; + boolean[] modifiedTabs = getModifiedTabs(handles); + for (boolean mod : modifiedTabs) { + if (mod) { + modified = true; + break; + } + } + + if (modified) { + // ask to keep the values + int ret = Base.showYesNoQuestion(this, "Tweak Mode", + "Keep the changes?", + "You changed some values in your sketch. Would you like to keep the changes?"); + if (ret == 1) { + // NO! don't keep changes + loadSavedCode(); + // update the painter to draw the saved (old) code + ta.invalidate(); + } + else { + // YES! keep changes + // the new values are already present, just make sure the user can save the modified tabs + for (int i=0; i> handles, List> colorBoxes) { + // set OSC port of handles +// for (int i=0; i handles[]) { + private boolean[] getModifiedTabs(List> handles) { + boolean[] modifiedTabs = new boolean[handles.size()]; + + for (int i = 0; i < handles.size(); i++) { + for (Handle h : handles.get(i)) { + if (h.valueChanged()) { + modifiedTabs[i] = true; + } + } + } + return modifiedTabs; + } + + + public void initBaseCode() { + SketchCode[] code = sketch.getCode(); + + String space = new String(); + + for (int i=0; i> handles, boolean withSpaces) + { + SketchCode[] sketchCode = sketch.getCode(); + for (int tab=0; tab handles[]) + public boolean automateSketch(Sketch sketch, List> handles) { + SketchCode[] code = sketch.getCode(); + + if (code.length<1) + return false; + + if (handles.size() == 0) + return false; + + int setupStartPos = SketchParser.getSetupStart(baseCode[0]); + if (setupStartPos < 0) { + return false; + } + + // get port number from preferences.txt + int port; + String portStr = Preferences.get(prefTweakPort); + if (portStr == null) { + Preferences.set(prefTweakPort, "auto"); + portStr = "auto"; + } + + if (portStr.equals("auto")) { + // random port for udp (0xc000 - 0xffff) + port = (int)(Math.random()*0x3fff) + 0xc000; + } + else { + port = Preferences.getInteger(prefTweakPort); + } + + /* create the client that will send the new values to the sketch */ + tweakClient = new UDPTweakClient(port); + // update handles with a reference to the client object + for (int tab=0; tab 0) { + header += "int[] tweakmode_int = new int["+numOfInts+"];\n"; + } + if (numOfFloats > 0) { + header += "float[] tweakmode_float = new float["+numOfFloats+"];\n\n"; + } + + /* add the server code that will receive the value change messages */ + header += UDPTweakClient.getServerCode(port, numOfInts>0, numOfFloats>0); + header += "TweakModeServer tweakmode_Server;\n"; + + + header += "void tweakmode_initAllVars() {\n"; + //for (int i=0; i list : handles) { + //for (Handle n : handles[i]) { + for (Handle n : list) { + header += " " + n.name + " = " + n.strValue + ";\n"; + } + } + header += "}\n\n"; + header += "void tweakmode_initCommunication() {\n"; + header += " tweakmode_Server = new TweakModeServer();\n"; + header += " tweakmode_Server.setup();\n"; + header += " tweakmode_Server.start();\n"; + header += "}\n"; + + header += "\n\n\n\n\n"; + + // add call to our initAllVars and initOSC functions from the setup() function. + String addToSetup = "\n"+ + " tweakmode_initAllVars();\n"+ + " tweakmode_initCommunication();\n\n"; + + setupStartPos = SketchParser.getSetupStart(c); + c = replaceString(c, setupStartPos, setupStartPos, addToSetup); + + code[0].setProgram(header + c); + + /* print out modified code */ + String showModCode = Preferences.get(prefTweakShowCode); + if (showModCode == null) { + Preferences.setBoolean(prefTweakShowCode, false); + } + + if (Preferences.getBoolean(prefTweakShowCode)) { + System.out.println("\nTweakMode modified code:\n"); + for (int i=0; i handles[]) + private int howManyInts(List> handles) { + int count = 0; + //for (int i=0; i list : handles) { + //for (Handle n : handles[i]) { + for (Handle n : list) { + if (n.type == "int" || n.type == "hex" || n.type == "webcolor") { + count++; + } + } + } + return count; + } + + //private int howManyFloats(ArrayList handles[]) + private int howManyFloats(List> handles) { + int count = 0; + //for (int i=0; i list : handles) { + //for (Handle n : handles[i]) { + for (Handle n : list) { + if (n.type == "float") { + count++; + } + } + } + return count; + } } diff --git a/java/src/processing/mode/java/JavaMode.java b/java/src/processing/mode/java/JavaMode.java index a20d0b616..cc3494f43 100644 --- a/java/src/processing/mode/java/JavaMode.java +++ b/java/src/processing/mode/java/JavaMode.java @@ -32,7 +32,6 @@ import java.util.logging.Logger; import javax.swing.ImageIcon; import processing.app.*; -import processing.mode.java.debug.DebugEditor; import processing.mode.java.runner.Runner; import processing.mode.java.tweak.SketchParser; @@ -40,7 +39,7 @@ import processing.mode.java.tweak.SketchParser; public class JavaMode extends Mode { public Editor createEditor(Base base, String path, EditorState state) { - return new DebugEditor(base, path, state, this); + return new JavaEditor(base, path, state, this); } @@ -111,7 +110,7 @@ public class JavaMode extends Mode { public Runner handleRun(Sketch sketch, RunnerListener listener) throws SketchException { - final DebugEditor editor = (DebugEditor)listener; + final JavaEditor editor = (JavaEditor)listener; editor.errorCheckerService.quickErrorCheck(); if (enableTweak) { enableTweak = false; @@ -124,7 +123,7 @@ public class JavaMode extends Mode { public Runner handlePresent(Sketch sketch, RunnerListener listener) throws SketchException { - final DebugEditor editor = (DebugEditor)listener; + final JavaEditor editor = (JavaEditor)listener; editor.errorCheckerService.quickErrorCheck(); if (enableTweak) { enableTweak = false; @@ -157,7 +156,7 @@ public class JavaMode extends Mode { public Runner handleTweak(Sketch sketch, RunnerListener listener, final boolean present) throws SketchException { - final DebugEditor editor = (DebugEditor)listener; + final JavaEditor editor = (JavaEditor)listener; boolean launchInteractive = false; if (isSketchModified(sketch)) { diff --git a/java/src/processing/mode/java/debug/DebugEditor.java b/java/src/processing/mode/java/debug/DebugEditor.java deleted file mode 100644 index bdb285222..000000000 --- a/java/src/processing/mode/java/debug/DebugEditor.java +++ /dev/null @@ -1,2061 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing 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. - - 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. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -package processing.mode.java.debug; - -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Color; -import java.awt.Container; -import java.awt.EventQueue; -import java.awt.FlowLayout; -import java.awt.Font; -import java.awt.Frame; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.WindowEvent; -import java.awt.event.WindowFocusListener; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JCheckBoxMenuItem; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; -import javax.swing.border.EtchedBorder; -import javax.swing.table.TableModel; -import javax.swing.text.Document; - -import org.eclipse.jdt.core.compiler.IProblem; - -import processing.app.Base; -import processing.app.EditorState; -import processing.app.EditorToolbar; -import processing.app.Language; -import processing.app.Mode; -import processing.app.Preferences; -import processing.app.Sketch; -import processing.app.SketchCode; -import processing.app.Toolkit; -import processing.app.syntax.JEditTextArea; -import processing.app.syntax.PdeTextAreaDefaults; -import processing.core.PApplet; -import processing.mode.java.JavaEditor; -import processing.mode.java.JavaMode; -import processing.mode.java.pdex.ErrorBar; -import processing.mode.java.pdex.ErrorCheckerService; -import processing.mode.java.pdex.ErrorMessageSimplifier; -import processing.mode.java.pdex.Problem; -import processing.mode.java.pdex.JavaTextArea; -import processing.mode.java.pdex.XQConsoleToggle; -import processing.mode.java.pdex.XQErrorTable; -import processing.mode.java.tweak.ColorControlBox; -import processing.mode.java.tweak.Handle; -import processing.mode.java.tweak.SketchParser; -import processing.mode.java.tweak.UDPTweakClient; - - -/** - * Main View Class. Handles the editor window including tool bar and menu. Has - * access to the Sketch. Provides line highlighting (for breakpoints and the - * debuggers current line). - * - * @author Martin Leopold - * @author Manindra Moharana <me@mkmoharana.com> - */ -public class DebugEditor extends JavaEditor implements ActionListener { - // important fields from superclass - //protected Sketch sketch; - //private JMenu fileMenu; - //protected EditorToolbar toolbar; - - protected Color breakpointColor; // = new Color(240, 240, 240); // the background color for highlighting lines - protected Color currentLineColor; // = new Color(255, 255, 150); // the background color for highlighting lines - protected Color breakpointMarkerColor; // = new Color(74, 84, 94); // the color of breakpoint gutter markers - protected Color currentLineMarkerColor; // = new Color(226, 117, 0); // the color of current line gutter markers - protected List breakpointedLines = new ArrayList(); // breakpointed lines - protected LineHighlight currentLine; // line the debugger is currently suspended at - protected final String breakpointMarkerComment = " //<>//"; // breakpoint marker comment - - protected JMenu debugMenu; // the debug menu - - protected JMenuItem debugMenuItem; - protected JMenuItem continueMenuItem; - protected JMenuItem stopMenuItem; - - protected JMenuItem toggleBreakpointMenuItem; - protected JMenuItem listBreakpointsMenuItem; - - protected JMenuItem stepOverMenuItem; - protected JMenuItem stepIntoMenuItem; - protected JMenuItem stepOutMenuItem; - - protected JMenuItem printStackTraceMenuItem; - protected JMenuItem printLocalsMenuItem; - protected JMenuItem printThisMenuItem; - protected JMenuItem printSourceMenuItem; - protected JMenuItem printThreads; - - protected JMenuItem toggleVariableInspectorMenuItem; - - public JavaMode dmode; // the mode - protected Debugger dbg; // the debugger - protected VariableInspector vi; // the variable inspector frame - - public JavaTextArea ta; // the text area - public ErrorBar errorBar; - - protected XQConsoleToggle btnShowConsole; - protected XQConsoleToggle btnShowErrors; - protected JScrollPane errorTableScrollPane; - protected JPanel consoleProblemsPane; - protected XQErrorTable errorTable; - - public boolean compilationCheckEnabled = true; - - protected JCheckBoxMenuItem showWarnings; - public JCheckBoxMenuItem problemWindowMenuCB; - protected JCheckBoxMenuItem debugMessagesEnabled; - protected JMenuItem showOutline, showTabOutline; - protected JCheckBoxMenuItem writeErrorLog; - protected JCheckBoxMenuItem completionsEnabled; - - // TODO no way should this be public; make an accessor or protected - public boolean hasJavaTabs; - - - public DebugEditor(Base base, String path, EditorState state, Mode mode) { - super(base, path, state, mode); - - dmode = (JavaMode) mode; - dbg = new Debugger(this); - vi = new VariableInspector(this); - - // access to customized (i.e. subclassed) text area - ta = (JavaTextArea) textarea; - - // Add show usage option - JMenuItem showUsageItem = new JMenuItem("Show Usage..."); - showUsageItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleShowUsage(); - } - }); - ta.getRightClickPopup().add(showUsageItem); - - // add refactor option - JMenuItem renameItem = new JMenuItem("Rename..."); - renameItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleRefactor(); - } - }); - - // TODO: Add support for word select on right click and rename. -// ta.customPainter.addMouseListener(new MouseAdapter() { -// public void mouseClicked(MouseEvent evt) { -// System.out.println(evt); -// } -// }); - ta.getRightClickPopup().add(renameItem); - // set action on frame close -// addWindowListener(new WindowAdapter() { -// @Override -// public void windowClosing(WindowEvent e) { -// onWindowClosing(e); -// } -// }); - - Toolkit.setMenuMnemonics(ta.getRightClickPopup()); - - // load settings from theme.txt - breakpointColor = mode.getColor("breakpoint.bgcolor"); //, breakpointColor); - breakpointMarkerColor = mode.getColor("breakpoint.marker.color"); //, breakpointMarkerColor); - currentLineColor = mode.getColor("currentline.bgcolor"); //, currentLineColor); - currentLineMarkerColor = mode.getColor("currentline.marker.color"); //, currentLineMarkerColor); - - // set breakpoints from marker comments - for (LineID lineID : stripBreakpointComments()) { - //System.out.println("setting: " + lineID); - dbg.setBreakpoint(lineID); - } - getSketch().setModified(false); // setting breakpoints will flag sketch as modified, so override this here - - checkForJavaTabs(); - initializeErrorChecker(); - - ta.setECSandThemeforTextArea(errorCheckerService, dmode); - - addXQModeUI(); - debugToolbarEnabled = new AtomicBoolean(false); - //log("Sketch Path: " + path); - } - - private void addXQModeUI(){ - - // Adding ErrorBar - JPanel textAndError = new JPanel(); - Box box = (Box) textarea.getParent(); - box.remove(2); // Remove textArea from it's container, i.e Box - textAndError.setLayout(new BorderLayout()); - errorBar = new ErrorBar(this, textarea.getMinimumSize().height, dmode); - textAndError.add(errorBar, BorderLayout.EAST); - textarea.setBounds(0, 0, errorBar.getX() - 1, textarea.getHeight()); - textAndError.add(textarea); - box.add(textAndError); - - // Adding Error Table in a scroll pane - errorTableScrollPane = new JScrollPane(); - errorTable = new XQErrorTable(errorCheckerService); - // errorTableScrollPane.setBorder(new EmptyBorder(2, 2, 2, 2)); - errorTableScrollPane.setBorder(new EtchedBorder()); - errorTableScrollPane.setViewportView(errorTable); - - // Adding toggle console button - consolePanel.remove(2); - JPanel lineStatusPanel = new JPanel(); - lineStatusPanel.setLayout(new BorderLayout()); - btnShowConsole = new XQConsoleToggle(this, - XQConsoleToggle.CONSOLE, lineStatus.getHeight()); - btnShowErrors = new XQConsoleToggle(this, - XQConsoleToggle.ERRORSLIST, lineStatus.getHeight()); - btnShowConsole.addMouseListener(btnShowConsole); - - // lineStatusPanel.add(btnShowConsole, BorderLayout.EAST); - // lineStatusPanel.add(btnShowErrors); - btnShowErrors.addMouseListener(btnShowErrors); - - JPanel toggleButtonPanel = new JPanel(new BorderLayout()); - toggleButtonPanel.add(btnShowConsole, BorderLayout.EAST); - toggleButtonPanel.add(btnShowErrors, BorderLayout.WEST); - lineStatusPanel.add(toggleButtonPanel, BorderLayout.EAST); - lineStatus.setBounds(0, 0, toggleButtonPanel.getX() - 1, - toggleButtonPanel.getHeight()); - lineStatusPanel.add(lineStatus); - consolePanel.add(lineStatusPanel, BorderLayout.SOUTH); - lineStatusPanel.repaint(); - - // Adding JPanel with CardLayout for Console/Problems Toggle - consolePanel.remove(1); - consoleProblemsPane = new JPanel(new CardLayout()); - consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.ERRORSLIST); - consoleProblemsPane.add(console, XQConsoleToggle.CONSOLE); - consolePanel.add(consoleProblemsPane, BorderLayout.CENTER); - - // ensure completion gets hidden on editor losing focus - addWindowFocusListener(new WindowFocusListener() { - public void windowLostFocus(WindowEvent e) { - ta.hideSuggestion(); - } - public void windowGainedFocus(WindowEvent e) { - - } - }); - } - -// /** -// * Event handler called when closing the editor window. Kills the variable -// * inspector window. -// * -// * @param e the event object -// */ -// protected void onWindowClosing(WindowEvent e) { -// // remove var.inspector -// vi.dispose(); -// // quit running debug session -// dbg.stopDebug(); -// } - /** - * Used instead of the windowClosing event handler, since it's not called on - * mode switch. Called when closing the editor window. Stops running debug - * sessions and kills the variable inspector window. - */ - @Override - public void dispose() { - //System.out.println("window dispose"); - // quit running debug session - dbg.stopDebug(); - // remove var.inspector - vi.dispose(); - errorCheckerService.stopThread(); - // original dispose - super.dispose(); - } - - - // Added temporarily to dump error log. TODO: Remove this later - public void internalCloseRunner() { - if (JavaMode.errorLogsEnabled) { - writeErrorsToFile(); - } - super.internalCloseRunner(); - } - - - /** - * Writes all error messages to a csv file. - * For analytics purposes only. - */ - private void writeErrorsToFile() { - if (errorCheckerService.tempErrorLog.size() == 0) return; - - try { - System.out.println("Writing errors"); - StringBuilder sb = new StringBuilder(); - sb.append("Sketch: " + getSketch().getFolder() + ", " - + new java.sql.Timestamp(new java.util.Date().getTime()) - + "\nComma in error msg is substituted with ^ symbol\nFor separating arguments in error args | symbol is used\n"); - sb.append("ERROR TYPE, ERROR ARGS, ERROR MSG\n"); - - for (String errMsg : errorCheckerService.tempErrorLog.keySet()) { - IProblem ip = errorCheckerService.tempErrorLog.get(errMsg); - if (ip != null) { - sb.append(ErrorMessageSimplifier.getIDName(ip.getID())); - sb.append(','); - sb.append("{"); - for (int i = 0; i < ip.getArguments().length; i++) { - sb.append(ip.getArguments()[i]); - if (i < ip.getArguments().length-1) - sb.append("| "); - } - sb.append("}"); - sb.append(','); - sb.append(ip.getMessage().replace(',', '^')); - sb.append("\n"); - } - } - System.out.println(sb); - File opFile = new File(getSketch().getFolder(), "ErrorLogs" - + File.separator + "ErrorLog_" + System.currentTimeMillis() + ".csv"); - PApplet.saveStream(opFile, new ByteArrayInputStream(sb.toString() - .getBytes(Charset.defaultCharset()))); - } catch (Exception e) { - System.err.println("Failed to save log file for sketch " + getSketch().getName()); - e.printStackTrace(); - } - } - - - private AtomicBoolean debugToolbarEnabled; - - public boolean isDebugToolbarEnabled() { - return debugToolbarEnabled != null && debugToolbarEnabled.get(); - } - - - protected EditorToolbar javaToolbar, debugToolbar; - - /** - * Toggles between java mode and debug mode toolbar - */ - protected void switchToolbars(){ - final EditorToolbar nextToolbar; - if(debugToolbarEnabled.get()){ - // switch to java - if(javaToolbar == null) - javaToolbar = createToolbar(); - nextToolbar = javaToolbar; - debugToolbarEnabled.set(false); - Base.log("Switching to Java Mode Toolbar"); - } - else{ - // switch to debug - if(debugToolbar == null) - debugToolbar = new DebugToolbar(this, getBase()); - nextToolbar = debugToolbar; - debugToolbarEnabled.set(true); - Base.log("Switching to Debugger Toolbar"); - } - - SwingUtilities.invokeLater(new Runnable() { - public void run() { - Box upper = (Box)splitPane.getComponent(0); - upper.remove(0); - upper.add(nextToolbar, 0); - upper.validate(); - nextToolbar.repaint(); - toolbar = nextToolbar; - // The toolbar responds to shift down/up events - // in order to show the alt version of toolbar buttons. - // With toolbar switch, KeyListener has to be changed as well - for (KeyListener kl : textarea.getKeyListeners()) { - if(kl instanceof EditorToolbar) - { - textarea.removeKeyListener(kl); - textarea.addKeyListener(toolbar); - break; - } - } - ta.repaint(); - } - }); - } - - /** - * Creates the debug menu. Includes ActionListeners for the menu items. - * Intended for adding to the menu bar. - * - * @return The debug menu - */ - protected JMenu buildDebugMenu() { - debugMenu = new JMenu(Language.text("menu.debug")); - //debugMenu = new JMenu("PDE X"); - - JCheckBoxMenuItem toggleDebugger = new JCheckBoxMenuItem(Language.text("menu.debug.show_debug_toolbar")); - toggleDebugger.setSelected(false); - toggleDebugger.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - switchToolbars(); - } - }); - debugMenu.add(toggleDebugger); - debugMenuItem = Toolkit.newJMenuItemAlt(Language.text("menu.debug.debug"), KeyEvent.VK_R); - debugMenuItem.addActionListener(this); - continueMenuItem = Toolkit.newJMenuItem(Language.text("menu.debug.continue"), KeyEvent.VK_U); - continueMenuItem.addActionListener(this); - stopMenuItem = new JMenuItem(Language.text("menu.debug.stop")); - stopMenuItem.addActionListener(this); - - toggleBreakpointMenuItem = Toolkit.newJMenuItem(Language.text("menu.debug.toggle_breakpoint"), KeyEvent.VK_B); - toggleBreakpointMenuItem.addActionListener(this); - listBreakpointsMenuItem = new JMenuItem(Language.text("menu.debug.list_breakpoints")); - listBreakpointsMenuItem.addActionListener(this); - - stepOverMenuItem = Toolkit.newJMenuItem(Language.text("menu.debug.step"), KeyEvent.VK_J); - stepOverMenuItem.addActionListener(this); - stepIntoMenuItem = Toolkit.newJMenuItemShift(Language.text("menu.debug.step_into"), KeyEvent.VK_J); - stepIntoMenuItem.addActionListener(this); - stepOutMenuItem = Toolkit.newJMenuItemAlt(Language.text("menu.debug.step_out"), KeyEvent.VK_J); - stepOutMenuItem.addActionListener(this); - - printStackTraceMenuItem = new JMenuItem(Language.text("menu.debug.print_stack_trace")); - printStackTraceMenuItem.addActionListener(this); - printLocalsMenuItem = new JMenuItem(Language.text("menu.debug.print_locals")); - printLocalsMenuItem.addActionListener(this); - printThisMenuItem = new JMenuItem(Language.text("menu.debug.print_fields")); - printThisMenuItem.addActionListener(this); - printSourceMenuItem = new JMenuItem(Language.text("menu.debug.print_source_location")); - printSourceMenuItem.addActionListener(this); - printThreads = new JMenuItem(Language.text("menu.debug.print_threads")); - printThreads.addActionListener(this); - - toggleVariableInspectorMenuItem = Toolkit.newJMenuItem(Language.text("menu.debug.toggle_variable_inspector"), KeyEvent.VK_I); - toggleVariableInspectorMenuItem.addActionListener(this); - - debugMenu.add(debugMenuItem); - debugMenu.add(continueMenuItem); - debugMenu.add(stopMenuItem); - debugMenu.addSeparator(); - debugMenu.add(toggleBreakpointMenuItem); - debugMenu.add(listBreakpointsMenuItem); - debugMenu.addSeparator(); - debugMenu.add(stepOverMenuItem); - debugMenu.add(stepIntoMenuItem); - debugMenu.add(stepOutMenuItem); - debugMenu.addSeparator(); - debugMenu.add(printStackTraceMenuItem); - debugMenu.add(printLocalsMenuItem); - debugMenu.add(printThisMenuItem); - debugMenu.add(printSourceMenuItem); - debugMenu.add(printThreads); - debugMenu.addSeparator(); - debugMenu.add(toggleVariableInspectorMenuItem); - // debugMenu.addSeparator(); - - // XQMode menu items - /* - JCheckBoxMenuItem item; - item = new JCheckBoxMenuItem("Error Checker Enabled"); - item.setSelected(ExperimentalMode.errorCheckEnabled); - item.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - ExperimentalMode.errorCheckEnabled = ((JCheckBoxMenuItem) e.getSource()).isSelected(); - errorCheckerService.handleErrorCheckingToggle(); - dmode.savePreferences(); - } - }); - debugMenu.add(item); - - problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); - // problemWindowMenuCB.setSelected(true); - problemWindowMenuCB.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (errorCheckerService.errorWindow == null) { - return; - } - errorCheckerService.errorWindow - .setVisible(((JCheckBoxMenuItem) e.getSource()) - .isSelected()); - // switch to console, now that Error Window is open - showProblemListView(XQConsoleToggle.CONSOLE); - } - }); - debugMenu.add(problemWindowMenuCB); - - showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); - showWarnings.setSelected(ExperimentalMode.warningsEnabled); - showWarnings.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - ExperimentalMode.warningsEnabled = ((JCheckBoxMenuItem) e - .getSource()).isSelected(); - errorCheckerService.runManualErrorCheck(); - dmode.savePreferences(); - } - }); - debugMenu.add(showWarnings); - - completionsEnabled = new JCheckBoxMenuItem("Code Completion Enabled"); - completionsEnabled.setSelected(ExperimentalMode.codeCompletionsEnabled); - completionsEnabled.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ExperimentalMode.codeCompletionsEnabled = (((JCheckBoxMenuItem) e - .getSource()).isSelected()); - dmode.savePreferences(); - } - }); - debugMenu.add(completionsEnabled); - - debugMessagesEnabled = new JCheckBoxMenuItem("Show Debug Messages"); - debugMessagesEnabled.setSelected(ExperimentalMode.DEBUG); - debugMessagesEnabled.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ExperimentalMode.DEBUG = ((JCheckBoxMenuItem) e - .getSource()).isSelected(); - dmode.savePreferences(); - } - }); - debugMenu.add(debugMessagesEnabled); - - - writeErrorLog = new JCheckBoxMenuItem("Write Errors to Log"); - writeErrorLog.setSelected(ExperimentalMode.errorLogsEnabled); - writeErrorLog.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ExperimentalMode.errorLogsEnabled = ((JCheckBoxMenuItem) e - .getSource()).isSelected(); - dmode.savePreferences(); - } - }); - debugMenu.add(writeErrorLog); - - debugMenu.addSeparator(); - JMenuItem jitem = new JMenuItem("PDE X on GitHub"); - jitem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Base.openURL("https://github.com/processing/processing-experimental"); - } - }); - debugMenu.add(jitem); - */ - showOutline = Toolkit.newJMenuItem(Language.text("menu.debug.show_sketch_outline"), KeyEvent.VK_L); - showOutline.addActionListener(this); - debugMenu.add(showOutline); - - showTabOutline = Toolkit.newJMenuItem(Language.text("menu.debug.show_tabs_list"), KeyEvent.VK_Y); - showTabOutline.addActionListener(this); - debugMenu.add(showTabOutline); - - - return debugMenu; - } - - @Override - public JMenu buildModeMenu() { - return buildDebugMenu(); - } - - public JMenu buildSketchMenu() { - JMenuItem runItem = Toolkit.newJMenuItem(DebugToolbar - .getTitle(DebugToolbar.RUN, false), 'R'); - runItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleRun(); - } - }); - - JMenuItem presentItem = Toolkit.newJMenuItemShift(DebugToolbar - .getTitle(DebugToolbar.RUN, true), 'R'); - presentItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handlePresent(); - } - }); - - JMenuItem stopItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.STOP, - false)); - stopItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleStop(); - } - }); - - JMenuItem enableTweak = Toolkit.newJMenuItemShift(Language.text("menu.sketch.tweak"), 'T'); - enableTweak.setSelected(JavaMode.enableTweak); - enableTweak.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JavaMode.enableTweak = true; - handleRun(); - } - }); - - return buildSketchMenu(new JMenuItem[] { - runItem, presentItem, enableTweak, stopItem }); - } - - /** - * Callback for menu items. Implementation of Swing ActionListener. - * - * @param ae Action event - */ - @Override - public void actionPerformed(ActionEvent ae) { - //System.out.println("ActionEvent: " + ae.toString()); - - JMenuItem source = (JMenuItem) ae.getSource(); - if (source == debugMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Debug' menu item"); - //dmode.handleDebug(sketch, this); - dbg.startDebug(); - } else if (source == stopMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Stop' menu item"); - //dmode.handleDebug(sketch, this); - dbg.stopDebug(); - } else if (source == continueMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Continue' menu item"); - //dmode.handleDebug(sketch, this); - dbg.continueDebug(); - } else if (source == stepOverMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Over' menu item"); - dbg.stepOver(); - } else if (source == stepIntoMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Into' menu item"); - dbg.stepInto(); - } else if (source == stepOutMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Out' menu item"); - dbg.stepOut(); - } else if (source == printStackTraceMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Stack Trace' menu item"); - dbg.printStackTrace(); - } else if (source == printLocalsMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Locals' menu item"); - dbg.printLocals(); - } else if (source == printThisMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print This' menu item"); - dbg.printThis(); - } else if (source == printSourceMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Source' menu item"); - dbg.printSource(); - } else if (source == printThreads) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Threads' menu item"); - dbg.printThreads(); - } else if (source == toggleBreakpointMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' menu item"); - dbg.toggleBreakpoint(); - } else if (source == listBreakpointsMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'List Breakpoints' menu item"); - dbg.listBreakpoints(); - } else if (source == toggleVariableInspectorMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item"); - toggleVariableInspector(); - } else if (source.equals(showOutline)){ - Base.log("Show Sketch Outline:"); - errorCheckerService.getASTGenerator().showSketchOutline(); - } - else if (source.equals(showTabOutline)){ - Base.log("Show Tab Outline:"); - errorCheckerService.getASTGenerator().showTabOutline(); - } - } - -// @Override -// public void handleRun() { -// dbg.continueDebug(); -// } - /** - * Event handler called when hitting the stop button. Stops a running debug - * session or performs standard stop action if not currently debugging. - */ - @Override - public void handleStop() { - if (dbg.isStarted()) { - dbg.stopDebug(); - } else { - super.handleStop(); - } - } - - /** - * Event handler called when loading another sketch in this editor. Clears - * breakpoints of previous sketch. - * - * @param path - * @return true if a sketch was opened, false if aborted - */ - @Override - protected boolean handleOpenInternal(String path) { - // log("handleOpenInternal, path: " + path); - boolean didOpen = super.handleOpenInternal(path); - if (didOpen && dbg != null) { - // should already been stopped (open calls handleStop) - dbg.clearBreakpoints(); - clearBreakpointedLines(); // force clear breakpoint highlights - variableInspector().reset(); // clear contents of variable inspector - } - //if(didOpen){ - // autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); // this is used instead of loadAutosaver(), temp measure - // loadAutoSaver(); - // viewingAutosaveBackup = autosaver.isAutoSaveBackup(); - // log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); - //} - return didOpen; - } - - /** - * Extract breakpointed lines from source code marker comments. This removes - * marker comments from the editor text. Intended to be called on loading a - * sketch, since re-setting the sketches contents after removing the markers - * will clear all breakpoints. - * - * @return the list of {@link LineID}s where breakpoint marker comments were - * removed from. - */ - protected List stripBreakpointComments() { - List bps = new ArrayList(); - // iterate over all tabs - Sketch sketch = getSketch(); - for (int i = 0; i < sketch.getCodeCount(); i++) { - SketchCode tab = sketch.getCode(i); - String code = tab.getProgram(); - String lines[] = code.split("\\r?\\n"); // newlines not included - //System.out.println(code); - - // scan code for breakpoint comments - int lineIdx = 0; - for (String line : lines) { - //System.out.println(line); - if (line.endsWith(breakpointMarkerComment)) { - LineID lineID = new LineID(tab.getFileName(), lineIdx); - bps.add(lineID); - //System.out.println("found breakpoint: " + lineID); - // got a breakpoint - //dbg.setBreakpoint(lineID); - int index = line.lastIndexOf(breakpointMarkerComment); - lines[lineIdx] = line.substring(0, index); - } - lineIdx++; - } - //tab.setProgram(code); - code = PApplet.join(lines, "\n"); - setTabContents(tab.getFileName(), code); - } - return bps; - } - - /** - * Add breakpoint marker comments to the source file of a specific tab. This - * acts on the source file on disk, not the editor text. Intended to be - * called just after saving the sketch. - * - * @param tabFilename the tab file name - */ - protected void addBreakpointComments(String tabFilename) { - SketchCode tab = getTab(tabFilename); - if(tab == null) { - // this method gets called twice when saving sketch for the first time - // once with new name and another with old(causing NPE). Keep an eye out - // for potential issues. See #2675. TODO: - Base.loge("Illegal tab name to addBreakpointComments() " + tabFilename); - return; - } - List bps = dbg.getBreakpoints(tab.getFileName()); - - // load the source file - File sourceFile = new File(sketch.getFolder(), tab.getFileName()); - //System.out.println("file: " + sourceFile); - try { - String code = Base.loadFile(sourceFile); - //System.out.println("code: " + code); - String lines[] = code.split("\\r?\\n"); // newlines not included - for (LineBreakpoint bp : bps) { - //System.out.println("adding bp: " + bp.lineID()); - lines[bp.lineID().lineIdx()] += breakpointMarkerComment; - } - code = PApplet.join(lines, "\n"); - //System.out.println("new code: " + code); - Base.saveFile(code, sourceFile); - } catch (IOException ex) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.SEVERE, null, ex); - } - } - - @Override - public boolean handleSave(boolean immediately) { - //System.out.println("handleSave " + immediately); - - //log("handleSave, viewing autosave? " + viewingAutosaveBackup); - /* If user wants to save a backup, the backup sketch should get - * copied to the main sketch directory, simply reload the main sketch. - */ - if(viewingAutosaveBackup){ - /* - File files[] = autosaver.getSketchBackupFolder().listFiles(); - File src = autosaver.getSketchBackupFolder(), dst = autosaver - .getActualSketchFolder(); - for (File f : files) { - log("Copying " + f.getAbsolutePath() + " to " + dst.getAbsolutePath()); - try { - if (f.isFile()) { - f.delete(); - Base.copyFile(f, new File(dst + File.separator + f.getName())); - } else { - Base.removeDir(f); - Base.copyDir(f, new File(dst + File.separator + f.getName())); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - File sk = autosaver.getActualSketchFolder(); - Base.removeDir(autosaver.getAutoSaveDir()); - //handleOpenInternal(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde"); - getBase().handleOpen(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde"); - //viewingAutosaveBackup = false; - */ - } - - // note modified tabs - final List modified = new ArrayList(); - for (int i = 0; i < getSketch().getCodeCount(); i++) { - SketchCode tab = getSketch().getCode(i); - if (tab.isModified()) { - modified.add(tab.getFileName()); - } - } - - boolean saved = super.handleSave(immediately); - if (saved) { - if (immediately) { - for (String tabFilename : modified) { - addBreakpointComments(tabFilename); - } - } else { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - for (String tabFilename : modified) { - addBreakpointComments(tabFilename); - } - } - }); - } - } - // if file location has changed, update autosaver - // autosaver.reloadAutosaveDir(); - return saved; - } - - @Override - public boolean handleSaveAs() { - //System.out.println("handleSaveAs"); - String oldName = getSketch().getCode(0).getFileName(); - //System.out.println("old name: " + oldName); - boolean saved = super.handleSaveAs(); - if (saved) { - // re-set breakpoints in first tab (name has changed) - List bps = dbg.getBreakpoints(oldName); - dbg.clearBreakpoints(oldName); - String newName = getSketch().getCode(0).getFileName(); - //System.out.println("new name: " + newName); - for (LineBreakpoint bp : bps) { - LineID line = new LineID(newName, bp.lineID().lineIdx()); - //System.out.println("setting: " + line); - dbg.setBreakpoint(line); - } - // add breakpoint marker comments to source file - for (int i = 0; i < getSketch().getCodeCount(); i++) { - addBreakpointComments(getSketch().getCode(i).getFileName()); - } - - // set new name of variable inspector - vi.setTitle(getSketch().getName()); - } - // if file location has changed, update autosaver -// autosaver.reloadAutosaveDir(); - return saved; - } - - - private boolean viewingAutosaveBackup; - - - /** - * Set text contents of a specific tab. Updates underlying document and text - * area. Clears Breakpoints. - * - * @param tabFilename the tab file name - * @param code the text to set - */ - protected void setTabContents(String tabFilename, String code) { - // remove all breakpoints of this tab - dbg.clearBreakpoints(tabFilename); - - SketchCode currentTab = getCurrentTab(); - - // set code of tab - SketchCode tab = getTab(tabFilename); - if (tab != null) { - tab.setProgram(code); - // this updates document and text area - // TODO: does this have any negative effects? (setting the doc to null) - tab.setDocument(null); - setCode(tab); - - // switch back to original tab - setCode(currentTab); - } - } - - /** - * Clear the console. - */ - public void clearConsole() { - console.clear(); - } - - /** - * Clear current text selection. - */ - public void clearSelection() { - setSelection(getCaretOffset(), getCaretOffset()); - } - - /** - * Select a line in the current tab. - * - * @param lineIdx 0-based line number - */ - public void selectLine(int lineIdx) { - setSelection(getLineStartOffset(lineIdx), getLineStopOffset(lineIdx)); - } - - /** - * Set the cursor to the start of a line. - * - * @param lineIdx 0-based line number - */ - public void cursorToLineStart(int lineIdx) { - setSelection(getLineStartOffset(lineIdx), getLineStartOffset(lineIdx)); - } - - /** - * Set the cursor to the end of a line. - * - * @param lineIdx 0-based line number - */ - public void cursorToLineEnd(int lineIdx) { - setSelection(getLineStopOffset(lineIdx), getLineStopOffset(lineIdx)); - } - - /** - * Switch to a tab. - * - * @param tabFileName the file name identifying the tab. (as in - * {@link SketchCode#getFileName()}) - */ - public void switchToTab(String tabFileName) { - Sketch s = getSketch(); - for (int i = 0; i < s.getCodeCount(); i++) { - if (tabFileName.equals(s.getCode(i).getFileName())) { - s.setCurrentCode(i); - break; - } - } - } - - - /** - * Access the debugger. - * - * @return the debugger controller object - */ - public Debugger dbg() { - return dbg; - } - - - /** - * Access the mode. - * - * @return the mode object - */ - public JavaMode mode() { - return dmode; - } - - /** - * Access the custom text area object. - * - * @return the text area object - */ - public JavaTextArea textArea() { - return ta; - } - - - /** - * Grab current contents of the sketch window, advance the console, stop any - * other running sketches, auto-save the user's code... not in that order. - */ - @Override - public void prepareRun() { - autoSave(); - super.prepareRun(); - } - - /** - * Displays a JDialog prompting the user to save when the user hits - * run/present/etc. - */ - protected void autoSave() { - if (!JavaMode.autoSaveEnabled) - return; - - try { - // if (sketch.isUntitled() && - // ExperimentalMode.untitledAutoSaveEnabled) { - // if (handleSave(true)) - // statusTimedNotice("Saved. Running...", 5); - // else - // statusTimedNotice("Save Canceled. Running anyway...", 5); - // } - // else - if (sketch.isModified() && !sketch.isUntitled()) { - if (JavaMode.autoSavePromptEnabled) { - final JDialog autoSaveDialog = new JDialog( - base.getActiveEditor(), this.getSketch().getName(), - true); - Container container = autoSaveDialog.getContentPane(); - - JPanel panelMain = new JPanel(); - panelMain.setBorder(BorderFactory.createEmptyBorder(4, 0, - 2, 2)); - panelMain.setLayout(new BoxLayout(panelMain, - BoxLayout.PAGE_AXIS)); - - JPanel panelLabel = new JPanel(new FlowLayout( - FlowLayout.LEFT)); - JLabel label = new JLabel( - " There are unsaved" - + " changes in your sketch.
" - + "    Do you want to save it before" - + " running? "); - label.setFont(new Font(label.getFont().getName(), - Font.PLAIN, label.getFont().getSize() + 1)); - panelLabel.add(label); - panelMain.add(panelLabel); - final JCheckBox dontRedisplay = new JCheckBox( - "Remember this decision"); - - JPanel panelButtons = new JPanel(new FlowLayout( - FlowLayout.CENTER, 8, 2)); - JButton btnRunSave = new JButton("Save and Run"); - btnRunSave.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - handleSave(true); - if (dontRedisplay.isSelected()) { - JavaMode.autoSavePromptEnabled = !dontRedisplay.isSelected(); - JavaMode.defaultAutoSaveEnabled = true; - dmode.savePreferences(); - } - autoSaveDialog.dispose(); - } - }); - panelButtons.add(btnRunSave); - JButton btnRunNoSave = new JButton("Run, Don't Save"); - btnRunNoSave.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (dontRedisplay.isSelected()) { - JavaMode.autoSavePromptEnabled = !dontRedisplay.isSelected(); - JavaMode.defaultAutoSaveEnabled = false; - dmode.savePreferences(); - } - autoSaveDialog.dispose(); - } - }); - panelButtons.add(btnRunNoSave); - panelMain.add(panelButtons); - - JPanel panelCheck = new JPanel(); - panelCheck - .setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); - panelCheck.add(dontRedisplay); - panelMain.add(panelCheck); - - container.add(panelMain); - - autoSaveDialog.setResizable(false); - autoSaveDialog.pack(); - autoSaveDialog - .setLocationRelativeTo(base.getActiveEditor()); - autoSaveDialog.setVisible(true); - - } else if (JavaMode.defaultAutoSaveEnabled) { - handleSave(true); - } - } - } catch (Exception e) { - statusError(e); - } - - } - - /** - * Access variable inspector window. - * - * @return the variable inspector object - */ - public VariableInspector variableInspector() { - return vi; - } - - public DebugToolbar toolbar() { - if(toolbar instanceof DebugToolbar) - return (DebugToolbar) toolbar; - return null; - } - - /** - * Show the variable inspector window. - */ - public void showVariableInspector() { - vi.setVisible(true); - } - - /** - * Set visibility of the variable inspector window. - * - * @param visible true to set the variable inspector visible, false for - * invisible. - */ - public void showVariableInspector(boolean visible) { - vi.setVisible(visible); - } - - /** - * Hide the variable inspector window. - */ - public void hideVariableInspector() { - vi.setVisible(true); - } - - /** - * Toggle visibility of the variable inspector window. - */ - public void toggleVariableInspector() { - vi.setFocusableWindowState(false); // to not get focus when set visible - vi.setVisible(!vi.isVisible()); - vi.setFocusableWindowState(true); // allow to get focus again - } - - /** - * Text area factory method. Instantiates the customized TextArea. - * - * @return the customized text area object - */ - @Override -// protected JEditTextArea createTextArea() { -// //System.out.println("overriding creation of text area"); -// return new TextArea(new PdeTextAreaDefaults(mode), this); -// } - protected JEditTextArea createTextArea() { - return new JavaTextArea(new PdeTextAreaDefaults(mode), this); - //return new JavaTextArea(new PdeTextAreaDefaults(mode), new JavaInputHandler(this), this); - /* - return new TextArea(new PdeTextAreaDefaults(mode), new PdeInputHandler(), this) { - // Forwards key events directly to the input handler. This is slightly - // faster than using a KeyListener because some Swing overhead is avoided. - PdeKeyListener editorListener = new PdeKeyListener(DebugEditor.this, this); - - // Moved out of JEditTextArea for 3.0a6 to remove dependency on Java Mode - public void processKeyEvent(KeyEvent evt) { - // this had to be added in Processing 007X, because the menu key - // events weren't making it up to the frame. - super.processKeyEvent(evt); - - if (inputHandler != null) { - switch (evt.getID()) { - case KeyEvent.KEY_TYPED: - if ((editorListener == null) || !editorListener.keyTyped(evt)) { - inputHandler.keyTyped(evt); - } - break; - case KeyEvent.KEY_PRESSED: - if ((editorListener == null) || !editorListener.keyPressed(evt)) { - inputHandler.keyPressed(evt); - } - break; - case KeyEvent.KEY_RELEASED: - inputHandler.keyReleased(evt); - break; - } - } - } - }; - */ - } - - - /** - * Set the line to highlight as currently suspended at. Will override the - * breakpoint color, if set. Switches to the appropriate tab and scroll to - * the line by placing the cursor there. - * - * @param line the line to highlight as current suspended line - */ - public void setCurrentLine(LineID line) { - clearCurrentLine(); - if (line == null) { - return; // safety, e.g. when no line mapping is found and the null line is used. - } - switchToTab(line.fileName()); - // scroll to line, by setting the cursor - cursorToLineStart(line.lineIdx()); - // highlight line - currentLine = new LineHighlight(line.lineIdx(), currentLineColor, this); - currentLine.setMarker(ta.currentLineMarker, currentLineMarkerColor); - currentLine.setPriority(10); // fixes current line being hidden by the breakpoint when moved down - } - - /** - * Clear the highlight for the debuggers current line. - */ - public void clearCurrentLine() { - if (currentLine != null) { - currentLine.clear(); - currentLine.dispose(); - - // revert to breakpoint color if any is set on this line - for (LineHighlight hl : breakpointedLines) { - if (hl.lineID().equals(currentLine.lineID())) { - hl.paint(); - break; - } - } - currentLine = null; - } - } - - /** - * Add highlight for a breakpointed line. - * - * @param lineID the line id to highlight as breakpointed - */ - public void addBreakpointedLine(LineID lineID) { - LineHighlight hl = new LineHighlight(lineID, breakpointColor, this); - hl.setMarker(ta.breakpointMarker, breakpointMarkerColor); - breakpointedLines.add(hl); - // repaint current line if it's on this line - if (currentLine != null && currentLine.lineID().equals(lineID)) { - currentLine.paint(); - } - } - - /** - * Add highlight for a breakpointed line on the current tab. - * - * @param lineIdx the line index on the current tab to highlight as - * breakpointed - */ - //TODO: remove and replace by {@link #addBreakpointedLine(LineID lineID)} - public void addBreakpointedLine(int lineIdx) { - addBreakpointedLine(getLineIDInCurrentTab(lineIdx)); - } - - /** - * Remove a highlight for a breakpointed line. Needs to be on the current - * tab. - * - * @param lineIdx the line index on the current tab to remove a breakpoint - * highlight from - */ - public void removeBreakpointedLine(int lineIdx) { - LineID line = getLineIDInCurrentTab(lineIdx); - //System.out.println("line id: " + line.fileName() + " " + line.lineIdx()); - LineHighlight foundLine = null; - for (LineHighlight hl : breakpointedLines) { - if (hl.lineID.equals(line)) { - foundLine = hl; - break; - } - } - if (foundLine != null) { - foundLine.clear(); - breakpointedLines.remove(foundLine); - foundLine.dispose(); - // repaint current line if it's on this line - if (currentLine != null && currentLine.lineID().equals(line)) { - currentLine.paint(); - } - } - } - - /** - * Remove all highlights for breakpointed lines. - */ - public void clearBreakpointedLines() { - for (LineHighlight hl : breakpointedLines) { - hl.clear(); - hl.dispose(); - } - breakpointedLines.clear(); // remove all breakpoints - // fix highlights not being removed when tab names have changed due to opening a new sketch in same editor - ta.clearLineBgColors(); // force clear all highlights - ta.clearGutterText(); - - // repaint current line - if (currentLine != null) { - currentLine.paint(); - } - } - - /** - * Retrieve a {@link LineID} object for a line on the current tab. - * - * @param lineIdx the line index on the current tab - * @return the {@link LineID} object representing a line index on the - * current tab - */ - public LineID getLineIDInCurrentTab(int lineIdx) { - return new LineID(getSketch().getCurrentCode().getFileName(), lineIdx); - } - - /** - * Retrieve line of sketch where the cursor currently resides. - * - * @return the current {@link LineID} - */ - protected LineID getCurrentLineID() { - String tab = getSketch().getCurrentCode().getFileName(); - int lineNo = getTextArea().getCaretLine(); - return new LineID(tab, lineNo); - } - - /** - * Check whether a {@link LineID} is on the current tab. - * - * @param line the {@link LineID} - * @return true, if the {@link LineID} is on the current tab. - */ - public boolean isInCurrentTab(LineID line) { - return line.fileName().equals(getSketch().getCurrentCode().getFileName()); - } - - /** - * Event handler called when switching between tabs. Loads all line - * background colors set for the tab. - * - * @param code tab to switch to - */ - @Override - protected void setCode(SketchCode code) { - //System.out.println("tab switch: " + code.getFileName()); - super.setCode(code); // set the new document in the textarea, etc. need to do this first - - // set line background colors for tab - if (ta != null) { // can be null when setCode is called the first time (in constructor) - // clear all line backgrounds - ta.clearLineBgColors(); - // clear all gutter text - ta.clearGutterText(); - // load appropriate line backgrounds for tab - // first paint breakpoints - for (LineHighlight hl : breakpointedLines) { - if (isInCurrentTab(hl.lineID())) { - hl.paint(); - } - } - // now paint current line (if any) - if (currentLine != null) { - if (isInCurrentTab(currentLine.lineID())) { - currentLine.paint(); - } - } - } - if (dbg() != null && dbg().isStarted()) { - dbg().startTrackingLineChanges(); - } - } - - /** - * Get a tab by its file name. - * - * @param fileName the filename to search for. - * @return the {@link SketchCode} object representing the tab, or null if - * not found - */ - public SketchCode getTab(String fileName) { - Sketch s = getSketch(); - for (SketchCode c : s.getCode()) { - if (c.getFileName().equals(fileName)) { - return c; - } - } - return null; - } - - /** - * Retrieve the current tab. - * - * @return the {@link SketchCode} representing the current tab - */ - public SketchCode getCurrentTab() { - return getSketch().getCurrentCode(); - } - - /** - * Access the currently edited document. - * - * @return the document object - */ - public Document currentDocument() { - //return ta.getDocument(); - return getCurrentTab().getDocument(); - } - - /** - * Factory method for the editor toolbar. Instantiates the customized - * toolbar. - * - * @return the toolbar - */ - /*@Override - public EditorToolbar createToolbar() { - return new DebugToolbar(this, base); - }*/ - - /** - * Event Handler for double clicking in the left hand gutter area. - * - * @param lineIdx the line (0-based) that was double clicked - */ - public void gutterDblClicked(int lineIdx) { - if (dbg != null) { - dbg.toggleBreakpoint(lineIdx); - } - } - - public void statusBusy() { - statusNotice("Debugger busy..."); - } - - public void statusHalted() { - statusNotice("Debugger halted."); - } - - public static final int STATUS_EMPTY = 100, STATUS_COMPILER_ERR = 200, - STATUS_WARNING = 300, STATUS_INFO = 400, STATUS_ERR = 500; - public int statusMessageType = STATUS_EMPTY; - public String statusMessage; - public void statusMessage(final String what, int type){ - // Don't re-display the old message again - if(type != STATUS_EMPTY) { - if(what.equals(statusMessage) && type == statusMessageType) { - return; - } - } - statusMessage = new String(what); - statusMessageType = type; - switch (type) { - case STATUS_COMPILER_ERR: - case STATUS_ERR: - super.statusError(what); - break; - case STATUS_INFO: - case STATUS_WARNING: - statusNotice(what); - break; - } - // Don't need to clear compiler error messages - if(type == STATUS_COMPILER_ERR) return; - - // Clear the message after a delay - SwingWorker s = new SwingWorker() { - @Override - protected Object doInBackground() throws Exception { - try { - Thread.sleep(2 * 1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - statusEmpty(); - return null; - } - }; - s.execute(); - } - - public void statusEmpty(){ - statusMessage = null; - statusMessageType = STATUS_EMPTY; - super.statusEmpty(); - } - - public ErrorCheckerService errorCheckerService; - - /** - * Initializes and starts Error Checker Service - */ - private void initializeErrorChecker() { - Thread errorCheckerThread = null; - - if (errorCheckerThread == null) { - errorCheckerService = new ErrorCheckerService(this); - errorCheckerThread = new Thread(errorCheckerService); - try { - errorCheckerThread.start(); - } catch (Exception e) { - System.err - .println("Error Checker Service not initialized [XQEditor]: " - + e); - // e.printStackTrace(); - } - // System.out.println("Error Checker Service initialized."); - } - - } - - /** - * Updates the error bar - * @param problems - */ - public void updateErrorBar(ArrayList problems) { - errorBar.updateErrorPoints(problems); - } - - /** - * Toggle between Console and Errors List - * - * @param buttonName - * - Button Label - */ - public void showProblemListView(String buttonName) { - CardLayout cl = (CardLayout) consoleProblemsPane.getLayout(); - cl.show(consoleProblemsPane, buttonName); - } - - /** - * Updates the error table - * @param tableModel - * @return - */ - synchronized public boolean updateTable(final TableModel tableModel) { - return errorTable.updateTable(tableModel); - } - - - /** - * Handle whether the tiny red error indicator is shown near the error button - * at the bottom of the PDE - */ - public void updateErrorToggle(){ - btnShowErrors.updateMarker(JavaMode.errorCheckEnabled && - errorCheckerService.hasErrors(), - errorBar.errorColor); - } - - - /** - * Handle refactor operation - */ - private void handleRefactor() { - Base.log("Caret at:" + ta.getLineText(ta.getCaretLine())); - errorCheckerService.getASTGenerator().handleRefactor(); - } - - - /** - * Handle show usage operation - */ - private void handleShowUsage() { - Base.log("Caret at:" + ta.getLineText(ta.getCaretLine())); - errorCheckerService.getASTGenerator().handleShowUsage(); - } - - - /** - * Checks if the sketch contains java tabs. If it does, the editor ain't built - * for it, yet. Also, user should really start looking at more powerful IDEs - * likeEclipse. Disable compilation check and some more features. - */ - private void checkForJavaTabs() { - hasJavaTabs = false; - for (int i = 0; i < this.getSketch().getCodeCount(); i++) { - if (this.getSketch().getCode(i).getExtension().equals("java")) { - compilationCheckEnabled = false; - hasJavaTabs = true; - JOptionPane.showMessageDialog(new Frame(), this - .getSketch().getName() - + " contains .java tabs. Some editor features are not supported " + - "for .java tabs and will be disabled."); - break; - } - } - } - - - protected void applyPreferences() { - super.applyPreferences(); - if (dmode != null) { - dmode.loadPreferences(); - Base.log("Applying prefs"); - // trigger it once to refresh UI - errorCheckerService.runManualErrorCheck(); - } - } - - - // TweakMode code - /** - * Show warnings menu item - */ - //protected JCheckBoxMenuItem enableTweakCB; - - public static final String prefTweakPort = "tweak.port"; - public static final String prefTweakShowCode = "tweak.showcode"; - - public String[] baseCode; - - final static int SPACE_AMOUNT = 0; - - UDPTweakClient tweakClient; - - public void startInteractiveMode() - { - ta.startInteractiveMode(); - } - - //public void stopInteractiveMode(ArrayList handles[]) { - public void stopInteractiveMode(List> handles) { - tweakClient.shutdown(); - ta.stopInteractiveMode(); - - // remove space from the code (before and after) - removeSpacesFromCode(); - - // check which tabs were modified - boolean modified = false; - boolean[] modifiedTabs = getModifiedTabs(handles); - for (boolean mod : modifiedTabs) { - if (mod) { - modified = true; - break; - } - } - - if (modified) { - // ask to keep the values - int ret = Base.showYesNoQuestion(this, "Tweak Mode", - "Keep the changes?", - "You changed some values in your sketch. Would you like to keep the changes?"); - if (ret == 1) { - // NO! don't keep changes - loadSavedCode(); - // update the painter to draw the saved (old) code - ta.invalidate(); - } - else { - // YES! keep changes - // the new values are already present, just make sure the user can save the modified tabs - for (int i=0; i> handles, List> colorBoxes) { - // set OSC port of handles -// for (int i=0; i handles[]) { - private boolean[] getModifiedTabs(List> handles) { - boolean[] modifiedTabs = new boolean[handles.size()]; - - for (int i = 0; i < handles.size(); i++) { - for (Handle h : handles.get(i)) { - if (h.valueChanged()) { - modifiedTabs[i] = true; - } - } - } - return modifiedTabs; - } - - - public void initBaseCode() { - SketchCode[] code = sketch.getCode(); - - String space = new String(); - - for (int i=0; i> handles, boolean withSpaces) - { - SketchCode[] sketchCode = sketch.getCode(); - for (int tab=0; tab handles[]) - public boolean automateSketch(Sketch sketch, List> handles) { - SketchCode[] code = sketch.getCode(); - - if (code.length<1) - return false; - - if (handles.size() == 0) - return false; - - int setupStartPos = SketchParser.getSetupStart(baseCode[0]); - if (setupStartPos < 0) { - return false; - } - - // get port number from preferences.txt - int port; - String portStr = Preferences.get(prefTweakPort); - if (portStr == null) { - Preferences.set(prefTweakPort, "auto"); - portStr = "auto"; - } - - if (portStr.equals("auto")) { - // random port for udp (0xc000 - 0xffff) - port = (int)(Math.random()*0x3fff) + 0xc000; - } - else { - port = Preferences.getInteger(prefTweakPort); - } - - /* create the client that will send the new values to the sketch */ - tweakClient = new UDPTweakClient(port); - // update handles with a reference to the client object - for (int tab=0; tab 0) { - header += "int[] tweakmode_int = new int["+numOfInts+"];\n"; - } - if (numOfFloats > 0) { - header += "float[] tweakmode_float = new float["+numOfFloats+"];\n\n"; - } - - /* add the server code that will receive the value change messages */ - header += UDPTweakClient.getServerCode(port, numOfInts>0, numOfFloats>0); - header += "TweakModeServer tweakmode_Server;\n"; - - - header += "void tweakmode_initAllVars() {\n"; - //for (int i=0; i list : handles) { - //for (Handle n : handles[i]) { - for (Handle n : list) { - header += " " + n.name + " = " + n.strValue + ";\n"; - } - } - header += "}\n\n"; - header += "void tweakmode_initCommunication() {\n"; - header += " tweakmode_Server = new TweakModeServer();\n"; - header += " tweakmode_Server.setup();\n"; - header += " tweakmode_Server.start();\n"; - header += "}\n"; - - header += "\n\n\n\n\n"; - - // add call to our initAllVars and initOSC functions from the setup() function. - String addToSetup = "\n"+ - " tweakmode_initAllVars();\n"+ - " tweakmode_initCommunication();\n\n"; - - setupStartPos = SketchParser.getSetupStart(c); - c = replaceString(c, setupStartPos, setupStartPos, addToSetup); - - code[0].setProgram(header + c); - - /* print out modified code */ - String showModCode = Preferences.get(prefTweakShowCode); - if (showModCode == null) { - Preferences.setBoolean(prefTweakShowCode, false); - } - - if (Preferences.getBoolean(prefTweakShowCode)) { - System.out.println("\nTweakMode modified code:\n"); - for (int i=0; i handles[]) - private int howManyInts(List> handles) { - int count = 0; - //for (int i=0; i list : handles) { - //for (Handle n : handles[i]) { - for (Handle n : list) { - if (n.type == "int" || n.type == "hex" || n.type == "webcolor") { - count++; - } - } - } - return count; - } - - //private int howManyFloats(ArrayList handles[]) - private int howManyFloats(List> handles) { - int count = 0; - //for (int i=0; i list : handles) { - //for (Handle n : handles[i]) { - for (Handle n : list) { - if (n.type == "float") { - count++; - } - } - } - return count; - } -} diff --git a/java/src/processing/mode/java/debug/LineBreakpoint.java b/java/src/processing/mode/java/debug/LineBreakpoint.java index 19031609e..def772494 100644 --- a/java/src/processing/mode/java/debug/LineBreakpoint.java +++ b/java/src/processing/mode/java/debug/LineBreakpoint.java @@ -25,6 +25,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import processing.app.Base; +import processing.mode.java.Debugger; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.Location; diff --git a/java/src/processing/mode/java/debug/LineHighlight.java b/java/src/processing/mode/java/debug/LineHighlight.java index f86aadd7d..905887257 100644 --- a/java/src/processing/mode/java/debug/LineHighlight.java +++ b/java/src/processing/mode/java/debug/LineHighlight.java @@ -24,6 +24,9 @@ import java.awt.Color; import java.util.HashSet; import java.util.Set; +import processing.mode.java.JavaEditor; + + /** * Model/Controller for a highlighted source code line. Implements a custom * background color and a text based marker placed in the left-hand gutter area. @@ -32,57 +35,63 @@ import java.util.Set; */ public class LineHighlight implements LineListener { - protected DebugEditor editor; // the view, used for highlighting lines by setting a background color - protected Color bgColor; // the background color for highlighting lines - protected LineID lineID; // the id of the line - protected String marker; // - protected Color markerColor; - protected int priority = 0; - protected static Set allHighlights = new HashSet(); + protected JavaEditor editor; // the view, used for highlighting lines by setting a background color + protected Color bgColor; // the background color for highlighting lines + protected LineID lineID; // the id of the line + protected String marker; // + protected Color markerColor; + protected int priority = 0; + protected static Set allHighlights = new HashSet(); - protected static boolean isHighestPriority(LineHighlight hl) { - for (LineHighlight check : allHighlights) { - if (check.lineID().equals(hl.lineID()) && check.priority() > hl.priority()) { - return false; - } - } - return true; + + /** + * Create a {@link LineHighlight}. + * + * @param lineID the line id to highlight + * @param bgColor the background color used for highlighting + * @param editor the {@link JavaEditor} + */ + public LineHighlight(LineID lineID, Color bgColor, JavaEditor editor) { + this.lineID = lineID; + this.bgColor = bgColor; + this.editor = editor; + lineID.addListener(this); + lineID.startTracking(editor.getTab(lineID.fileName()).getDocument()); // TODO: overwrite a previous doc? + paint(); // already checks if on current tab + allHighlights.add(this); + } + + + protected static boolean isHighestPriority(LineHighlight hl) { + for (LineHighlight check : allHighlights) { + if (check.getLineID().equals(hl.getLineID()) && + check.priority() > hl.priority()) { + return false; + } } + return true; + } - /** - * Create a {@link LineHighlight}. - * - * @param lineID the line id to highlight - * @param bgColor the background color used for highlighting - * @param editor the {@link DebugEditor} - */ - public LineHighlight(LineID lineID, Color bgColor, DebugEditor editor) { - this.lineID = lineID; - this.bgColor = bgColor; - this.editor = editor; - lineID.addListener(this); - lineID.startTracking(editor.getTab(lineID.fileName()).getDocument()); // TODO: overwrite a previous doc? - paint(); // already checks if on current tab - allHighlights.add(this); - } + + public void setPriority(int p) { + this.priority = p; + } - public void setPriority(int p) { - this.priority = p; - } - - public int priority() { - return priority; - } + + public int priority() { + return priority; + } + /** * Create a {@link LineHighlight} on the current tab. * * @param lineIdx the line index on the current tab to highlight * @param bgColor the background color used for highlighting - * @param editor the {@link DebugEditor} + * @param editor the {@link JavaEditor} */ - // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, Color bgColor, DebugEditor editor)} - public LineHighlight(int lineIdx, Color bgColor, DebugEditor editor) { + // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, Color bgColor, JavaEditor editor)} + public LineHighlight(int lineIdx, Color bgColor, JavaEditor editor) { this(editor.getLineIDInCurrentTab(lineIdx), bgColor, editor); } @@ -114,7 +123,7 @@ public class LineHighlight implements LineListener { * * @return the line id */ - public LineID lineID() { + public LineID getLineID() { return lineID; } diff --git a/java/src/processing/mode/java/debug/VariableInspector.java b/java/src/processing/mode/java/debug/VariableInspector.java index 85053429a..1558f9f0a 100644 --- a/java/src/processing/mode/java/debug/VariableInspector.java +++ b/java/src/processing/mode/java/debug/VariableInspector.java @@ -61,6 +61,8 @@ import org.netbeans.swing.outline.RowModel; import com.sun.jdi.Value; +import processing.mode.java.Debugger; +import processing.mode.java.JavaEditor; import processing.mode.java.JavaMode; @@ -79,7 +81,7 @@ public class VariableInspector extends JFrame { protected List locals; // current local variables protected List thisFields; // all fields of the current this-object protected List declaredThisFields; // declared i.e. non-inherited fields of this - protected DebugEditor editor; // the editor + protected JavaEditor editor; // the editor protected Debugger dbg; // the debugger protected List expandedNodes = new ArrayList(); // list of expanded tree paths. (using list to maintain the order of expansion) protected boolean p5mode = true; // processing / "advanced" mode flag (currently not used @@ -87,7 +89,7 @@ public class VariableInspector extends JFrame { /** * Creates new form VariableInspector */ - public VariableInspector(DebugEditor editor) { + public VariableInspector(JavaEditor editor) { this.editor = editor; this.dbg = editor.dbg(); diff --git a/java/src/processing/mode/java/pdex/ASTGenerator.java b/java/src/processing/mode/java/pdex/ASTGenerator.java index 8597d23b6..3eb9a93f5 100644 --- a/java/src/processing/mode/java/pdex/ASTGenerator.java +++ b/java/src/processing/mode/java/pdex/ASTGenerator.java @@ -111,8 +111,8 @@ import processing.app.Base; import processing.app.Library; import processing.app.SketchCode; import processing.app.Toolkit; +import processing.mode.java.JavaEditor; import processing.mode.java.JavaMode; -import processing.mode.java.debug.DebugEditor; import processing.mode.java.preproc.PdePreprocessor; import com.google.classpath.ClassPath; @@ -124,7 +124,7 @@ public class ASTGenerator { protected ErrorCheckerService errorCheckerService; - protected DebugEditor editor; + protected JavaEditor editor; public DefaultMutableTreeNode codeTree = new DefaultMutableTreeNode(); @@ -1751,7 +1751,7 @@ public class ASTGenerator { // Base.loge("null"); if (scrollOnly) { editor.statusMessage(simpName + " is not defined in this sketch", - DebugEditor.STATUS_ERR); + JavaEditor.STATUS_ERR); } } @@ -2036,7 +2036,7 @@ public class ASTGenerator { DefaultMutableTreeNode defCU = findAllOccurrences(); //TODO: Repetition here if(defCU == null){ editor.statusMessage("Can't locate definition of " + selText, - DebugEditor.STATUS_ERR); + JavaEditor.STATUS_ERR); return; } @@ -2132,13 +2132,13 @@ public class ASTGenerator { log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ editor.statusMessage("Highlight the class/function/variable name first" - , DebugEditor.STATUS_INFO); + , JavaEditor.STATUS_INFO); return; } if(errorCheckerService.hasSyntaxErrors()){ editor.statusMessage("Can't perform action until syntax errors are " + - "fixed :(", DebugEditor.STATUS_WARNING); + "fixed :(", JavaEditor.STATUS_WARNING); return; } DefaultMutableTreeNode defCU = findAllOccurrences(); @@ -2146,7 +2146,7 @@ public class ASTGenerator { : lastClickedWord; if(defCU == null){ editor.statusMessage("Can't locate definition of " + selText, - DebugEditor.STATUS_ERR); + JavaEditor.STATUS_ERR); return; } if(defCU.getChildCount() == 0) @@ -2476,14 +2476,14 @@ public class ASTGenerator { log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ editor.statusMessage("Highlight the class/function/variable name first", - DebugEditor.STATUS_INFO); + JavaEditor.STATUS_INFO); return; } if(errorCheckerService.hasSyntaxErrors()){ editor .statusMessage("Can't perform action until syntax errors are fixed :(", - DebugEditor.STATUS_WARNING); + JavaEditor.STATUS_WARNING); return; } @@ -2492,7 +2492,7 @@ public class ASTGenerator { : lastClickedWord; if(defCU == null){ editor.statusMessage(selText + " isn't defined in this sketch, so it can't" + - " be renamed", DebugEditor.STATUS_ERR); + " be renamed", JavaEditor.STATUS_ERR); return; } if (!frmRename.isVisible()){ diff --git a/java/src/processing/mode/java/pdex/CompletionPanel.java b/java/src/processing/mode/java/pdex/CompletionPanel.java index e712c730a..fc6599aa4 100644 --- a/java/src/processing/mode/java/pdex/CompletionPanel.java +++ b/java/src/processing/mode/java/pdex/CompletionPanel.java @@ -51,7 +51,7 @@ import javax.swing.text.BadLocationException; import processing.app.Base; import processing.app.syntax.JEditTextArea; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; /** @@ -87,7 +87,7 @@ public class CompletionPanel { */ private JScrollPane scrollPane; - protected DebugEditor editor; + protected JavaEditor editor; public static final int MOUSE_COMPLETION = 10, KEYBOARD_COMPLETION = 20; @@ -101,7 +101,7 @@ public class CompletionPanel { * @param dedit */ public CompletionPanel(final JEditTextArea textarea, int position, String subWord, - DefaultListModel items, final Point location, DebugEditor dedit) { + DefaultListModel items, final Point location, JavaEditor dedit) { this.textarea = (JavaTextArea) textarea; editor = dedit; this.insertionPosition = position; diff --git a/java/src/processing/mode/java/pdex/ErrorBar.java b/java/src/processing/mode/java/pdex/ErrorBar.java index bf536d994..a853846db 100644 --- a/java/src/processing/mode/java/pdex/ErrorBar.java +++ b/java/src/processing/mode/java/pdex/ErrorBar.java @@ -38,7 +38,7 @@ import javax.swing.text.BadLocationException; import processing.app.Base; import processing.app.SketchCode; import processing.mode.java.JavaMode; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; /** * The bar on the left of the text area which displays all errors as rectangles.
@@ -83,9 +83,9 @@ public class ErrorBar extends JPanel { public Color backgroundColor; // = new Color(0x2C343D); /** - * DebugEditor instance + * JavaEditor instance */ - protected DebugEditor editor; + protected JavaEditor editor; /** * ErrorCheckerService instance @@ -130,7 +130,7 @@ public class ErrorBar extends JPanel { } - public ErrorBar(DebugEditor editor, int height, JavaMode mode) { + public ErrorBar(JavaEditor editor, int height, JavaMode mode) { this.editor = editor; this.preferredHeight = height; this.errorCheckerService = editor.errorCheckerService; diff --git a/java/src/processing/mode/java/pdex/ErrorCheckerService.java b/java/src/processing/mode/java/pdex/ErrorCheckerService.java index cb2c82704..26632bb7d 100644 --- a/java/src/processing/mode/java/pdex/ErrorCheckerService.java +++ b/java/src/processing/mode/java/pdex/ErrorCheckerService.java @@ -55,7 +55,7 @@ import processing.app.SketchCode; import processing.app.syntax.SyntaxDocument; import processing.core.PApplet; import processing.mode.java.JavaMode; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; import processing.mode.java.preproc.PdePreprocessor; @@ -66,7 +66,7 @@ import processing.mode.java.preproc.PdePreprocessor; @SuppressWarnings("unchecked") public class ErrorCheckerService implements Runnable { - protected DebugEditor editor; + protected JavaEditor editor; /** Error check happens every sleepTime milliseconds */ public static final int sleepTime = 1000; @@ -217,7 +217,7 @@ public class ErrorCheckerService implements Runnable { protected ErrorMessageSimplifier errorMsgSimplifier; - public ErrorCheckerService(DebugEditor debugEditor) { + public ErrorCheckerService(JavaEditor debugEditor) { ensureMinP5Version(); this.editor = debugEditor; stopThread = new AtomicBoolean(false); @@ -274,7 +274,7 @@ public class ErrorCheckerService implements Runnable { } final ErrorCheckerService thisService = this; - final DebugEditor thisEditor = editor; + final JavaEditor thisEditor = editor; EventQueue.invokeLater(new Runnable() { public void run() { try { @@ -1101,10 +1101,10 @@ public class ErrorCheckerService implements Runnable { if (emarker.getProblem().getLineNumber() == editor.getTextArea().getCaretLine()) { if (emarker.getType() == ErrorMarker.Warning) { editor.statusMessage(emarker.getProblem().getMessage(), - DebugEditor.STATUS_INFO); + JavaEditor.STATUS_INFO); } else { editor.statusMessage(emarker.getProblem().getMessage(), - DebugEditor.STATUS_COMPILER_ERR); + JavaEditor.STATUS_COMPILER_ERR); } return; } @@ -1113,7 +1113,7 @@ public class ErrorCheckerService implements Runnable { } // This line isn't an error line anymore, so probably just clear it - if (editor.statusMessageType == DebugEditor.STATUS_COMPILER_ERR) { + if (editor.statusMessageType == JavaEditor.STATUS_COMPILER_ERR) { editor.statusEmpty(); return; } @@ -1748,7 +1748,7 @@ public class ErrorCheckerService implements Runnable { pauseThread.set(false); } - public DebugEditor getEditor() { + public JavaEditor getEditor() { return editor; } diff --git a/java/src/processing/mode/java/pdex/ErrorWindow.java b/java/src/processing/mode/java/pdex/ErrorWindow.java index bfbd5cfde..92c0ee539 100644 --- a/java/src/processing/mode/java/pdex/ErrorWindow.java +++ b/java/src/processing/mode/java/pdex/ErrorWindow.java @@ -37,7 +37,7 @@ import javax.swing.table.TableModel; import processing.app.Editor; import processing.app.Toolkit; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; /** * Error Window that displays a tablular list of errors. Clicking on an error @@ -58,7 +58,7 @@ public class ErrorWindow extends JFrame { */ protected JScrollPane scrollPane; - protected DebugEditor thisEditor; + protected JavaEditor thisEditor; private JFrame thisErrorWindow; /** @@ -75,7 +75,7 @@ public class ErrorWindow extends JFrame { * - Editor * @param ecs - ErrorCheckerService */ - public ErrorWindow(DebugEditor editor, ErrorCheckerService ecs) { + public ErrorWindow(JavaEditor editor, ErrorCheckerService ecs) { thisErrorWindow = this; errorCheckerService = ecs; thisEditor = editor; diff --git a/java/src/processing/mode/java/pdex/JavaTextArea.java b/java/src/processing/mode/java/pdex/JavaTextArea.java index cc03ae5fb..f1317e457 100644 --- a/java/src/processing/mode/java/pdex/JavaTextArea.java +++ b/java/src/processing/mode/java/pdex/JavaTextArea.java @@ -22,7 +22,7 @@ package processing.mode.java.pdex; import processing.mode.java.JavaInputHandler; import processing.mode.java.JavaMode; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; import processing.mode.java.tweak.ColorControlBox; import processing.mode.java.tweak.Handle; @@ -57,7 +57,7 @@ import processing.app.syntax.TextAreaDefaults; */ public class JavaTextArea extends JEditTextArea { protected PdeTextAreaDefaults defaults; - protected DebugEditor editor; + protected JavaEditor editor; protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler @@ -89,9 +89,9 @@ public class JavaTextArea extends JEditTextArea { } - //public JavaTextArea(TextAreaDefaults defaults, InputHandler inputHandler, DebugEditor editor) { - //public JavaTextArea(DebugEditor editor) { - public JavaTextArea(TextAreaDefaults defaults, DebugEditor editor) { + //public JavaTextArea(TextAreaDefaults defaults, InputHandler inputHandler, JavaEditor editor) { + //public JavaTextArea(JavaEditor editor) { + public JavaTextArea(TextAreaDefaults defaults, JavaEditor editor) { super(defaults, new JavaInputHandler(editor)); //super(defaults, inputHandler); this.editor = editor; diff --git a/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java b/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java index ed7619281..bd5d92f8d 100644 --- a/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java +++ b/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java @@ -21,7 +21,7 @@ along with this program; if not, write to the Free Software Foundation, Inc. package processing.mode.java.pdex; import processing.mode.java.JavaMode; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; import processing.mode.java.tweak.*; import java.awt.Color; @@ -845,7 +845,7 @@ public class JavaTextAreaPainter extends TextAreaPainter // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - private DebugEditor getEditor() { + private JavaEditor getEditor() { return ((JavaTextArea) textArea).editor; } diff --git a/java/src/processing/mode/java/pdex/SketchOutline.java b/java/src/processing/mode/java/pdex/SketchOutline.java index f4e9af8ee..3cf94d196 100644 --- a/java/src/processing/mode/java/pdex/SketchOutline.java +++ b/java/src/processing/mode/java/pdex/SketchOutline.java @@ -55,7 +55,7 @@ import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; public class SketchOutline { @@ -65,7 +65,7 @@ public class SketchOutline { protected DefaultMutableTreeNode soNode, tempNode; protected final JTree soTree; protected JTextField searchField; - protected DebugEditor editor; + protected JavaEditor editor; protected boolean internalSelection = false; diff --git a/java/src/processing/mode/java/pdex/TabOutline.java b/java/src/processing/mode/java/pdex/TabOutline.java index a34704e1c..b4e51738f 100644 --- a/java/src/processing/mode/java/pdex/TabOutline.java +++ b/java/src/processing/mode/java/pdex/TabOutline.java @@ -51,7 +51,8 @@ import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeSelectionModel; import processing.app.SketchCode; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; + public class TabOutline { protected JFrame frmOutlineView; @@ -66,7 +67,7 @@ public class TabOutline { protected JLabel lblCaption; - protected DebugEditor editor; + protected JavaEditor editor; protected ErrorCheckerService errorCheckerService; @@ -84,10 +85,8 @@ public class TabOutline { frmOutlineView.setUndecorated(true); Point tp = errorCheckerService.getEditor().ta.getLocationOnScreen(); lblCaption = new JLabel("Tabs List (type to filter)"); -// int minWidth = (int) (editor.getMinimumSize().width * 0.7f), maxWidth = (int) (editor -// .getMinimumSize().width * 0.9f); - int minWidth = estimateFrameWidth(), maxWidth = (int) (editor - .getMinimumSize().width * 0.9f); + int minWidth = estimateFrameWidth(); + int maxWidth = (int) (editor.getMinimumSize().width * 0.9f); frmOutlineView.setLayout(new BoxLayout(frmOutlineView.getContentPane(), BoxLayout.Y_AXIS)); JPanel panelTop = new JPanel(), panelMiddle = new JPanel(), panelBottom = new JPanel(); diff --git a/java/src/processing/mode/java/pdex/XQConsoleToggle.java b/java/src/processing/mode/java/pdex/XQConsoleToggle.java index 65496cfc8..d256d4c39 100644 --- a/java/src/processing/mode/java/pdex/XQConsoleToggle.java +++ b/java/src/processing/mode/java/pdex/XQConsoleToggle.java @@ -31,7 +31,7 @@ import java.awt.event.MouseListener; import javax.swing.JPanel; import processing.app.Language; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; /** * Toggle Button displayed in the editor line status panel for toggling bewtween @@ -51,10 +51,10 @@ public class XQConsoleToggle extends JPanel implements MouseListener { * Height of the component */ protected int height; - protected DebugEditor editor; + protected JavaEditor editor; protected String buttonName; - public XQConsoleToggle(DebugEditor editor, String buttonName, int height) { + public XQConsoleToggle(JavaEditor editor, String buttonName, int height) { this.editor = editor; this.height = height; this.buttonName = buttonName; diff --git a/java/src/processing/mode/java/pdex/XQErrorTable.java b/java/src/processing/mode/java/pdex/XQErrorTable.java index e4445ba21..dbfdb5ee9 100644 --- a/java/src/processing/mode/java/pdex/XQErrorTable.java +++ b/java/src/processing/mode/java/pdex/XQErrorTable.java @@ -33,7 +33,7 @@ import javax.swing.text.BadLocationException; import processing.app.Base; import processing.app.Language; -import processing.mode.java.debug.DebugEditor; +import processing.mode.java.JavaEditor; /** @@ -219,7 +219,7 @@ public class XQErrorTable extends JTable { frmImportSuggest.getContentPane().add(panel); frmImportSuggest.pack(); - final DebugEditor editor = errorCheckerService.getEditor(); + final JavaEditor editor = errorCheckerService.getEditor(); classList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (classList.getSelectedValue() != null) {