001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.drjava.ui;
038:
039: import java.util.Vector;
040:
041: import java.util.Enumeration;
042:
043: import javax.swing.*;
044: import javax.swing.tree.*;
045: import javax.swing.table.*;
046: import java.awt.event.*;
047: import java.awt.*;
048:
049: import edu.rice.cs.drjava.model.SingleDisplayModel;
050: import edu.rice.cs.drjava.model.debug.*;
051: import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
052: import edu.rice.cs.drjava.config.*;
053: import edu.rice.cs.util.swing.Utilities;
054: import edu.rice.cs.util.swing.RightClickMouseAdapter;
055:
056: /**
057: * Panel for displaying the debugger input and output in MainFrame. This
058: * class is a swing view class and hence should only be accessed from the
059: * event-handling thread.
060: * @version $Id: DebugPanel.java 4255 2007-08-28 19:17:37Z mgricken $
061: */
062: public class DebugPanel extends JPanel implements OptionConstants {
063:
064: private JSplitPane _tabsPane;
065: private JTabbedPane _leftPane;
066: private JTabbedPane _rightPane;
067: private JPanel _tabsAndStatusPane;
068:
069: private JTable _watchTable;
070: private JTable _stackTable;
071: private JTable _threadTable;
072: private long _currentThreadID;
073:
074: // private JPopupMenu _threadRunningPopupMenu;
075: private JPopupMenu _threadSuspendedPopupMenu;
076: private JPopupMenu _stackPopupMenu;
077: private JPopupMenu _watchPopupMenu;
078: private DebugThreadData _threadInPopup;
079:
080: private final SingleDisplayModel _model;
081: private final MainFrame _frame;
082: private final Debugger _debugger;
083:
084: private JPanel _buttonPanel;
085: private JButton _closeButton;
086: private JButton _resumeButton;
087: private JButton _stepIntoButton;
088: private JButton _stepOverButton;
089: private JButton _stepOutButton;
090: private JLabel _statusBar;
091:
092: private Vector<DebugWatchData> _watches;
093: private Vector<DebugThreadData> _threads;
094: private Vector<DebugStackData> _stackFrames;
095:
096: private DefaultTreeCellRenderer dtcr;
097:
098: /** Constructs a new panel to display debugging information when the Debugger is active. This is swing view class and hence should only
099: * be accessed from the event-handling thread.
100: */
101: public DebugPanel(MainFrame frame) {
102:
103: this .setLayout(new BorderLayout());
104:
105: _frame = frame;
106: _model = frame.getModel();
107: _debugger = _model.getDebugger();
108:
109: _watches = new Vector<DebugWatchData>();
110: _threads = new Vector<DebugThreadData>();
111: _stackFrames = new Vector<DebugStackData>();
112: _leftPane = new JTabbedPane();
113: _rightPane = new JTabbedPane();
114:
115: _setupTabPanes();
116:
117: _tabsPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
118: _leftPane, _rightPane);
119: _tabsPane.setOneTouchExpandable(true);
120: _tabsPane.setDividerLocation((int) (_frame.getWidth() / 2.5));
121:
122: _tabsAndStatusPane = new JPanel(new BorderLayout());
123: _tabsAndStatusPane.add(_tabsPane, BorderLayout.CENTER);
124:
125: _statusBar = new JLabel("");
126: _statusBar.setForeground(Color.blue.darker());
127:
128: _tabsAndStatusPane.add(_statusBar, BorderLayout.SOUTH);
129:
130: this .add(_tabsAndStatusPane, BorderLayout.CENTER);
131:
132: _buttonPanel = new JPanel(new BorderLayout());
133: _setupButtonPanel();
134: this .add(_buttonPanel, BorderLayout.EAST);
135:
136: _debugger.addListener(new DebugPanelListener());
137:
138: // Setup the color listeners.
139: _setColors(_watchTable);
140: _setColors(_stackTable);
141: _setColors(_threadTable);
142: }
143:
144: /** Quick helper for setting up color listeners. */
145: private static void _setColors(Component c) {
146: new ForegroundColorListener(c);
147: new BackgroundColorListener(c);
148: }
149:
150: /** Causes all display tables to update their information from the debug manager. */
151: public void updateData() {
152: assert EventQueue.isDispatchThread();
153: if (_debugger.isReady()) {
154: try {
155: _watches = _debugger.getWatches();
156:
157: if (_debugger.isCurrentThreadSuspended())
158: _stackFrames = _debugger.getCurrentStackFrameData();
159: else
160: _stackFrames = new Vector<DebugStackData>();
161:
162: _threads = _debugger.getCurrentThreadData();
163: } catch (DebugException de) {
164: // Thrown if
165: _frame._showDebugError(de);
166: }
167: } else {
168: // Clean up if debugger dies
169: _watches = new Vector<DebugWatchData>();
170: _threads = new Vector<DebugThreadData>();
171: _stackFrames = new Vector<DebugStackData>();
172: }
173:
174: ((AbstractTableModel) _watchTable.getModel())
175: .fireTableDataChanged();
176: ((AbstractTableModel) _stackTable.getModel())
177: .fireTableDataChanged();
178: ((AbstractTableModel) _threadTable.getModel())
179: .fireTableDataChanged();
180: }
181:
182: /** Creates the tabbed panes in the debug panel. */
183: private void _setupTabPanes() {
184:
185: // Watches table
186: _initWatchTable();
187:
188: // Stack table
189: _stackTable = new JTable(new StackTableModel());
190: _stackTable.addMouseListener(new StackMouseAdapter());
191:
192: _rightPane.addTab("Stack", new JScrollPane(_stackTable));
193:
194: // Thread table
195: _initThreadTable();
196:
197: // Sets the method column to always be 7 times as wide as the line column
198: TableColumn methodColumn;
199: TableColumn lineColumn;
200: methodColumn = _stackTable.getColumnModel().getColumn(0);
201: lineColumn = _stackTable.getColumnModel().getColumn(1);
202: methodColumn.setPreferredWidth(7 * lineColumn
203: .getPreferredWidth());
204:
205: _initPopup();
206: }
207:
208: private void _initWatchTable() {
209: _watchTable = new JTable(new WatchTableModel());
210: _watchTable.setDefaultEditor(_watchTable.getColumnClass(0),
211: new WatchEditor());
212: _watchTable.setDefaultRenderer(_watchTable.getColumnClass(0),
213: new WatchRenderer());
214:
215: _leftPane.addTab("Watches", new JScrollPane(_watchTable));
216: }
217:
218: private void _initThreadTable() {
219: _threadTable = new JTable(new ThreadTableModel());
220: _threadTable.addMouseListener(new ThreadMouseAdapter());
221: _rightPane.addTab("Threads", new JScrollPane(_threadTable));
222:
223: // Sets the name column to always be 2 times as wide as the status column
224: TableColumn nameColumn;
225: TableColumn statusColumn;
226: nameColumn = _threadTable.getColumnModel().getColumn(0);
227: statusColumn = _threadTable.getColumnModel().getColumn(1);
228: nameColumn.setPreferredWidth(2 * statusColumn
229: .getPreferredWidth());
230:
231: // Adds a cell renderer to the threads table
232: _currentThreadID = 0;
233: TableCellRenderer threadTableRenderer = new DefaultTableCellRenderer() {
234: public Component getTableCellRendererComponent(
235: JTable table, Object value, boolean isSelected,
236: boolean hasFocus, int row, int column) {
237: Component renderer = super
238: .getTableCellRendererComponent(table, value,
239: isSelected, hasFocus, row, column);
240:
241: _setThreadCellFont(row);
242:
243: return renderer;
244: }
245:
246: /**
247: * Sets the font for a cell in the thread table.
248: * @param row the current row
249: */
250: private void _setThreadCellFont(int row) {
251: DebugThreadData currThread = _threads.get(row);
252: if (currThread.getUniqueID() == _currentThreadID
253: && currThread.isSuspended()) {
254: setFont(getFont().deriveFont(Font.BOLD));
255: }
256: }
257: };
258: _threadTable.getColumnModel().getColumn(0).setCellRenderer(
259: threadTableRenderer);
260: _threadTable.getColumnModel().getColumn(1).setCellRenderer(
261: threadTableRenderer);
262: }
263:
264: /** Adds config color support to DefaultCellEditor. */
265: private static class WatchEditor extends DefaultCellEditor {
266:
267: WatchEditor() {
268: super (new JTextField());
269: }
270:
271: /**
272: * Overrides the default editor component to use proper coloring.
273: */
274: public Component getTableCellEditorComponent(JTable table,
275: Object value, boolean isSelected, int row, int column) {
276: Component editor = super .getTableCellEditorComponent(table,
277: value, isSelected, row, column);
278: _setColors(editor);
279: return editor;
280: }
281: }
282:
283: /** Adds config color support to DefaultTableCellRenderer. */
284: private class WatchRenderer extends DefaultTableCellRenderer {
285:
286: /**
287: * Overrides the default rederer component to use proper coloring.
288: */
289: public Component getTableCellRendererComponent(JTable table,
290: Object value, boolean isSelected, boolean hasFocus,
291: int row, int column) {
292: Component renderer = super .getTableCellRendererComponent(
293: table, value, isSelected, hasFocus, row, column);
294: _setColors(renderer);
295: _setWatchCellFont(row);
296: return renderer;
297: }
298:
299: /**
300: * Sets the font for a cell in the watch table.
301: * @param row the current row
302: */
303: private void _setWatchCellFont(int row) {
304: int numWatches = _watches.size();
305: if (row < numWatches) {
306: DebugWatchData currWatch = _watches.get(row);
307: if (currWatch.isChanged()) {
308: setFont(getFont().deriveFont(Font.BOLD));
309: }
310: }
311: }
312: }
313:
314: /** A table for displaying the watched variables and fields. Where is the synchronization for this class? */
315: public class WatchTableModel extends AbstractTableModel {
316:
317: private String[] _columnNames = { "Name", "Value", "Type" };
318:
319: public String getColumnName(int col) {
320: return _columnNames[col];
321: }
322:
323: public int getRowCount() {
324: return _watches.size() + 1;
325: }
326:
327: public int getColumnCount() {
328: return _columnNames.length;
329: }
330:
331: public Object getValueAt(int row, int col) {
332: if (row < _watches.size()) {
333: DebugWatchData watch = _watches.get(row);
334: switch (col) {
335: case 0:
336: return watch.getName();
337: case 1:
338: return watch.getValue();
339: case 2:
340: return watch.getType();
341: }
342: fireTableRowsUpdated(row, _watches.size() - 1);
343: return null;
344: } else {
345: fireTableRowsUpdated(row, _watches.size() - 1);
346: // Last row blank
347: return "";
348: }
349: }
350:
351: public boolean isCellEditable(int row, int col) {
352: // First col for entering new values
353: if (col == 0)
354: return true;
355: return false;
356: }
357:
358: public void setValueAt(Object value, int row, int col) {
359: try {
360: if ((value == null) || (value.equals(""))) {
361: // Remove value
362: _debugger.removeWatch(row);
363: } else {
364: if (row < _watches.size())
365: _debugger.removeWatch(row);
366: // Add value
367: _debugger.addWatch(String.valueOf(value));
368: }
369: //fireTableCellUpdated(row, col);
370: fireTableRowsUpdated(row, _watches.size() - 1);
371: } catch (DebugException de) {
372: _frame._showDebugError(de);
373: }
374: }
375: }
376:
377: /** A table for displaying the current stack trace. */
378: public class StackTableModel extends AbstractTableModel {
379:
380: private String[] _columnNames = { "Method", "Line" }; // Do we need #?
381:
382: public String getColumnName(int col) {
383: return _columnNames[col];
384: }
385:
386: public int getRowCount() {
387: if (_stackFrames == null)
388: return 0;
389: return _stackFrames.size();
390: }
391:
392: public int getColumnCount() {
393: return _columnNames.length;
394: }
395:
396: public Object getValueAt(int row, int col) {
397: DebugStackData frame = _stackFrames.get(row);
398: switch (col) {
399: case 0:
400: return frame.getMethod();
401: case 1:
402: return new Integer(frame.getLine());
403: }
404: return null;
405: }
406:
407: public boolean isCellEditable(int row, int col) {
408: return false;
409: }
410: }
411:
412: /** A table for displaying all current threads. Where is the synchronization for this class? */
413: public class ThreadTableModel extends AbstractTableModel {
414:
415: private String[] _columnNames = { "Name", "Status" };
416:
417: public String getColumnName(int col) {
418: return _columnNames[col];
419: }
420:
421: public int getRowCount() {
422: if (_threads == null)
423: return 0;
424: return _threads.size();
425: }
426:
427: public int getColumnCount() {
428: return _columnNames.length;
429: }
430:
431: public Object getValueAt(int row, int col) {
432: DebugThreadData threadData = _threads.get(row);
433: switch (col) {
434: case 0:
435: return threadData.getName();
436: case 1:
437: return threadData.getStatus();
438: default:
439: return null;
440: }
441:
442: }
443:
444: public boolean isCellEditable(int row, int col) {
445: return false;
446: }
447: }
448:
449: /** Creates the buttons for controlling the debugger. */
450: private void _setupButtonPanel() {
451: JPanel mainButtons = new JPanel();
452: JPanel emptyPanel = new JPanel();
453: JPanel closeButtonPanel = new JPanel(new BorderLayout());
454: GridBagLayout gbLayout = new GridBagLayout();
455: GridBagConstraints c = new GridBagConstraints();
456: mainButtons.setLayout(gbLayout);
457:
458: Action resumeAction = new AbstractAction("Resume") {
459: public void actionPerformed(ActionEvent ae) {
460: try {
461: _frame.debuggerResume();
462: } catch (DebugException de) {
463: _frame._showDebugError(de);
464: }
465: }
466: };
467: _resumeButton = new JButton(resumeAction);
468:
469: Action stepIntoAction = new AbstractAction("Step Into") {
470: public void actionPerformed(ActionEvent ae) {
471: _frame.debuggerStep(Debugger.StepType.STEP_INTO);
472: }
473: };
474: _stepIntoButton = new JButton(stepIntoAction);
475:
476: Action stepOverAction = new AbstractAction("Step Over") {
477: public void actionPerformed(ActionEvent ae) {
478: _frame.debuggerStep(Debugger.StepType.STEP_OVER);
479: }
480: };
481: _stepOverButton = new JButton(stepOverAction);
482:
483: Action stepOutAction = new AbstractAction("Step Out") {
484: public void actionPerformed(ActionEvent ae) {
485: _frame.debuggerStep(Debugger.StepType.STEP_OUT);
486: }
487: };
488: _stepOutButton = new JButton(stepOutAction);
489:
490: ActionListener closeListener = new ActionListener() {
491: public void actionPerformed(ActionEvent ae) {
492: _frame.debuggerToggle();
493: }
494: };
495:
496: _closeButton = new CommonCloseButton(closeListener);
497:
498: closeButtonPanel.add(_closeButton, BorderLayout.NORTH);
499: mainButtons.add(_resumeButton);
500: mainButtons.add(_stepIntoButton);
501: mainButtons.add(_stepOverButton);
502: mainButtons.add(_stepOutButton);
503: mainButtons.add(emptyPanel);
504:
505: c.fill = GridBagConstraints.HORIZONTAL;
506: c.anchor = GridBagConstraints.NORTH;
507: c.gridwidth = GridBagConstraints.REMAINDER;
508: c.weightx = 1.0;
509:
510: gbLayout.setConstraints(_resumeButton, c);
511: gbLayout.setConstraints(_stepIntoButton, c);
512: gbLayout.setConstraints(_stepOverButton, c);
513: gbLayout.setConstraints(_stepOutButton, c);
514:
515: c.fill = GridBagConstraints.BOTH;
516: c.anchor = GridBagConstraints.SOUTH;
517: c.gridheight = GridBagConstraints.REMAINDER;
518: c.weighty = 1.0;
519:
520: gbLayout.setConstraints(emptyPanel, c);
521:
522: disableButtons();
523: _buttonPanel.add(mainButtons, BorderLayout.CENTER);
524: _buttonPanel.add(closeButtonPanel, BorderLayout.EAST);
525: }
526:
527: /**
528: * Initializes the pop-up menu that is revealed when the user
529: * right-clicks on a row in the thread table or stack table.
530: */
531: private void _initPopup() {
532: // this is commented out because we do not currently support manual
533: // suspension of a running thread.
534: // _threadRunningPopupMenu = new JPopupMenu("Thread Selection");
535: // JMenuItem threadRunningSuspend = new JMenuItem();
536: // Action suspendAction = new AbstractAction("Suspend Thread") {
537: // public void actionPerformed(ActionEvent e) {
538: // try{
539: // _debugger.suspend(getSelectedThread());
540: // }
541: // catch(DebugException exception) {
542: // JOptionPane.showMessageDialog(_frame, "Cannot suspend the thread.", "Debugger Error", JOptionPane.ERROR_MESSAGE);
543: // }
544: // }
545: // };
546: // threadRunningSuspend.setAction(suspendAction);
547: // _threadRunningPopupMenu.add(threadRunningSuspend);
548: // threadRunningSuspend.setText("Suspend and Select Thread");
549:
550: Action selectAction = new AbstractAction("Select Thread") {
551: public void actionPerformed(ActionEvent e) {
552: _selectCurrentThread();
553: }
554: };
555:
556: _threadSuspendedPopupMenu = new JPopupMenu("Thread Selection");
557: _threadSuspendedPopupMenu.add(selectAction);
558: _threadSuspendedPopupMenu.add(new AbstractAction(
559: "Resume Thread") {
560: public void actionPerformed(ActionEvent e) {
561: try {
562: if (_threadInPopup.isSuspended())
563: _debugger.resume(_threadInPopup);
564: } catch (DebugException dbe) {
565: _frame._showDebugError(dbe);
566: }
567: }
568: });
569:
570: _stackPopupMenu = new JPopupMenu("Stack Selection");
571: _stackPopupMenu.add(new AbstractAction("Scroll to Source") {
572: public void actionPerformed(ActionEvent e) {
573: try {
574: _debugger.scrollToSource(getSelectedStackItem());
575: } catch (DebugException de) {
576: _frame._showDebugError(de);
577: }
578: }
579: });
580:
581: _watchPopupMenu = new JPopupMenu("Watches");
582: _watchPopupMenu.add(new AbstractAction("Remove Watch") {
583: public void actionPerformed(ActionEvent e) {
584: try {
585: _debugger.removeWatch(_watchTable.getSelectedRow());
586: _watchTable.revalidate();
587: _watchTable.repaint();
588: } catch (DebugException de) {
589: _frame._showDebugError(de);
590: }
591: }
592: });
593: _watchTable.addMouseListener(new DebugTableMouseAdapter(
594: _watchTable) {
595: protected void _showPopup(MouseEvent e) {
596: if (_watchTable.getSelectedRow() < _watchTable
597: .getRowCount() - 1) {
598: _watchPopupMenu.show(e.getComponent(), e.getX(), e
599: .getY());
600: }
601: }
602:
603: protected void _action() {
604: }
605: });
606: }
607:
608: /**
609: */
610: private void _selectCurrentThread() {
611: if (_threadInPopup.isSuspended()) {
612: try {
613: _debugger.setCurrentThread(_threadInPopup);
614: } catch (DebugException de) {
615: _frame._showDebugError(de);
616: }
617: }
618: }
619:
620: /**
621: * gets the thread that is currently selected in the thread table
622: * @return the highlighted thread
623: */
624: public DebugThreadData getSelectedThread() {
625: int row = _threadTable.getSelectedRow();
626: if (row == -1) {
627: row = 0; // if there is no selected index, just return the first element
628: }
629: return _threads.get(row);
630: }
631:
632: /** Gets the DebugStackData that is currently selected in the stack table
633: * @return the highlighted stack element
634: */
635: public DebugStackData getSelectedStackItem() {
636: return _stackFrames.get(_stackTable.getSelectedRow());
637: }
638:
639: /** @return the selected watch */
640: public DebugWatchData getSelectedWatch() {
641: return _watches.get(_watchTable.getSelectedRow());
642: }
643:
644: /** Listens to events from the debug manager to keep the panel updated. */
645: class DebugPanelListener implements DebugListener {
646: /** Called when the current thread is suspended. */
647: public void currThreadSuspended() {
648: // Only change GUI from event-dispatching thread
649: Utilities.invokeLater(new Runnable() {
650: public void run() {
651: updateData();
652: }
653: });
654: }
655:
656: /** Called when the current thread is resumed */
657: public void currThreadResumed() {
658: // Only change GUI from event-dispatching thread
659: Utilities.invokeLater(new Runnable() {
660: public void run() {
661: updateData();
662: }
663: });
664: }
665:
666: /** Called when a thread starts. Only runs in event thread. */
667: public void threadStarted() {
668: updateData();
669: }
670:
671: /** Called when the current thread dies. Only runs in event thread. */
672: public void currThreadDied() {
673: updateData();
674: }
675:
676: /** Called when any thread other than the current thread dies. Only runs in event thread. */
677: public void nonCurrThreadDied() {
678: updateData();
679: }
680:
681: /** Called when the current (selected) thread is set in the debugger.
682: * @param thread the thread that was set as current
683: */
684: public void currThreadSet(DebugThreadData thread) {
685: _currentThreadID = thread.getUniqueID();
686:
687: // Only change GUI from event-dispatching thread
688: Utilities.invokeLater(new Runnable() {
689: public void run() {
690: updateData();
691: }
692: });
693: }
694:
695: public void threadLocationUpdated(OpenDefinitionsDocument doc,
696: int lineNumber, boolean shouldHighlight) {
697: }
698:
699: public void debuggerStarted() {
700: }
701:
702: public void debuggerShutdown() {
703: }
704:
705: public void breakpointReached(final Breakpoint bp) {
706: }
707:
708: public void watchSet(final DebugWatchData w) {
709: }
710:
711: public void watchRemoved(final DebugWatchData w) {
712: }
713:
714: public void stepRequested() {
715: }
716:
717: public void regionAdded(Breakpoint r, int index) {
718: }
719:
720: public void regionChanged(Breakpoint r, int index) {
721: }
722:
723: public void regionRemoved(Breakpoint r) {
724: }
725: }
726:
727: /**
728: * Enables and disables the appropriate buttons depending on if the current
729: * thread has been suspended or resumed
730: * @param isSuspended indicates if the current thread has been suspended
731: */
732: public void setThreadDependentButtons(boolean isSuspended) {
733: _resumeButton.setEnabled(isSuspended);
734: _stepIntoButton.setEnabled(isSuspended);
735: _stepOverButton.setEnabled(isSuspended);
736: _stepOutButton.setEnabled(isSuspended);
737: }
738:
739: public void disableButtons() {
740: setThreadDependentButtons(false);
741: }
742:
743: public void setStatusText(String text) {
744: _statusBar.setText(text);
745: }
746:
747: public String getStatusText() {
748: return _statusBar.getText();
749: }
750:
751: /**
752: * Updates the UI to a new look and feel.
753: * Need to update the contained popup menus as well.
754: *
755: * Currently, we don't support changing the look and feel
756: * on the fly, so this is disabled.
757: *
758: public void updateUI() {
759: super.updateUI();
760: if (_threadSuspendedPopupMenu != null) {
761: SwingUtilities.updateComponentTreeUI(_threadSuspendedPopupMenu);
762: }
763: if (_stackPopupMenu != null) {
764: SwingUtilities.updateComponentTreeUI(_stackPopupMenu);
765: }
766: if (_watchPopupMenu != null) {
767: SwingUtilities.updateComponentTreeUI(_watchPopupMenu);
768: }
769: }*/
770:
771: /**
772: * Concrete DebugTableMouseAdapter for the thread table.
773: */
774: private class ThreadMouseAdapter extends DebugTableMouseAdapter {
775: public ThreadMouseAdapter() {
776: super (_threadTable);
777: }
778:
779: protected void _showPopup(MouseEvent e) {
780: _threadInPopup = _threads.get(_lastRow);
781: if (_threadInPopup.isSuspended()) {
782: _threadSuspendedPopupMenu.show(e.getComponent(), e
783: .getX(), e.getY());
784: }
785: // else {
786: // _threadRunningPopupMenu.show(e.getComponent(), e.getX(), e.getY());
787: // }
788: }
789:
790: protected void _action() {
791: _threadInPopup = _threads.get(_lastRow);
792: _selectCurrentThread();
793: }
794: }
795:
796: /**
797: * Concrete DebugTableMouseAdapter for the stack table.
798: */
799: private class StackMouseAdapter extends DebugTableMouseAdapter {
800: public StackMouseAdapter() {
801: super (_stackTable);
802: }
803:
804: protected void _showPopup(MouseEvent e) {
805: _stackPopupMenu.show(e.getComponent(), e.getX(), e.getY());
806: }
807:
808: protected void _action() {
809: try {
810: _debugger.scrollToSource(_stackFrames.get(_lastRow));
811: } catch (DebugException de) {
812: _frame._showDebugError(de);
813: }
814: }
815: }
816:
817: /**
818: * A mouse adapter that allows for double-clicking and
819: * bringing up a right-click menu.
820: */
821: private abstract class DebugTableMouseAdapter extends
822: RightClickMouseAdapter {
823: protected JTable _table;
824: protected int _lastRow;
825:
826: public DebugTableMouseAdapter(JTable table) {
827: _table = table;
828: _lastRow = -1;
829: }
830:
831: protected abstract void _showPopup(MouseEvent e);
832:
833: protected abstract void _action();
834:
835: protected void _popupAction(MouseEvent e) {
836: _lastRow = _table.rowAtPoint(e.getPoint());
837: _table.setRowSelectionInterval(_lastRow, _lastRow);
838: _showPopup(e);
839: }
840:
841: public void mousePressed(MouseEvent e) {
842: super .mousePressed(e);
843:
844: if (SwingUtilities.isLeftMouseButton(e)
845: && e.getClickCount() == 2) {
846: _lastRow = _table.rowAtPoint(e.getPoint());
847: _action();
848: }
849: }
850: }
851:
852: private class BPTree extends JTree {
853: public BPTree(DefaultTreeModel s) {
854: super (s);
855: }
856:
857: public void setForeground(Color c) {
858: super .setForeground(c);
859: if (dtcr != null)
860: dtcr.setTextNonSelectionColor(c);
861: }
862:
863: public void setBackground(Color c) {
864: super.setBackground(c);
865: if (DebugPanel.this != null && dtcr != null)
866: dtcr.setBackgroundNonSelectionColor(c);
867: }
868: }
869: }
|