All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lambda.Debugger.Debugger Maven / Gradle / Ivy

The newest version!
/*                        Debugger.java

 Copyright 2003, Bil Lewis

 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 com.lambda.Debugger;

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionListener;

public class Debugger extends JFrame {
    private static int FONT_SIZE = 10;
    private static String FONT = "Courier";
    static String version = "28.Mar.07";
    static boolean firstRun = false;
    static Debugger mainFrame;
    static long endTime, startTime, totalTime;
    private static boolean firstTimeTracePane = true;
    protected static long timeDebugifying = 0;
    // Used by statistics & class loader

    static boolean GC_OFF = false;
    static boolean SHOW = true; // Used by StopButton.java
    static boolean NO_WINDOWS = false; // Used by StopButton.java
    static boolean INSTRUMENT = true; // Used by StopButton.java
    static boolean BUG = false;
    static boolean VGA = false;
    static boolean SCREEN_SHOT = false;
    static boolean DEBUGIFY_ONLY = false;
    static boolean PAUSED = false;
    // static boolean OUTPUT_ONLY = false; // Used by StopButton.java
    static boolean START = true;
    static boolean NATIVE_TOSTRING = false;
    static boolean TRACE_LOADER = false;
    static boolean TRACE_LOADER_STACK = false;//***************************
    static boolean TEST = false;
    static boolean DEMO = false; // Set by Launcher
    static boolean CMD_LINE = true; // Started from the command line?
    static boolean PAUSE_ON_STOP = false;
    static boolean KILL_TARGET_ON_STOP = true;
    static boolean DEBUG = false;
    static boolean DEBUG_DEBUGGER = false; // Set to false for users.
    static boolean NO_DEFAULTS = false;
    static boolean USE_BOOTCLASSLOADER = (InstrumentorForCL.class
            .getClassLoader() == null);
    static long MAX_MEMORY = 80000000;
    static Object[] argList = { new String[0] };
    static Class clazz = null;
    static String programName = "";
    static String DIRECTORY = "./";
    public static ClassLoader classLoader;
    public static String ODBName = "ODDB";
    static {
        if ("com.lambda".startsWith("com"))
            ODBName = "ODB";
    }
    static PrintStream StdOut = System.out;

    static private void readCommandLineFlags() {

        // These are used regularly and defined in the defaults file
        // String cd = System.getProperty("CUTOFF_DEPTH"); if (cd != null)
        // D.CUTOFF_DEPTH = Integer.parseInt(cd);
        {
            String s = System.getProperty("MEMORY");
            if (s != null) {
                MAX_MEMORY = Long.parseLong(s);
                if (MAX_MEMORY > ((long)Integer.MAX_VALUE))
                    MAX_MEMORY = (long)Integer.MAX_VALUE;
                TimeStamp.setMax((int) (MAX_MEMORY / 200L));
            }
        }  {
            String s = System.getProperty("FONT");
            if (s != null) {
                FONT = s;
            }
        }  {
            String s = System.getProperty("FONT_SIZE");
            if (s != null) {
                FONT_SIZE = Integer.parseInt(s);
            }
        }
        if (System.getProperty("GC_OFF") != null)
            GC_OFF = true;
        if (System.getProperty("DONT_SHOW") != null)
            SHOW = false;
        if (System.getProperty("NO_WINDOWS") != null) {
            SHOW = false;
            NO_WINDOWS = true;
        }
        if (System.getProperty("DONT_INSTRUMENT") != null)
            INSTRUMENT = false;
        if (System.getProperty("PAUSED") != null) {
            D.DISABLE = true;
            PAUSED = true;
        }
        // if (System.getProperty("OUTPUT_ONLY") != null) {OUTPUT_ONLY = true;
        // PAUSED=true;}
        if (System.getProperty("DONT_START") != null)
            START = false;
        if (System.getProperty("DONT_KILL_TARGET") != null)
            KILL_TARGET_ON_STOP = false;

        // These are rarely used by regular users
        if (System.getProperty("NO_DEFAULTS") != null)
            NO_DEFAULTS = true;
        if (System.getProperty("NATIVE_TOSTRING") != null)
            NATIVE_TOSTRING = true;
        if (System.getProperty("DEBUGIFY_ONLY") != null)
            DEBUGIFY_ONLY = true;

        // These are never used by regular users
        if (System.getProperty("BUG") != null)
            BUG = true;
        if (System.getProperty("VGA") != null)
            VGA = true;
        if (System.getProperty("SCREEN_SHOT") != null)
            SCREEN_SHOT = true;
        if (System.getProperty("TRACE_LOADER") != null)
            TRACE_LOADER = true;
        if (System.getProperty("TRACE_LOADER_STACK") != null)
            TRACE_LOADER = TRACE_LOADER_STACK = true;
        if (System.getProperty("TEST") != null)
            TEST = true;
        if (System.getProperty("DEBUG_DEBUGGER") != null)
            DEBUG_DEBUGGER = D.DEBUG_DEBUGGER = true;
        if (System.getProperty("DONT_PAUSE_ON_STOP") != null)
            PAUSE_ON_STOP = false;

        // if (D.CUTOFF_DEPTH > 0 && D.CUTOFF_DEPTH != D.DONT_START)
        // Debugger.println("Only calls less than "+D.CUTOFF_DEPTH+" deep will
        // be recorded (and no assignments).");
        if (PAUSED)
            Debugger
                    .println("Recording will not start until 'Start Recording' is pushed");
        if (!INSTRUMENT)
            Debugger.println("Classes will not be instrumented");
        if (!SHOW & !PAUSED)
            Debugger.println("Recording will continue until 'Stop' is pushed");

    }

    public static void println(String s) {
        if (!NO_WINDOWS)
            StdOut.println(ODBName + ": " + s);
    }

    private void initialize() {
        ClassLoader cl = getClass().getClassLoader();
        upImage = new ImageIcon(cl.getResource("images/up16.gif"));
        downImage = new ImageIcon(cl.getResource("images/down16.gif"));
        firstImage = new ImageIcon(cl.getResource("images/first16.gif"));
        backImage = new ImageIcon(cl.getResource("images/back16.gif"));
        forwardImage = new ImageIcon(cl.getResource("images/forward16.gif"));
        lastImage = new ImageIcon(cl.getResource("images/last16.gif"));
        loopImage = new ImageIcon(cl.getResource("images/loop16.gif"));
        backLoopImage = new ImageIcon(cl.getResource("images/BackLoop16.gif"));
        prevLineImage = new ImageIcon(cl.getResource("images/PrevLine16.gif"));
        nextLineImage = new ImageIcon(cl.getResource("images/NextLine16.gif"));

        setTitle("Omniscient Debugger " + version + " - " + programName);

        topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout());
        // topPanel.setSize(500, 800);
        getContentPane().add(topPanel);
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        createFileMenu(menuBar);
        createRunMenu(menuBar);
        if (!SCREEN_SHOT)
            createCodeMenu(menuBar);
        createTraceMenu(menuBar);
        createFilterMenu(menuBar);
        if (!SCREEN_SHOT)
            createObjectsMenu(menuBar);
        if (!SCREEN_SHOT)
            createDebugMenu(menuBar);
        if (!SCREEN_SHOT)
            createHelpMenu(menuBar);

        JButton b3, b4, b5, b6, b7;

        menuBar.add(b3 = new JButton("Previous"));
        b3.setToolTipText("Revert to the previously selected time");
        menuBar.add(b4 = new JButton(firstImage));
        b4.setToolTipText("First timestamp (any thread)");
        menuBar.add(b5 = new JButton(backImage));
        b5.setToolTipText("Previous timestamp (any thread)");
        menuBar.add(b6 = new JButton(forwardImage));
        b6.setToolTipText("Next timestamp (any thread)");
        menuBar.add(b7 = new JButton(lastImage));
        b7.setToolTipText("Last timestamp (any thread)");
        ActionListener listener = new DebuggerActionListener(b3, b4, b5, b6, b7);
        b3.addActionListener(listener);
        b4.addActionListener(listener);
        b5.addActionListener(listener);
        b6.addActionListener(listener);
        b7.addActionListener(listener);

        menuBar.add(TSLabel = new JLabel("Time Stamp: "));

        // Create spliter panes for rows
        JSplitPane westPane1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        JSplitPane westPane2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        JSplitPane westPane3 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        // JSplitPane eastPane1 = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
        // JSplitPane eastPane2 = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
        // JSplitPane eastPane3 = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
        JSplitPane centerPane1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        JSplitPane centerPane2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        ;
        // eastPane1.setTopComponent(eastPane2);
        // eastPane1.setBottomComponent(eastPane3);
        centerPane1.setBottomComponent(centerPane2);

        // Create a splitter pane for the three columns
        JSplitPane splitPaneH = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        JSplitPane splitPaneH1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        topPanel.add(splitPaneH, BorderLayout.CENTER);

        // miniBuffer at bottom
        JScrollPane sp = createTA("");
        miniBuffer = (JTextArea) sp.getViewport().getComponent(0);
        MiniBuffer.initialize(miniBuffer);
        // sp.setBackground( Color.lightGray );
        topPanel.add(sp, BorderLayout.SOUTH);
        splitPaneH1.setLeftComponent(westPane1);
        splitPaneH1.setRightComponent(centerPane1);
        splitPaneH.setLeftComponent(splitPaneH1);
        // splitPaneH.setRightComponent(eastPane1 );

        // // centerPane1.setMinimumSize(new Dimension(500, 500));
        // // splitPaneH1.setMinimumSize(new Dimension(750, 700));

        // createTimeSlider();
        // topPanel.add( timeSlider, BorderLayout.NORTH );

        // Set up west (left) column
        JPanel threadsPanel = createThreadsPanel();
        JPanel stackPanel = createStackPanel();
        JPanel localsPanel = createLocalsPanel();
        JPanel thisPanel = createThisPanel();

        westPane1.setTopComponent(threadsPanel);
        westPane1.setBottomComponent(westPane2);
        westPane2.setTopComponent(stackPanel);
        westPane2.setBottomComponent(westPane3);
        westPane3.setTopComponent(localsPanel);
        westPane3.setBottomComponent(thisPanel);

        // Set up middle column
        JPanel codePanel = createCodePanel();
        centerPane2.setTopComponent(codePanel);
        JPanel tracePanel = createTracePanel();
        centerPane1.setTopComponent(tracePanel);
        JPanel TTYPanel = createTTYPanel();
        centerPane2.setBottomComponent(TTYPanel);

        // Set up east (right) column
        JPanel variablePanel = createObjectPanel();
        splitPaneH.setRightComponent(variablePanel);
        // eastPane1.setTopComponent( variablePanel );
        // JPanel locksPanel = createLocksPanel();
        // eastPane1.setBottomComponent( locksPanel );
        // JPanel excPanel = createExcPanel();
        // eastPane3.setTopComponent( excPanel);
        // JPanel IOPanel = createIOPanel();
        // eastPane3.setBottomComponent( IOPanel);
    }

    static TimeStamp previousTime = null;

    public static void revertPrevious() {
        if (previousTime == null)
            return;
        revert(previousTime);
    }

    public static void revert() {
        revert(TimeStamp.currentTime());
    }

    public static void revert(int time) {
        revert(TimeStamp.lookup(time));
    }

    public static void revert(TimeStamp ts) {
        revert(ts, true);
    }

    public static void revert(TimeStamp ts, boolean updateMessage) {
        if (TimeStamp.empty()) {
            message("No Time Stamps Collected?!", true);
            return;
        }
        if (ts.time < 0) {
            Debugger
                    .message(
                            "Inconsistant/Non-Existant TimeStamps. (An unusual Start/Stop?)",
                            true);
            return; // Blink/beep?
        }
        if (TimeStamp.empty())
            return;
        if (reverting)
            return; // A recursive call from an updateUI?
        reverting = true;
        SourceLine sl = ts.getSourceLine();
        if (sl == SourceLine.SPECIAL_HIDDEN_FILE_LINE) {
            TimeStamp ts1 = ts.getNextThisThread();
            if (ts1 != null)
                ts = ts1;
        }
        previousTime = TimeStamp.currentTime();
        TraceLine tl = ts.getPreviousBalancedTrace();
        if (tl == null)
            tl = TraceLine.defaultTraceLine();
        long clock = Clock.findTime(ts.time)
                - Clock.findTime(previousTime.time);
        if (updateMessage)
            Debugger.message("From last: " + (ts.time - previousTime.time)
                    + " stamps, " + Clock.formatTime(clock) + "secs      "
                    + ts.messageString(), false);
        TimeStamp.setCurrentTime(ts);
        updateTracePane(ts);
        updateStackPanel(tl);
        updateLocalsPanel(tl);
        updateObjectsPane();
        updateCodePanel();
        updateThreadPanel(ts);
        updateTTYPanel(ts);
        updateThisPanel(tl.thisObj);
        updateTSLabel(ts);
        // if (timeSlider.getValue() != ts.time) {timeSlider.setValue(ts.time);
        // timeSlider.updateUI();}
        reverting = false;
    }

    public static void updateTSLabel(TimeStamp ts) {
        TSLabel.setText(getString(ts.time) + Clock.getString(ts.time)
                + SourceLine.getString(ts));
    }

    public static String getString(int time) { // time stamp time!
        String s = " Event " + formatTime(time) + " [" + TimeStamp.eott() + "]";
        return s;
    }

    private static String formatTime(int time) {
        int nChars = ("" + TimeStamp.eott()).length();
        String s = "" + time;
        while (s.length() < nChars)
            s = " " + s;
        return s;
    }

    public static void updateObjectsPane() {
        ObjectPane.update();
    }

    public static void updateTTYPanel(TimeStamp ts) {
        if (TTYPane.singleton().getSize() == 0)
            return;
        TTYPList.updateUI();
        int index = TTYPane.getClosest(ts);
        TTYPList.setSelectedIndex(index);
        if (index < 2)
            TTYPList.ensureIndexIsVisible(0);
        else
            TTYPList.ensureIndexIsVisible(index - 2);
        if (index + 2 > TTYPane.singleton().getSize())
            TTYPList.ensureIndexIsVisible(TTYPane.singleton().getSize() - 1);
        else
            TTYPList.ensureIndexIsVisible(index + 2);
        TTYPList.ensureIndexIsVisible(index);
    }

    public static void updateThreadPanel(TimeStamp ts) {
        if (ThreadPane.singleton().getSize() == 0)
            return;

        ThreadPane tp = (ThreadPane) ThreadPList.getSelectedValue();

        if ((tp == null) || (tp.tid != ts.getThread())) { // Only null once?
            // Best default??
            int index = ThreadPane.find(ts.getThread());
            ThreadPList.setSelectedIndex(index);
            ThreadPList.ensureIndexIsVisible(index);
        }
        ThreadPList.updateUI();
    }

    public static void updateTracePane(TimeStamp ts) {
        MethodLine ml = ts.getNearestTraceThisThread();

        if (TimeStamp.getType(ts.time) == TimeStamp.LAST) {
            // RM should display the same as following RL.
            TraceLine tl = ts.getPreviousBalancedTrace();
            if ((tl != null) && (tl.returnLine != null)
                    && (tl.returnLine.filteredIndex != -1))
                ml = tl.returnLine;
        }

        // if ((ml instanceof ReturnLine) && (ml.filteredIndex == -1)) ml =
        // ((ReturnLine) ml).traceLine; NEVER HAPPEN
        if (ml == null) {
            ml = TraceLine.defaultTraceLine();
        } // Just don't crash.
        // D.println("TraceLineB: "+ml.toString(0));
        if (previousTime.getThread() != ts.getThread()) {
            // D.println("Changing from "+ TimeStamp.previousTime().getThread()
            // +" to "+ ts.getThread());
            TracePList.updateUI();
        }
        if (firstTimeTracePane) {
            firstTimeTracePane = false;
            TracePList.updateUI();
            // Where should I do this? When changing threads (above) and
            // initializing (somewhere)
        }

        if (TracePList.getSelectedIndex() != ml.filteredIndex) {
            TracePList.setSelectedIndex(ml.filteredIndex);
            TracePList.ensureIndexIsVisible(ml.filteredIndex - 2);
            TracePList.ensureIndexIsVisible(ml.filteredIndex + 2);
            TracePList.ensureIndexIsVisible(ml.filteredIndex);
        }
    }

    public JPanel createP(String s) {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        JLabel l = new JLabel(s);
        JPanel panel1 = new JPanel();
        // panel.add(l);
        panel1.add(l);
        panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS));
        panel.add(panel1);
        // panel.setBackground( Color.lightGray );
        panel.setBorder(BorderFactory.createLineBorder(Color.black));
        return panel;
    }

    public JPanel createP2(String s) {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        JPanel panel1 = new JPanel();
        panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS));
        JPanel panel2 = new JPanel();
        panel2.setLayout(new BoxLayout(panel2, BoxLayout.X_AXIS));
        JLabel l = new JLabel(s);
        panel1.add(l);
        panel1.add(panel2);
        panel.add(panel1);

        // panel.setBackground( Color.lightGray );
        panel.setBorder(BorderFactory.createLineBorder(Color.black));
        return panel;
    }

    public JPanel createP1(String s) {
        JLabel l = new JLabel(s);
        JPanel panel = new JPanel();
        panel.add(l);
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        // panel.setBackground( Color.lightGray );
        panel.setBorder(BorderFactory.createLineBorder(Color.black));
        return panel;
    }

    public JScrollPane createTA(String s) {
        JTextArea ta = new JTextArea(s);
        ta.setFont(new Font(FONT, Font.PLAIN, FONT_SIZE));
        ta.setBorder(BorderFactory.createLineBorder(Color.black));
        JScrollPane sp = new JScrollPane(ta);
        // sp.getViewport().add(ta);
        return sp;
    }

    // REMOVE THIS WHEN CODEPANE is ready
    public JScrollPane createJL(VectorD listData, ListSelectionListener sl) {
        return (createJL(listData, sl, false));
    }

    public JScrollPane createJL(VectorD listData, ListSelectionListener sl,
            boolean doubleClick) {
        JList list;
        if (doubleClick)
            list = new DoubleClickJList(listData);
        else
            list = new JList(listData);

        list.setFont(new Font(FONT, Font.PLAIN, FONT_SIZE));
        list.addListSelectionListener(sl);
        list.setBorder(BorderFactory.createLineBorder(Color.black));
        JScrollPane sp = new JScrollPane(list);
        // sp.getViewport().add(list);
        return sp;
    }

    public JScrollPane createJL(AbstractListModel listData,
            ListSelectionListener sl) {
        return (createJL(listData, sl, false));
    }

    public JScrollPane createJL(AbstractListModel listData,
            ListSelectionListener sl, boolean doubleClick) {
        JList list;
        if (doubleClick)
            list = new DoubleClickJList(listData);
        else
            list = new JList(listData);

        list.setFont(new Font(FONT, Font.PLAIN, FONT_SIZE));
        list.addListSelectionListener(sl);
        list.setBorder(BorderFactory.createLineBorder(Color.black));
        JScrollPane sp = new JScrollPane(list);
        // sp.getViewport().add(list);
        return sp;
    }

    // Create special panels

    public JPanel createThreadsPanel() {
        JButton b0, b1, b2, b3;
        JPanel panel = createP("Threads ");
        JPanel panel1 = (JPanel) panel.getComponent(0);

        JScrollPane sp = createJL(ThreadPane.singleton(), new ThreadListener(),
                true);
        ThreadPList = (JList) sp.getViewport().getComponent(0);

        // panel.add(new Label("Threads"));

        panel1.add(b0 = new JButton(firstImage));
        b0.setToolTipText("First timestamp this thread");
        panel1.add(b1 = new JButton(backImage));
        b1.setToolTipText("Previous context switch");
        panel1.add(b2 = new JButton(forwardImage));
        b2.setToolTipText("Next context switch");
        panel1.add(b3 = new JButton(lastImage));
        b3.setToolTipText("Last timestamp this thread");
        ActionListener listener = new ThreadActionListener(b0, b1, b2, b3);
        b0.addActionListener(listener);
        b1.addActionListener(listener);
        b2.addActionListener(listener);
        b3.addActionListener(listener);
        panel.add(sp);
        if (VGA) {
            panel.setMinimumSize(new Dimension(80, 0));
            // panel.setPreferredSize(new Dimension(150, 100));
            panel.setMaximumSize(new Dimension(200, 300));
        } else {
            panel.setMinimumSize(new Dimension(200, 150));
            // panel.setPreferredSize(new Dimension(250, 250));
            panel.setMaximumSize(new Dimension(400, 400));
        }

        // ThreadPane.initialize();
        return panel;
    }

    public JPanel createStackPanel() {
        JPanel panel = createP1("Stack");
        JScrollPane sp = createJL(new StackList(), new StackListener(), true);
        StackPList = (JList) sp.getViewport().getComponent(0);
        panel.add(sp);
        if (VGA) {
            panel.setMinimumSize(new Dimension(80, 0));
            // panel.setPreferredSize(new Dimension(150, 80));
            panel.setMaximumSize(new Dimension(400, 200));
        } else {
            panel.setMinimumSize(new Dimension(200, 100));
            // panel.setPreferredSize(new Dimension(250, 250));
            panel.setMaximumSize(new Dimension(400, 300));
        }
        return panel;
    }

    public JPanel createLocalsPanel() {
        JButton b0, b1, b2, b3, b4;
        JPanel panel = createP("Locals ");
        JPanel panel1 = (JPanel) panel.getComponent(0);
        panel1.add(b0 = new JButton(firstImage));
        b0.setToolTipText("First value this variable");
        panel1.add(b1 = new JButton(backImage));
        b1.setToolTipText("Previous value this variable");
        panel1.add(b2 = new JButton(forwardImage));
        b2.setToolTipText("Next value this variable");
        panel1.add(b3 = new JButton(lastImage));
        b3.setToolTipText("Last value this variable");
        b4 = new JButton("X"); // KILL THIS LATER

        ActionListener listener = new LocalsActionListener(b0, b1, b2, b3, b4);
        b0.addActionListener(listener);
        b1.addActionListener(listener);
        b2.addActionListener(listener);
        b3.addActionListener(listener);
        b4.addActionListener(listener);

        JScrollPane sp = createJL(LocalsPane.singleton(),
                new LocalsActionListener(), true);
        panel.add(sp);
        LocalsPList = (JList) sp.getViewport().getComponent(0);
        if (VGA) {
            panel.setMinimumSize(new Dimension(80, 0));
            // panel.setPreferredSize(new Dimension(150, 120));
            panel.setMaximumSize(new Dimension(400, 300));
        } else {
            panel.setMinimumSize(new Dimension(200, 100));
            // panel.setPreferredSize(new Dimension(250, 250));
            panel.setMaximumSize(new Dimension(400, 300));
        }
        return panel;
    }

    public JPanel createThisPanel() {

        JButton b0, b1, b2, b3, b4;
        JPanel panel = createP1("this");
        JScrollPane sp = createJL(ThisPane.singleton(),
                new ThisActionListener(), true);
        panel.add(sp);
        ThisPList = (JList) sp.getViewport().getComponent(0);
        if (VGA) {
            panel.setMinimumSize(new Dimension(80, 0));
            // panel.setPreferredSize(new Dimension(150, 80));
            panel.setMaximumSize(new Dimension(400, 200));
        } else {
            panel.setMinimumSize(new Dimension(200, 100));
            // panel.setPreferredSize(new Dimension(250, 250));
            panel.setMaximumSize(new Dimension(400, 200));
        }
        return panel;
    }

    public static void updateStackPanel(TraceLine tl) {
        StackList sl = tl.generateStackList();
        StackList.setCurrentStackList(sl);
        StackPList.setModel(sl);
        StackPList.updateUI();
    }

    public static void updateCodePanel() {
        updateCodePanel(TimeStamp.currentTime());
    }

    public static void updateCodePanel(TimeStamp ts) {
        SourceLine sl = ts.getSourceLine();
        if (sl == SourceLine.SPECIAL_HIDDEN_FILE_LINE) {
            // System.out.println("Hidden line at: "+ts);
            TimeStamp ts1 = ts.getNextThisThread();
            if (ts1 != null)
                sl = ts1.getSourceLine();
        }
        int line = sl.line;
        int end = 0, start = 0;
        String fileName = sl.getFile();
        VectorD codeList = CodePane.getDisplayList(sl);
        // if (codeList.size() == 0) return; // For files not found, don't move.
        if (codePanelCurrentFile != fileName) {
            codeJList.setListData(codeList);
            codePanelCurrentFile = fileName;
            codeJList.updateUI();
        }
        if (line < 1)
            return;
        codeJList.setSelectedIndex(line - 1);
        int min = Math.max(0, line - 6);
        int max = Math.min(codeList.size() - 1, line + 6);
        codeJList.ensureIndexIsVisible(max);
        codeJList.ensureIndexIsVisible(min);
        codeJList.ensureIndexIsVisible(line - 1);
    }

    private static Object previousThis;

    public static void updateTimeSlider() {
        if (TimeStamp.empty())
            timeSlider.setMaximum(0);
        else
            timeSlider.setMaximum(TimeStamp.eott());

        timeSlider.updateUI();
    }

    public static void updateThisPanel(Object o) {
        int selectedLine = -1;

        if (o == previousThis) {
            ThisPList.updateUI();
            return; // SOMETHING LIKE THIS. BUT MUST UPDATE THE VALUES OF IVs.?
        }

        previousThis = o;

        ThisPane.singleton().displayList = new VectorD(); // KINDA TACKY.
        if (o != null)
            ThisPane.add(o);
        ThisPList.setModel(ThisPane.singleton());
        ThisPList.updateUI();
        if (selectedLine > -1)
            ThisPList.setSelectedIndex(selectedLine);
    }

    static Locals previousLocals = null;

    public static void updateLocalsPanel(TraceLine tl) {
        int selectedLine = -1;

        Locals locals = tl.locals;
        if (locals == null) {
            locals = Locals.DEFAULT;
        } // null is fine. Easier to make empty Locals than patch in null.
        if (previousLocals == locals) {
            selectedLine = LocalsPList.getSelectedIndex();
        } else {
            /*
             * VectorD v = new VectorD(); LocalsPane.singleton().displayList =
             * v; // Change soon! int len = locals.locals.length; for (int i=0;
             * i < len; i++) v.add(locals.locals[i]);
             */
            LocalsPane.singleton().displayList = locals.createShadowLocals();
            previousLocals = locals;
            LocalsPList.setModel(LocalsPane.singleton());
        }
        LocalsPList.updateUI();
        if (selectedLine > -1)
            LocalsPList.setSelectedIndex(selectedLine);
        // LocalsPane.printAll();
    }

    public JPanel createObjectPanel() {
        JButton b0, b1, b2, b3, b4, b5, b6;
        JPanel panel = createP2("Objects ");
        JPanel panel2 = (JPanel) panel.getComponent(0);
        JPanel panel1 = (JPanel) panel2.getComponent(1);
        panel1.add(b0 = new JButton(firstImage));
        b0.setToolTipText("First value this variable");
        panel1.add(b1 = new JButton(backImage));
        b1.setToolTipText("Previous value this variable");
        panel1.add(b2 = new JButton(forwardImage));
        b2.setToolTipText("Next value this variable");
        panel1.add(b3 = new JButton(lastImage));
        b3.setToolTipText("Last value this variable");
        ActionListener listener = new ObjectActionListener(b0, b1, b2, b3);
        b0.addActionListener(listener);
        b1.addActionListener(listener);
        b2.addActionListener(listener);
        b3.addActionListener(listener);

        JScrollPane sp = createJL(new ObjectPane(), new ObjectListener(), true);
        panel.add(sp);
        ObjectsPList = (JList) sp.getViewport().getComponent(0);
        if (VGA) {
            panel.setMinimumSize(new Dimension(80, 150));
            // panel.setPreferredSize(new Dimension(160, 250));
        } else {
            panel.setMinimumSize(new Dimension(100, 250));
            // panel.setPreferredSize(new Dimension(250, 250));
        }
        return panel;
    }

    public JPanel createTracePanel() {
        JButton b3, b4, b5, b6, b7;
        JPanel panel = createP("Method Traces ");
        JPanel panel1 = (JPanel) panel.getComponent(0);

        panel1.add(b4 = new JButton(firstImage));
        b4.setToolTipText("First call of this method");
        panel1.add(b5 = new JButton(backImage));
        b5.setToolTipText("Previous call of this method");
        panel1.add(b6 = new JButton(forwardImage));
        b6.setToolTipText("Next call of this method");
        panel1.add(b7 = new JButton(lastImage));
        b7.setToolTipText("Last call of this method");
        ActionListener listener = new TraceActionListener(b4, b5, b6, b7);
        b4.addActionListener(listener);
        b5.addActionListener(listener);
        b6.addActionListener(listener);
        b7.addActionListener(listener);

        JScrollPane sp = createJL(TraceLine.SINGLETON, new TraceListener(),
                true);
        TracePList = (JList) sp.getViewport().getComponent(0);
        if (VGA) {
            panel.setMinimumSize(new Dimension(200, 100));
            panel.setPreferredSize(new Dimension(350, 300));
            panel.setMaximumSize(new Dimension(800, 600));
        } else {
            panel.setMinimumSize(new Dimension(450, 150));
            // panel.setPreferredSize(new Dimension(550, 400));
            panel.setMaximumSize(new Dimension(500, 600));
        }
        panel.add(sp);
        return panel;
    }

    public JPanel createCodePanel() {
        JButton b0, b1, b2, b3, b4, b5, b6, b7, b8, b9;
        JPanel panel = createP("Code ");
        JPanel panel1 = (JPanel) panel.getComponent(0);
        panel1.add(b0 = new JButton(firstImage));
        b0.setToolTipText("First timestamp this method");
        panel1.add(b1 = new JButton(prevLineImage));
        b1.setToolTipText("Previous line this method (step over)");
        panel1.add(b2 = new JButton(backImage));
        b2.setToolTipText("Previous line any method (step in/out)");
        panel1.add(b3 = new JButton(forwardImage));
        b3.setToolTipText("Next line any method (step in/out)");
        panel1.add(b4 = new JButton(nextLineImage));
        b4.setToolTipText("Next line this method (step over)");
        panel1.add(b5 = new JButton(lastImage));
        b5.setToolTipText("Last timestamp this method");
        panel1.add(b6 = new JButton(loopImage));
        b6.setToolTipText("Next timestamp on this line, in this method");
        panel1.add(b7 = new JButton(backLoopImage));
        b7.setToolTipText("Previous timestamp on this line, in this method");
        panel1.add(b8 = new JButton(upImage));
        b8.setToolTipText("Go back to caller of this method");
        panel1.add(b9 = new JButton(downImage));
        b9.setToolTipText("Return from this method");
        ActionListener listener = new CodeActionListener(b0, b1, b2, b3, b4,
                b5, b6, b7, b8, b9);
        b0.addActionListener(listener);
        b1.addActionListener(listener);
        b2.addActionListener(listener);
        b3.addActionListener(listener);
        b4.addActionListener(listener);
        b5.addActionListener(listener);
        b6.addActionListener(listener);
        b7.addActionListener(listener);
        b8.addActionListener(listener);
        b9.addActionListener(listener);

        JScrollPane sp = createJL(new VectorD(), new CodeListener(), true);
        codeJList = (JList) sp.getViewport().getComponent(0);
        if (VGA) {
            panel.setMinimumSize(new Dimension(200, 100));
            // panel.setPreferredSize(new Dimension(300, 200));
            panel.setMaximumSize(new Dimension(800, 600));
        } else {
            panel.setMinimumSize(new Dimension(400, 150));
            // panel.setPreferredSize(new Dimension(550, 400));
            panel.setMaximumSize(new Dimension(500, 600));
        }
        panel.add(sp);
        return panel;
    }

    public JPanel createTTYPanel() {
        JButton b0, b1, b2, b3;

        JPanel panel = createP("TTY Output ");

        JPanel panel1 = (JPanel) panel.getComponent(0);
        panel1.add(b0 = new JButton(firstImage));
        b0.setToolTipText("First timestamp this PrintStream");
        panel1.add(b1 = new JButton(backImage));
        b1.setToolTipText("Previous timestamp this PrintStream");
        panel1.add(b2 = new JButton(forwardImage));
        b2.setToolTipText("Next timestamp this PrintStream");
        panel1.add(b3 = new JButton(lastImage));
        b3.setToolTipText("Last timestamp this PrintStream");
        ActionListener listener = new TTYActionListener(b0, b1, b2, b3);
        b0.addActionListener(listener);
        b1.addActionListener(listener);
        b2.addActionListener(listener);
        b3.addActionListener(listener);

        JScrollPane sp = createJL(TTYPane.singleton(), new TTYListener());
        TTYPList = (JList) sp.getViewport().getComponent(0);
        panel.add(sp);
        if (VGA) {
            panel.setMinimumSize(new Dimension(200, 0));
            // panel.setPreferredSize(new Dimension(300, 100));
            panel.setMaximumSize(new Dimension(500, 400));
        } else {
            panel.setMinimumSize(new Dimension(400, 0));
            // panel.setPreferredSize(new Dimension(550, 200));
            panel.setMaximumSize(new Dimension(500, 400));
        }
        TTYPane.initialize();
        return panel;
    }

    public void makeTracePopup(JComponent panel) {
        JMenuItem copyThis = new JMenuItem("Copy 'this' to Object Pane");
        JMenuItem copyArg1 = new JMenuItem("Copy 'arg 1' to Object Pane");
        JMenuItem copyArg2 = new JMenuItem("Copy 'arg 2' to Object Pane");
        JMenuItem copyArg3 = new JMenuItem("Copy 'arg 3' to Object Pane");
        traceMenu = new JPopupMenu("Trace Menu");
        traceMenu.add(copyThis);
        traceMenu.add(copyArg1);
        traceMenu.add(copyArg2);
        traceMenu.add(copyArg3);
        panel.add(traceMenu);
        enableEvents(AWTEvent.MOUSE_EVENT_MASK);
        ActionListener listener = new TraceActionListener();
        copyThis.addActionListener(listener);
        copyArg1.addActionListener(listener);
        copyArg2.addActionListener(listener);
        copyArg3.addActionListener(listener);
    }

    // ****************************** Main program
    // ******************************
    public static void runLSD(String args[], boolean noWindows) {
        NO_WINDOWS = noWindows;
        SHOW = !noWindows;
        main(args);
    }

    public static void main(String args[]) {
        final String[] args2 = args;
        main2(args);
    }

    public static void main2(String args[]) {
        // Create an instance of the test application
        String[] args1 = new String[0];

        println(version);

        if (DEBUGIFY_ONLY) { // Must be cmd line: % debugify *class
            Debugify.main(args);
            System.exit(0);
        }
        CMD_LINE = (args.length > 0);
        if (START)
            START = CMD_LINE;
        readCommandLineFlags();
        firstRun = Defaults.readDefaults();
        readCommandLineFlags();
        TimeStamp.initialize();

        if (CMD_LINE) { // if on command line w/a class name to run.
            programName = args[0];
            args1 = new String[args.length - 1];
            int len = args.length - 1;
            for (int i = 0; i < len; i++)
                args1[i] = args[i + 1];
            if (INSTRUMENT && !USE_BOOTCLASSLOADER) {
                classLoader = new DebugifyingClassLoader();
                Thread.currentThread().setContextClassLoader(classLoader);
            } else
                classLoader = Thread.currentThread().getContextClassLoader();
            try {
                clazz = classLoader.loadClass(programName);
            } catch (ClassNotFoundException ex) {
                System.err.println("Class not found: " + programName);
                System.exit(1);
            }
            if (firstRun) {
                // Package p = clazz.getPackage(); MAY RETURN NULL?!
                String name = clazz.getName();
                int dot = name.lastIndexOf('.');
                String packageName = "";
                if (dot == -1) {
                } else {
                    packageName = name.substring(0, dot + 1);
                }
                // System.out.println(""+packageName);
                //Defaults.addIOP(packageName);
            }
            if (!NO_WINDOWS)
                StopButton.create(START, PAUSED, SHOW, INSTRUMENT);

            argList = new Object[1];
            argList[0] = args1;

            final Object[] argList2 = argList;
            final Class clazz2 = clazz;
            if (START) {
                // new Thread(new Runnable() {public void run() {runMain(clazz2,
                // argList2);}}, "Main").start();
                runMain(clazz2, argList2);
            }
        } else
            Launch.create();

    } // Otherwise only create it when the user pushes STOP (StopButton.java)

    private static void runMain(Class clazz, Object[] argList) {
        runTarget(clazz, argList);
        if (SHOW)
            stopTarget(); // create debugger when main thread returns
        if (TEST)
            SwingUtilities.invokeLater(new DebuggerCommand());
    }

    public static synchronized void createDebugger() {
        if (mainFrame != null)
            return;
        // Somebody already created it. (Early STOP button is one way)
        mainFrame = new Debugger();
        mainFrame.initialize();
        mainFrame.pack();
        mainFrame.setVisible(true);
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ThreadPane.initialize();
        previousTime = TimeStamp.bot1();
        TimeStamp.setCurrentTime(previousTime);
        revert(TimeStamp.bot1());
        updateUIs();
        if (firstRun)
            Defaults.writeDefaults();

    }

    static public Object runAlternate(Object obj, Method method, Object[] args) {
        Object returnValue = null;
        startTime = new Date().getTime();

        Shadow.updateAll();
        if (mainTimeLine)
            Debugger.switchTimeLines(true);
        else
            clearTimeLine();
        D.DISABLE = false; // Start collecting
        D.resumeProgram();

        Clock.start();
        try {
            returnValue = method.invoke(obj, args);
        } catch (InvocationTargetException e) {
            Throwable t = e.getTargetException();
            if (t instanceof DebuggerExit) {
                System.out.println("In target program: \n" + clazz + "."
                        + method.getName() + " System.exit() called\n");
                D.PAUSE_PROGRAM = true;
                SHOW = true;
                D.DISABLE = true;
                // The program should be dead, so always show.
            } else {
                System.out.println("In target program1: \n" + clazz + "."
                        + method.getName() + " threw " + t);
                TraceLine tl = TraceLine.getFirstTraceline();
                Throwable t1;
                if (t instanceof Exception)
                    t1 = t;
                else
                    t1 = new DebuggerException("" + t);
                if (tl != null)
                    D.catchEx(tl.getSourceLine().getIndex(), t1, tl);
                t.printStackTrace();
            }
        } catch (Exception e) {
            System.out.println("IMPOSSIBLE? In target program: \n" + clazz
                    + "." + method.getName() + " threw " + e);
            e.printStackTrace();
        }

        if (method.getReturnType() == null)
            returnValue = ShadowVoid.VOID;
        if (returnValue == null)
            returnValue = ShadowNull.NULL;

        if (TimeStamp.eott() < 2) {
            if (!PAUSED)
                Debugger
                        .println("collected no data on this run.  Is target debugified?");
            return returnValue;
        }

        endTime = new Date().getTime();
        totalTime = endTime - startTime;
        stopTarget(); // HACK! Should be like runTarget()
        return returnValue;
    }

    static void runTarget(Class c, Object[] a) {
        clazz = c;
        argList = a; // Globals. rename.
        startTime = new Date().getTime();
        Method method = null;

        // System.out.println("Starting " +clazz);
        try {
            method = clazz.getDeclaredMethod("main",
                    new Class[] { String[].class });
        } catch (Exception e) {
            System.out.println("There is no main(String[] argv) in " + clazz
                    + ".\n" + e);
            System.exit(1);
        }

        Clock.start();
        try {
            method.invoke(null, argList);
        } catch (InvocationTargetException e) {
            Throwable t = e.getTargetException();
            if (t instanceof DebuggerExit) {
                System.out.println("In target program: \n" + clazz + "."
                        + method.getName() + " System.exit() called\n");
                D.PAUSE_PROGRAM = true;
                SHOW = true;
                D.DISABLE = true;
                // The program should be dead, so always show.

            } else {
                System.out.println("In target program2: \n" + clazz + "."
                        + method.getName() + " threw " + t);
                TraceLine tl = TraceLine.getFirstTraceline();
                Throwable t1;
                if (t instanceof Exception)
                    t1 = t;
                else
                    t1 = new DebuggerException("" + t);
                if (tl != null)
                    D.catchEx(tl.getSourceLine().getIndex(), t1, tl);
                t.printStackTrace();
            }
        } catch (IllegalAccessException e) {
            System.out.println("main() not static in target program?: \n"
                    + clazz + "." + method.getName() + " threw " + e);
        } catch (Exception e) {
            System.out.println("IMPOSSIBLE? In target program: \n" + clazz
                    + "." + method.getName() + " threw " + e);
            e.printStackTrace();
        }

        if (TimeStamp.eott() < 2) {
            println("Collected no data on this run. Is target debugified?");
        }

        endTime = new Date().getTime();
        totalTime = endTime - startTime;
        if (SHOW)
            printStatistics();
    }

    static void restartTarget() { // Only called from event thread.
        D.killTarget();
        if (D.getCheckPattern())
            D.DISABLE = true;
        else
            D.DISABLE = false;
        startTarget(clazz);
    }

    static void startTarget(Class clazz) { // Only called from event thread.
        final Class clazzz = clazz;
        final Object[] argListt = argList;

        (new Thread(new Runnable() {
            public void run() {
                runTarget(clazzz, argListt);
                stopTarget();
            }
        }, "main")).start();
    }

    static void stopTarget() {
        D.PAUSE_PROGRAM = PAUSE_ON_STOP;
        D.KILL_TARGET = KILL_TARGET_ON_STOP;
        D.DISABLE = true;
        if (NO_WINDOWS)
            return;
        Runnable r = new Runnable() {
            public void run() {
                createDebugger();
            }
        };
        SwingUtilities.invokeLater(r);
    }

    public static void printStatistics() {
        if (DEBUG_DEBUGGER)
            printAllStatistics();
        else
            printSomeStatistics();
    }

    public static void printSomeStatistics() {
        Runtime run = Runtime.getRuntime();
        println(version + " run complete.");
        System.gc();
        System.out.println(" Realtime: " + totalTime / 1000.0 + " secs "
                + " TimeStamps Created: " + TimeStamp.nTSCreated + " ("
                + (TimeStamp.nTSCreated - TimeStamp.index) + " GC'd, leaving "
                + TimeStamp.index + ") ");
        System.out.println(" Memory: " + run.freeMemory() / 1000000
                + "MB free / " + run.totalMemory() / 1000000 + "MB max");
    }

    public static void printAllStatistics() {
        Runtime run = Runtime.getRuntime();
        println(version + " run complete.");
        System.gc();
        System.out.println(" Realtime: " + totalTime / 1000.0 + " secs "
                + " TimeStamps Created: " + TimeStamp.nTSCreated + " ("
                + (TimeStamp.nTSCreated - TimeStamp.index) + " GC'd, leaving "
                + TimeStamp.index + ") ");
        System.out.println(" Memory: " + run.freeMemory() / 1000000
                + "MB free / " + run.totalMemory() / 1000000 + "MB max");
        TraceLine.countInstrumentedMethods();
        // ShadowLocals: "+ ShadowLocal.NCreated+"
        System.out.println(" HistoryList Entries: " + HistoryList.nEntries
                + "\n SourceLines: " + SourceLine.nEntries + " TraceLines: "
                + TraceLine.nTraceLines + " of which Instrumented: "
                + TraceLine.nInstrumented + "\n HistoryListSingleton created: "
                + HistoryListSingleton.getNCreated()
                + " HistoryListSingleton upgraded: "
                + HistoryListSingleton.getNUpgraded() + " Lookups: "
                + TimeStamp.lookupSize() + "\n Shadows: " + Shadow.tableSize()
                + " Shadow entries " + Shadow.nEntries()
                + "\n Context Switches: " + TimeStamp.nContextSwitches()
                + "\n Time Debugifying Classes: " + timeDebugifying / 1000.0
                + " secs");
        HistoryList.printStatistics();
        Locals.printStatistics();
        Shadow.printStatistics();
        TraceLine.printStatistics();
    }

    public static String getMessage() {
        return (miniBuffer.getText());
    }

    public static void message(String msg, boolean beep) {
        MiniBuffer.message(msg, beep);
    }

    static ImageIcon upImage;
    static ImageIcon downImage;
    static ImageIcon firstImage;
    static ImageIcon backImage;
    static ImageIcon forwardImage;
    static ImageIcon lastImage;
    static ImageIcon loopImage;
    static ImageIcon backLoopImage;
    static ImageIcon prevLineImage;
    static ImageIcon nextLineImage;

    public static JList StackPList, LocalsPList, TracePList, ObjectsPList,
            ThisPList, ThreadPList, codeJList, TTYPList;
    public static JLabel TSLabel = null;
    public static JPopupMenu traceMenu;
    public static JPanel topPanel;
    public static boolean reverting = false;
    public static JTextArea miniBuffer;
    public static String codePanelCurrentFile = null;
    public static Thread CURRENT_THREAD = null;
    public static JSlider timeSlider;

    public static void setCurrentThread(Thread t) {
        CURRENT_THREAD = t;
    }

    public static Thread currentThread() {
        if ((TimeStamp.empty()) || (CURRENT_THREAD == null))
            CURRENT_THREAD = Thread.currentThread();
        return (CURRENT_THREAD);
    }

    public static JCheckBoxMenuItem firstLine; // , threadNextCommand;

    private void createFilterMenu(JMenuBar panel) {
        JMenu menu = new JMenu("Filter");
        FilterMenuActionListener listener = new FilterMenuActionListener();
        JMenuItem filterMethodC = createJMenuItemAlt(menu,
                "Filter out method in class", KeyEvent.VK_F, null, listener);
        JMenuItem filterMethod = createJMenuItemAlt(menu, "Filter out method",
                KeyEvent.VK_M, null, listener);
        JMenuItem filterMethodI = createJMenuItemAlt(menu,
                "Filter out method internals", 0, null, listener);
        JMenuItem unfilter = createJMenuItemAlt(menu, "Unfilter",
                KeyEvent.VK_U, null, listener);
        JMenuItem filterClass = createJMenuItemAlt(menu,
                "Filter out all methods in class", 0, null, listener);
        JMenuItem save = createJMenuItemAlt(menu, "Save filters to files", 0,
                null, listener);
        JMenuItem filterIn = createJMenuItemAlt(menu, "Filter in method",
                KeyEvent.VK_I, null, listener);
        JMenuItem filter1 = createJMenuItemAlt(menu, "Filter out depth>1", 0,
                null, listener);
        JMenuItem filter2 = createJMenuItemAlt(menu, "Filter out depth>2", 0,
                null, listener);
        JMenuItem filter3 = createJMenuItemAlt(menu, "Filter out depth>3", 0,
                null, listener);
        JMenuItem filter4 = createJMenuItemAlt(menu, "Filter out depth>4", 0,
                null, listener);
        JMenuItem filter5 = createJMenuItemAlt(menu, "Filter out depth>5", 0,
                null, listener);
        JMenuItem filter6 = createJMenuItemAlt(menu, "Filter out depth>6", 0,
                null, listener);
        JMenuItem filter7 = createJMenuItemAlt(menu, "Filter out depth>7", 0,
                null, listener);
        JMenuItem filter8 = createJMenuItemAlt(menu, "Filter out depth>8", 0,
                null, listener);
        JMenuItem filter9 = createJMenuItemAlt(menu, "Filter out depth>9", 0,
                null, listener);
        listener.addButtons(filterMethodC, unfilter, filterClass, save,
                filterIn, filter1, filter2, filter3, filter4, filter5, filter6,
                filter7, filter8, filter9, filterMethod, filterMethodI);
        panel.add(menu);
    }

    private void createTraceMenu(JMenuBar panel) {
        JMenu menu = new JMenu("Trace");
        TraceMenuActionListener listener = new TraceMenuActionListener();
        JMenuItem copy0MenuItem = createJMenuItemAlt(menu, "Copy 'this'", 0,
                null, listener);
        JMenuItem copy1MenuItem = createJMenuItemAlt(menu, "Copy argument 1",
                KeyEvent.VK_1, null, listener);
        JMenuItem copy2MenuItem = createJMenuItemAlt(menu, "Copy argument 2",
                KeyEvent.VK_2, null, listener);
        JMenuItem copy3MenuItem = createJMenuItemAlt(menu, "Copy argument 3",
                KeyEvent.VK_3, null, listener);
        JMenuItem copy4MenuItem = createJMenuItemAlt(menu, "Copy argument 4",
                KeyEvent.VK_4, null, listener);
        JMenuItem copy5MenuItem = createJMenuItemAlt(menu, "Copy argument 5",
                KeyEvent.VK_5, null, listener);
        JMenuItem copyrMenuItem = createJMenuItemAlt(menu, "Copy return value",
                0, null, listener);
        JMenuItem searchMenuItem = createJMenuItemCTRL(menu, "Search",
                KeyEvent.VK_S, "Search Trace Pane for string", listener);
        JMenuItem rsearchMenuItem = createJMenuItemCTRL(menu, "Reverse Search",
                KeyEvent.VK_R, "Reverse search Trace Pane for string", listener);
        JMenuItem esearchMenuItem = createJMenuItem(menu, "End Search",
                KeyEvent.VK_ENTER, "End Search and revert", listener);
        JMenuItem fgetMenuItem = createJMenuItemCTRL(menu, "fget",
                KeyEvent.VK_F, "fget ", listener);
        JMenuItem cdataMenuItem = createJMenuItemCTRL(menu, "cdata",
                KeyEvent.VK_C, "cdata ", listener);
        JMenuItem fgetStartMenuItem = createJMenuItemCTRL(menu,
                "Save start pattern", 0, "Save the fget pattern for start",
                listener);
        JMenuItem fgetStopMenuItem = createJMenuItemCTRL(menu,
                "Save stop pattern", 0, "Save the fget pattern for stop",
                listener);
        JMenuItem countMenuItem = createJMenuItemCTRL(menu,
                "Total no. of matches", KeyEvent.VK_T,
                "Count matches for current fget/cdata pattern", listener);
        JMenuItem fgetSFLMenuItem = createJMenuItemCTRL(menu,
                "Save start on current line", 0,
                "Save the fget pattern to start on this line", listener);
        JMenuItem fgetQueryMenuItem = createJMenuItemCTRL(menu,
                "Create FGET query", 0,
                "Create a query which matches the current traceline", listener);
        JMenuItem fgetSLQueryMenuItem = createJMenuItemCTRL(menu,
                "Create FGET SourceLine query", 0,
                "Create a query which matches the current SourceLine", listener);
        firstLine = new JCheckBoxMenuItem("Go to first line in method");
        firstLine.setState(true);
        menu.add(firstLine);
        /*
         * threadNextCommand = new JCheckBoxMenuItem("Thread previous/next goes
         * to NEXT thread"); threadNextCommand.setState(true);
         * menu.add(threadNextCommand);
         */
        listener.addButtons(copy0MenuItem, copy1MenuItem, copy2MenuItem,
                copy3MenuItem, copy4MenuItem, copy5MenuItem, copyrMenuItem,
                searchMenuItem, rsearchMenuItem, esearchMenuItem,
                cdataMenuItem, fgetMenuItem, fgetStartMenuItem,
                fgetStopMenuItem, countMenuItem, fgetSFLMenuItem,
                fgetQueryMenuItem, fgetSLQueryMenuItem);
        panel.add(menu);
    }

    private void createObjectsMenu(JMenuBar panel) {
        JMenu menu = new JMenu("Objects");
        // menu.setMnemonic('O');
        ObjectsMenuActionListener listener = new ObjectsMenuActionListener();

        JMenuItem copyClassMenuItem = createJMenuItemAlt(menu, "Add Class",
                KeyEvent.VK_K, "Add the Class of the selected object", listener);
        JMenuItem removeMenuItem = createJMenuItemAlt(menu, "Remove",
                KeyEvent.VK_R, "Remove the selected object", listener);
        JMenuItem expandMenuItem = createJMenuItemAlt(menu, "Expand",
                KeyEvent.VK_E, "Expand/Close the selected object", listener);
        JMenuItem selectMenuItem = createJMenuItemAlt(menu, "Select IV Value",
                KeyEvent.VK_S,
                "Select new value from list of values (Objects Pane)", listener);
        JMenuItem localMenuItem = createJMenuItemAlt(menu,
                "Select Local Value", KeyEvent.VK_L,
                "Select new value from list of values (Locals Pane)", listener);
        JMenuItem retainMenuItem = createJMenuItemAlt(menu, "Retain Only",
                KeyEvent.VK_O, "Retain only the selected IV", listener);
        JMenuItem setMenuItem = createJMenuItemAlt(menu, "Assign",
                KeyEvent.VK_A, "Assign new value to IV", listener);
        JMenuItem copyMenuItem = createJMenuItemAlt(menu, "Copy",
                KeyEvent.VK_C, "Copy into minibuffer", listener);
        JMenuItem abortMenuItem = createJMenuItemCTRL(menu, "Abort",
                KeyEvent.VK_G, "Abort current minibuffer command", listener);
        JMenuItem showAllMenuItem = createJMenuItemAlt(menu, "ShowAll", 0,
                "Show all IVs", listener);
        JMenuItem restoreMenuItem = createJMenuItemAlt(menu, "Restore", 0,
                "Restore all IVs", listener);
        JMenuItem addMenuItem = createJMenuItemAlt(menu,
                "Add Instance Variable", KeyEvent.VK_V,
                "Add the selected instance varible value", listener);
        JMenuItem hexMenuItem = createJMenuItemAlt(menu, "Special Format",
                KeyEvent.VK_X, "Display selected objects in special format",
                listener);
        JMenuItem printMenuItem = createJMenuItemAlt(menu, "Print", 0,
                "Print the selected object on terminal", listener);
        JMenuItem toStringMenuItem = createJMenuItemAlt(menu, "toString", 0,
                "Display obj.toString()", listener);
        JMenuItem inputObjectMenuItem = createJMenuItemAlt(menu,
                "Input Object", 0, "Input object from mini-buffer", listener);
        listener.addButtons(copyClassMenuItem, removeMenuItem, expandMenuItem,
                selectMenuItem, localMenuItem, retainMenuItem, setMenuItem,
                abortMenuItem, copyMenuItem, showAllMenuItem, restoreMenuItem,
                addMenuItem, hexMenuItem, printMenuItem, toStringMenuItem,
                inputObjectMenuItem);
        panel.add(menu);
    }

    private void createHelpMenu(JMenuBar panel) {
        JMenu menu = new JMenu("Help");
        // menu.setMnemonic('H');
        HelpMenuActionListener listener = new HelpMenuActionListener();
        JMenuItem ghelpMenuItem = createJMenuItemAlt(menu, "General Help", 0,
                "Show help message in mini buffer (bottom of Debugger)",
                listener);
        JMenuItem dhelpMenuItem = createJMenuItemAlt(
                menu,
                "ENV var Help",
                0,
                "Show Environment variable help message in mini buffer (bottom of Debugger)",
                listener);
        JMenuItem fhelpMenuItem = createJMenuItemAlt(menu, "FGET Help", 0,
                "Show FGET help message in mini buffer (bottom of Debugger)",
                listener);
        listener.addButtons(ghelpMenuItem, fhelpMenuItem, dhelpMenuItem);
        panel.add(menu);
    }

    private void createDebugMenu(JMenuBar panel) {
        JMenu menu = new JMenu("Debug");
        DebugMenuActionListener listener = new DebugMenuActionListener();
        JMenuItem recordMenuItem = createJMenuItemAlt(menu, "Record", 0,
                "Record Commands", listener);
        JMenuItem saveMenuItem = createJMenuItemAlt(menu, "Save", 0,
                "Save Commands to .debuggerCommands", listener);
        JMenuItem replayMenuItem = createJMenuItemAlt(menu, "Replay", 0,
                "Replay Commands", listener);
        JMenuItem dumpMenuItem = createJMenuItemAlt(menu, "Dump", 0,
                "Dump All Data to TTY", listener);
        JMenuItem statsMenuItem = createJMenuItemAlt(menu, "Statistics", 0,
                "Print out statistics to TTY", listener);
        JMenuItem revertMenuItem = createJMenuItemAlt(menu, "Revert", 0,
                "Revert to every time stamp in program", listener);
        JMenuItem testMenuItem = createJMenuItemAlt(menu, "Test", 0,
                "Run a test function", listener);
        JMenuItem wideMenuItem = createJMenuItemAlt(menu, "Wide", 0,
                "Show wide strings", listener);
        JMenuItem repeatMenuItem = createJMenuItemAlt(menu, "Repeat",
                KeyEvent.VK_SPACE, "Repeat last button command", listener);
        listener.addButtons(recordMenuItem, saveMenuItem, replayMenuItem,
                dumpMenuItem, statsMenuItem, revertMenuItem, testMenuItem,
                wideMenuItem, repeatMenuItem);
        panel.add(menu);
    }

    private JMenuItem createJMenuItemAlt(JMenu menu, String text, int key,
            String tooltip, ActionListener listener) {
        JMenuItem jm = new JMenuItem(text);
        if (key > 0)
            jm
                    .setAccelerator(KeyStroke.getKeyStroke(key,
                            ActionEvent.ALT_MASK));
        if (tooltip != null)
            jm.setToolTipText(tooltip);
        menu.add(jm);
        jm.addActionListener(listener);
        return jm;
    }

    private JMenuItem createJMenuItemCTRL(JMenu menu, String text, int key,
            String tooltip, ActionListener listener) {
        JMenuItem jm = new JMenuItem(text);
        if (key > 0)
            jm.setAccelerator(KeyStroke
                    .getKeyStroke(key, ActionEvent.CTRL_MASK));
        if (tooltip != null)
            jm.setToolTipText(tooltip);
        menu.add(jm);
        jm.addActionListener(listener);
        return jm;
    }

    private JMenuItem createJMenuItem(JMenu menu, String text, int key,
            String tooltip, ActionListener listener) {
        JMenuItem jm = new JMenuItem(text);
        if (key > 0)
            jm.setAccelerator(KeyStroke.getKeyStroke(key, 0));
        if (tooltip != null)
            jm.setToolTipText(tooltip);
        menu.add(jm);
        jm.addActionListener(listener);
        return jm;
    }

    private JSlider createTimeSlider() {
        timeSlider = new JSlider(JSlider.HORIZONTAL, 0, 0, 0);
        // Set in updateSlider
        timeSlider.addChangeListener(new TimeSliderListener());
        // timeSlider.setMajorTickSpacing(TimeStamp.eott()/20);
        // timeSlider.setPaintTicks(true);
        // timeSlider.setPaintLabels(true);
        timeSlider.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));

        return (timeSlider);
    }

    public static JCheckBoxMenuItem codeDirection, codeOutsideOK, codeThreadOK,
            codeAnyDirection;

    private void createCodeMenu(JMenuBar panel) {
        JMenu menu = new JMenu("Code");
        codeDirection = new JCheckBoxMenuItem("Normal Direction");
        codeDirection.setState(true);
        codeAnyDirection = new JCheckBoxMenuItem("Any Direction OK");
        codeAnyDirection.setState(true);
        codeOutsideOK = new JCheckBoxMenuItem("Outside Current Stack Frame OK");
        codeOutsideOK.setState(true);
        codeThreadOK = new JCheckBoxMenuItem("Any Thread OK");

        StackMenuActionListener listener = new StackMenuActionListener();
        JMenuItem gotoStackJMenuItem = createJMenuItemAlt(menu,
                "Goto Stack Frame", 0, "Goto selected stack frame", listener);
        listener.addButtons(gotoStackJMenuItem);

        menu.add(codeAnyDirection);
        menu.add(codeDirection);
        menu.add(codeOutsideOK);
        menu.add(codeThreadOK);
        menu.add(gotoStackJMenuItem);
        panel.add(menu);
    }

    private void createFileMenu(JMenuBar panel) {
        JMenu menu = new JMenu("File");
        FileMenuActionListener listener = new FileMenuActionListener();
        JMenuItem openJMenuItem = createJMenuItemAlt(menu, "Open", 0,
                "Open File", listener);
        JMenuItem exitJMenuItem = createJMenuItemAlt(menu, "Exit", 0,
                "Open File", listener);
        JMenuItem addJMenuItem = createJMenuItemCTRL(menu, "Add Mark",
                KeyEvent.VK_SPACE, "Add a mark to the ring", listener);
        JMenuItem previousJMenuItem = createJMenuItemCTRL(menu,
                "Previous Mark", KeyEvent.VK_X, "Cycle one mark in the ring",
                listener);
        JMenuItem clearJMenuItem = createJMenuItemCTRL(menu, "Clear Marks", 0,
                "Clear the mark ring", listener);
        listener.addButtons(openJMenuItem, exitJMenuItem, addJMenuItem,
                previousJMenuItem, clearJMenuItem);
        panel.add(menu);
    }

    private void createRunMenu(JMenuBar panel) {
        JMenu menu = new JMenu("Run");
        RunMenuActionListener listener = new RunMenuActionListener();
        JMenuItem restartJMenuItem = createJMenuItemAlt(menu, "Restart", 0,
                "Clear memory and restart", listener);
        JMenuItem clearJMenuItem = createJMenuItemAlt(menu, "Clear", 0,
                "Clear everything.", listener);
        JMenuItem startJMenuItem = createJMenuItemAlt(menu,
                "Start Recording on Output", 0,
                "Start Recording on Selected TTY Output", listener);
        JMenuItem stopJMenuItem = createJMenuItemAlt(menu,
                "Stop Recording on Output", 0,
                "Stop Recording on Selected TTY Output", listener);
        JMenuItem startLJMenuItem = createJMenuItemAlt(menu,
                "Start Recording on Line", 0,
                "Start Recording on Selected Line", listener);
        JMenuItem stopLJMenuItem = createJMenuItemAlt(menu,
                "Stop Recording on Line", 0, "Stop Recording on Selected Line",
                listener);
        JMenuItem callJMenuItem = createJMenuItemCTRL(menu,
                "Evaluate Expression", KeyEvent.VK_E,
                "Example: .copy(, 1)", listener);
        JMenuItem switchJMenuItem = createJMenuItemCTRL(menu,
                "Switch Timelines", KeyEvent.VK_O,
                "Switch to the other Timeline", listener);
        JMenuItem clearSSJMenuItem = createJMenuItemCTRL(menu,
                "Clear Start/Stop", 0, "Clear All Start/Stop Request", listener);
        listener.addButtons(restartJMenuItem, clearJMenuItem, startJMenuItem,
                stopJMenuItem, startLJMenuItem, stopLJMenuItem, callJMenuItem,
                switchJMenuItem, clearSSJMenuItem);
        panel.add(menu);
    }

    public static void clear() {
        TraceLine.clear();
        TimeStamp.clear();
        Shadow.clear();
        ObjectPane.clear();
        ThreadPane.clear();
        StackList.clear();
        LocalsPane.clear();
        ThisPane.clear();
        TTYPane.clear();
        updateUIs();
        revert(); // Defaults to "NO TIME"
    }

    public static void clearTimeLine() {
        Shadow.reset();
        TraceLine.clear();
        TimeStamp.clear();
        ThreadPane.clear();
        StackList.clear();
        LocalsPane.clear();
        ThisPane.clear();
        TTYPane.clear();
        updateUIs();
        revert(); // Defaults to "NO TIME"
    }

    public static boolean mainTimeLine = true;

    public static void switchTimeLines(boolean clear) {
        Shadow.switchTimeLines(clear);
        TraceLine.switchTimeLines(clear);
        TimeStamp.switchTimeLines(clear);
        ObjectPane.switchTimeLines(clear);
        ThreadPane.switchTimeLines(clear);
        ThreadPList.setSelectedIndex(0); // HACK
        StackList.switchTimeLines(clear);
        ThisPane.switchTimeLines(clear);
        TTYPane.switchTimeLines(clear);
        if (TimeStamp.empty()) {
            // TimeStamp.clear() does this too. So this is never run?
            D.DISABLE = false;
            D.stamp(0, null);
            // The redisplay for Shadows in ObjectPane expect a valid TS
            D.DISABLE = true;
        }
        revert();
        firstTimeTracePane = true;
        updateUIs();

        mainTimeLine = !mainTimeLine;
    }

    public static void updateUIs() {
        reverting = true;
        updateThisPanel(null);
        ThreadPList.updateUI();
        TracePList.updateUI();
        LocalsPList.updateUI();
        ThisPList.updateUI();
        StackPList.updateUI();
        ObjectsPList.updateUI();
        TTYPList.updateUI();
        // updateTimeSlider();
        reverting = false;
    }

    public static void dump() {
        Debugger.printStatistics();
        previousTime = TimeStamp.currentTime();
        TimeStamp.printAll();
        TraceLine.printAll();
        Shadow.printAll();
        TTYPane.printAll();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy