Package processing.mode.experimental

Source Code of processing.mode.experimental.DebugEditor

/*
* Copyright (C) 2012-14 Martin Leopold <m@martinleopold.com> and Manindra Moharana <me@mkmoharana.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package processing.mode.experimental;
import static processing.mode.experimental.ExperimentalMode.log;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
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.Timer;
import java.util.TimerTask;
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.Border;
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.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;

/**
* 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 <m@martinleopold.com>
* @author Manindra Moharana &lt;me@mkmoharana.com&gt;
*
*
*/
public class DebugEditor extends JavaEditor implements ActionListener {
    // important fields from superclass
    //protected Sketch sketch;
    //private JMenu fileMenu;
    //protected EditorToolbar toolbar;

    // highlighting
    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<LineHighlight> breakpointedLines = new ArrayList(); // breakpointed lines
    protected LineHighlight currentLine; // line the debugger is currently suspended at
    protected final String breakpointMarkerComment = " //<>//"; // breakpoint marker comment
    // menus
    protected JMenu debugMenu; // the debug menu
    // debugger control
    protected JMenuItem debugMenuItem;
    protected JMenuItem continueMenuItem;
    protected JMenuItem stopMenuItem;
    // breakpoints
    protected JMenuItem toggleBreakpointMenuItem;
    protected JMenuItem listBreakpointsMenuItem;
    // stepping
    protected JMenuItem stepOverMenuItem;
    protected JMenuItem stepIntoMenuItem;
    protected JMenuItem stepOutMenuItem;
    // info
    protected JMenuItem printStackTraceMenuItem;
    protected JMenuItem printLocalsMenuItem;
    protected JMenuItem printThisMenuItem;
    protected JMenuItem printSourceMenuItem;
    protected JMenuItem printThreads;
    // variable inspector
    protected JMenuItem toggleVariableInspectorMenuItem;
    // references
    protected ExperimentalMode dmode; // the mode
    protected Debugger dbg; // the debugger
    protected VariableInspector vi; // the variable inspector frame
    protected TextArea ta; // the text area

   
    protected ErrorBar errorBar;
    /**
     * Show Console button
     */
    protected XQConsoleToggle btnShowConsole;

    /**
     * Show Problems button
     */
    protected XQConsoleToggle btnShowErrors;

    /**
     * Scroll pane for Error Table
     */
    protected JScrollPane errorTableScrollPane;

    /**
     * Panel with card layout which contains the p5 console and Error Table
     * panes
     */
    protected JPanel consoleProblemsPane;
   
    protected XQErrorTable errorTable;
   
    /**
     * Enable/Disable compilation checking
     */
    protected boolean compilationCheckEnabled = true;
   
    /**
     * Show warnings menu item
     */
    protected JCheckBoxMenuItem showWarnings;
   
    /**
     * Check box menu item for show/hide Problem Window
     */
    public JCheckBoxMenuItem problemWindowMenuCB;
   
    /**
     * Enable/Disable debug ouput
     */
    protected JCheckBoxMenuItem debugMessagesEnabled;
   
    /**
     * Show outline view
     */
    protected JMenuItem showOutline;
   
    /**
     * Enable/Disable error logging
     */
    protected JCheckBoxMenuItem writeErrorLog;
   
    /**
     * Enable/Disable code completion
     */
    protected JCheckBoxMenuItem completionsEnabled;
   
    protected AutoSaveUtil autosaver;
   
    public DebugEditor(Base base, String path, EditorState state, Mode mode) {
        super(base, path, state, mode);

        // get mode
        dmode = (ExperimentalMode) mode;

        // init controller class
        dbg = new Debugger(this);

        // variable inspector window
        vi = new VariableInspector(this);

        // access to customized (i.e. subclassed) text area
        ta = (TextArea) 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);
//            }
//        });

        // load settings from theme.txt
        ExperimentalMode theme = dmode;
        breakpointColor = theme.getThemeColor("breakpoint.bgcolor", breakpointColor);
        breakpointMarkerColor = theme.getThemeColor("breakpoint.marker.color", breakpointMarkerColor);
        currentLineColor = theme.getThemeColor("currentline.bgcolor", currentLineColor);
        currentLineMarkerColor = theme.getThemeColor("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(ExperimentalMode.errorLogsEnabled) writeErrorsToFile();
//      if(autosaver != null && !viewingAutosaveBackup) {
//        log("stopping autosaver in internalCloseRunner");
//        autosaver.stop();
//      }
      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");
        StringBuffer sbuff = new StringBuffer();
      sbuff.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");
      sbuff.append("ERROR TYPE, ERROR ARGS, ERROR MSG\n");
        for (String errMsg : errorCheckerService.tempErrorLog.keySet()) {
          IProblem ip = errorCheckerService.tempErrorLog.get(errMsg);
          if(ip != null){
            sbuff.append(errorCheckerService.errorMsgSimplifier.getIDName(ip.getID()));
            sbuff.append(',');
            sbuff.append("{");
            for (int i = 0; i < ip.getArguments().length; i++) {
              sbuff.append(ip.getArguments()[i]);
              if(i < ip.getArguments().length - 1)
                sbuff.append("| ");
            }
            sbuff.append("}");
            sbuff.append(',');
            sbuff.append(ip.getMessage().replace(',', '^'));
            sbuff.append("\n");
          }
        }
        System.out.println(sbuff);
        File opFile = new File(getSketch().getFolder(), "ErrorLogs"
          + File.separator + "ErrorLog_" + System.currentTimeMillis() + ".csv");
        PApplet.saveStream(opFile, new ByteArrayInputStream(sbuff.toString()
          .getBytes(Charset.defaultCharset())));
      } catch (Exception e) {
        System.err.println("Failed to save log file for sketch " + getSketch().getName());
        e.printStackTrace();
      }
    }

    /**
     * Overrides sketch menu creation to change keyboard shortcuts from "Run".
     *
     * @return the sketch menu
     */
    /*@Override
    public JMenu buildSketchMenu() {
        JMenuItem runItem = Toolkit.newJMenuItemShift(DebugToolbar.getTitle(DebugToolbar.RUN, false), KeyEvent.VK_R);
        runItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                handleRun();
            }
        });

        JMenuItem presentItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.RUN, true));
        presentItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                handlePresent();
            }
        });

        JMenuItem stopItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.STOP, false));
        stopItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                handleStop();
            }
        });
        return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem});
    }*/
   
    /**
     * Whether debug toolbar is enabled
     */
    AtomicBoolean debugToolbarEnabled;
   
    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);
        log("Switching to Java Mode Toolbar");
      }
      else{
        // switch to debug
        if(debugToolbar == null)
          debugToolbar = new DebugToolbar(this, getBase());
        nextToolbar = debugToolbar;
        debugToolbarEnabled.set(true);
        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("Debug");
        debugMenu = new JMenu("PDE X");

        JCheckBoxMenuItem toggleDebugger = new JCheckBoxMenuItem("Show Debug Toolbar");
        toggleDebugger.setSelected(false);
        toggleDebugger.addActionListener(new ActionListener() {         
          public void actionPerformed(ActionEvent e) {
            switchToolbars();
          }
        });
        debugMenu.add(toggleDebugger);
        debugMenuItem = Toolkit.newJMenuItemAlt("Debug", KeyEvent.VK_R);
        debugMenuItem.addActionListener(this);
        continueMenuItem = Toolkit.newJMenuItem("Continue", KeyEvent.VK_U);
        continueMenuItem.addActionListener(this);
        stopMenuItem = new JMenuItem("Stop");
        stopMenuItem.addActionListener(this);

        toggleBreakpointMenuItem = Toolkit.newJMenuItem("Toggle Breakpoint", KeyEvent.VK_B);
        toggleBreakpointMenuItem.addActionListener(this);
        listBreakpointsMenuItem = new JMenuItem("List Breakpoints");
        listBreakpointsMenuItem.addActionListener(this);

        stepOverMenuItem = Toolkit.newJMenuItem("Step", KeyEvent.VK_H);
        stepOverMenuItem.addActionListener(this);
        stepIntoMenuItem = Toolkit.newJMenuItemShift("Step Into", KeyEvent.VK_H);
        stepIntoMenuItem.addActionListener(this);
        stepOutMenuItem = Toolkit.newJMenuItemAlt("Step Out", KeyEvent.VK_H);
        stepOutMenuItem.addActionListener(this);

        printStackTraceMenuItem = new JMenuItem("Print Stack Trace");
        printStackTraceMenuItem.addActionListener(this);
        printLocalsMenuItem = new JMenuItem("Print Locals");
        printLocalsMenuItem.addActionListener(this);
        printThisMenuItem = new JMenuItem("Print Fields");
        printThisMenuItem.addActionListener(this);
        printSourceMenuItem = new JMenuItem("Print Source Location");
        printSourceMenuItem.addActionListener(this);
        printThreads = new JMenuItem("Print Threads");
        printThreads.addActionListener(this);

        toggleVariableInspectorMenuItem = Toolkit.newJMenuItem("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);    
       
        showOutline = Toolkit.newJMenuItem("Show Outline", KeyEvent.VK_L);
        showOutline.addActionListener(this);
        debugMenu.add(showOutline);
       
        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);

        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(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)){
            log("Show Outline :D");
            errorCheckerService.getASTGenerator().showSketchOutline();
        }
    }

//    @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<LineID> stripBreakpointComments() {
        List<LineID> 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);
        List<LineBreakpoint> 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<String> 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<LineBreakpoint> 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;
   
    /**
     * Loads and starts the auto save service
     * Also handles the case where an auto save backup is found.
     * The user is asked to save the sketch to a new location
     */
    private void loadAutoSaver(){
      log("Load Auto Saver()");
      autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval);     
      if(!autosaver.checkForPastSave()) {
        autosaver.init();
        return;
      }
      File pastSave = autosaver.getPastSave();
      int response = Base
        .showYesNoQuestion(this,
                           "Unsaved backup found!",
                           "An automatic backup of \""
                               + pastSave.getParentFile().getName()
                               + "\" sketch has been found. This may mean Processing " +
                               "was closed unexpectedly last time.",
                           "Select YES to view it or NO to delete the backup.");
      if(response == JOptionPane.YES_OPTION){
        handleOpenInternal(pastSave.getAbsolutePath());       
        // Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to.");
        //log(getSketch().getMainFilePath());
        log("loadAutoSaver, viewing autosave? " + viewingAutosaveBackup);
        return;
      }
      else{
        autosaver.init();
      }
    }

    /**
     * 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 ExperimentalMode mode() {
        return dmode;
    }

    /**
     * Access the custom text area object.
     *
     * @return the text area object
     */
    public TextArea 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 (!ExperimentalMode.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 (ExperimentalMode.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(
                            "<html><body>&nbsp;There are unsaved"
                                    + " changes in your sketch.<br />"
                                    + "&nbsp;&nbsp;&nbsp; Do you want to save it before"
                                    + " running? </body></html>");
                    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()) {
                                ExperimentalMode.autoSavePromptEnabled = !dontRedisplay
                                        .isSelected();
                                ExperimentalMode.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()) {
                                ExperimentalMode.autoSavePromptEnabled = !dontRedisplay
                                        .isSelected();
                                ExperimentalMode.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 (ExperimentalMode.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);
    }

    /**
     * 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<Void, Void>() {
        @Override
        protected Void 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();
    }
   
    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<Problem> 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(errorCheckerService.hasErrors(),
                               errorBar.errorColor);
    }
   
    /**
     * Handle refactor operation
     */
    private void handleRefactor() {
      log("Caret at:");
      log(ta.getLineText(ta.getCaretLine()));
      errorCheckerService.getASTGenerator().handleRefactor();
    }
   
    /**
     * Handle show usage operation
     */
    private void handleShowUsage() {
      log("Caret at:");
      log(ta.getLineText(ta.getCaretLine()));
      errorCheckerService.getASTGenerator().handleShowUsage();
    }
   
    /**
     * Checks if the sketch contains java tabs. If it does, XQMode ain't built
     * for it, yet. Also, user should really start looking at Eclipse. Disable
     * compilation check.
     */
    private void checkForJavaTabs() {
      for (int i = 0; i < this.getSketch().getCodeCount(); i++) {
        if (this.getSketch().getCode(i).getExtension().equals("java")) {
          compilationCheckEnabled = false;
          JOptionPane.showMessageDialog(new Frame(), this
              .getSketch().getName()
              + " contains .java tabs. Live compilation error checking isn't "
              + "supported for java tabs. Only "
              + "syntax errors will be reported for .pde tabs.");
          break;
        }
      }
    }
}
TOP

Related Classes of processing.mode.experimental.DebugEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.