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: import java.util.ArrayList;
041: import java.util.Enumeration;
042: import java.io.File;
043:
044: import javax.swing.*;
045: import javax.swing.event.*;
046: import javax.swing.tree.*;
047: import javax.swing.table.*;
048: import javax.swing.text.BadLocationException;
049: import java.awt.event.*;
050: import java.awt.*;
051: import javax.swing.text.BadLocationException;
052: import javax.swing.text.Position;
053:
054: import edu.rice.cs.util.Lambda;
055: import edu.rice.cs.drjava.model.RegionManagerListener;
056: import edu.rice.cs.drjava.model.DocumentRegion;
057: import edu.rice.cs.drjava.model.debug.*;
058: import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
059: import edu.rice.cs.drjava.config.*;
060: import edu.rice.cs.drjava.model.definitions.ClassNameNotFoundException;
061: import edu.rice.cs.util.swing.Utilities;
062: import edu.rice.cs.util.UnexpectedException;
063:
064: /**
065: * Panel for displaying the breakpoints. This class is a swing view class and hence should only be accessed from the
066: * event-handling thread.
067: * @version $Id$
068: */
069: public class BreakpointsPanel extends RegionsTreePanel<Breakpoint> {
070: protected JButton _goToButton;
071: protected JButton _enableDisableButton;
072: protected JButton _removeButton;
073: protected JButton _removeAllButton;
074: protected final Debugger _debugger;
075:
076: /** Constructs a new breakpoints panel.
077: * This is swing view class and hence should only be accessed from the event-handling thread.
078: * @param frame the MainFrame
079: */
080: public BreakpointsPanel(MainFrame frame) {
081: super (frame, "Breakpoints");
082: _model.getBreakpointManager().addListener(
083: new RegionManagerListener<Breakpoint>() {
084: /** Called when a breakpoint is set in a document. Adds the breakpoint to the tree of breakpoints.
085: * Must be executed in event thread.
086: * @param bp the breakpoint
087: */
088: public void regionAdded(final Breakpoint bp,
089: int index) {
090: assert EventQueue.isDispatchThread();
091: addRegion(bp);
092: }
093:
094: /**
095: * Called when a breakpoint is changed.
096: * Removes the breakpoint from the tree of breakpoints.
097: * @param bp the breakpoint
098: * @param index the index of the breakpoint
099: */
100: public void regionChanged(final Breakpoint bp,
101: int index) {
102: // Only change GUI from event-dispatching thread
103: Runnable doCommand = new Runnable() {
104: public void run() {
105: File file = bp.getDocument()
106: .getRawFile();
107:
108: DefaultMutableTreeNode regDocNode = new DefaultMutableTreeNode(
109: file);
110:
111: // Find the document node for this region
112: Enumeration documents = _regionRootNode
113: .children();
114: boolean found = false;
115: while ((!found)
116: && (documents.hasMoreElements())) {
117: DefaultMutableTreeNode doc = (DefaultMutableTreeNode) documents
118: .nextElement();
119: if (doc.getUserObject().equals(
120: regDocNode.getUserObject())) {
121: // Find the correct line start offset node for this breakpoint
122: Enumeration existingRegions = doc
123: .children();
124: while (existingRegions
125: .hasMoreElements()) {
126: DefaultMutableTreeNode existing = (DefaultMutableTreeNode) existingRegions
127: .nextElement();
128: @SuppressWarnings("unchecked")
129: RegionTreeUserObj<Breakpoint> uo = (RegionTreeUserObj<Breakpoint>) existing
130: .getUserObject();
131: if (uo.region()
132: .getStartOffset() == bp
133: .getStartOffset()) {
134: Breakpoint r = uo
135: .region();
136: r.setEnabled(bp
137: .isEnabled());
138: ((DefaultTreeModel) _regTree
139: .getModel())
140: .nodeChanged(existing);
141: found = true;
142: break;
143: }
144: }
145: }
146: }
147: updateButtons();
148: }
149: };
150: Utilities.invokeLater(doCommand);
151: }
152:
153: /**
154: * Called when a breakpoint is removed from a document.
155: * Removes the breakpoint from the tree of breakpoints.
156: * @param bp the breakpoint
157: */
158: public void regionRemoved(final Breakpoint bp) {
159: removeRegion(bp);
160: }
161: });
162: _debugger = _model.getDebugger();
163: }
164:
165: /** Action performed when the Enter key is pressed. Should be overridden. */
166: protected void performDefaultAction() {
167: goToRegion();
168: }
169:
170: /** Creates the buttons for controlling the regions. Should be overridden. */
171: protected JComponent[] makeButtons() {
172: Action goToAction = new AbstractAction("Go to") {
173: public void actionPerformed(ActionEvent ae) {
174: goToRegion();
175: }
176: };
177: _goToButton = new JButton(goToAction);
178:
179: Action enableDisableAction = new AbstractAction("Disable") {
180: public void actionPerformed(ActionEvent ae) {
181: enableDisableBreakpoint();
182: }
183: };
184: _enableDisableButton = new JButton(enableDisableAction);
185:
186: Action removeAction = new AbstractAction("Remove") {
187: public void actionPerformed(ActionEvent ae) {
188: for (Breakpoint bp : getSelectedRegions()) {
189: _model.getBreakpointManager().removeRegion(bp);
190: }
191: }
192: };
193: _removeButton = new JButton(removeAction);
194:
195: Action removeAllAction = new AbstractAction("Remove All") {
196: public void actionPerformed(ActionEvent ae) {
197: _model.getBreakpointManager().clearRegions();
198: }
199: };
200: _removeAllButton = new JButton(removeAllAction);
201:
202: JComponent[] buts = new JComponent[] { _enableDisableButton,
203: _goToButton, _removeButton, _removeAllButton };
204:
205: return buts;
206: }
207:
208: /** Update button state and text. */
209: protected void updateButtons() {
210: ArrayList<Breakpoint> regs = getSelectedRegions();
211: _goToButton.setEnabled(regs.size() == 1);
212: _removeButton.setEnabled(regs.size() > 0);
213: _removeAllButton.setEnabled(_regionRootNode != null
214: && _regionRootNode.getDepth() > 0);
215: _enableDisableButton.setEnabled(regs.size() > 0);
216: if (regs.size() > 0) {
217: if (regs.get(0).isEnabled())
218: _enableDisableButton.setText("Disable");
219: else
220: _enableDisableButton.setText("Enable");
221: }
222: _removeAllButton.setEnabled(_regionRootNode != null
223: && _regionRootNode.getDepth() > 0);
224: }
225:
226: /** Makes the popup menu actions. Should be overridden if additional actions besides "Go to" and "Remove" are added. */
227: protected AbstractAction[] makePopupMenuActions() {
228: AbstractAction[] acts = new AbstractAction[] {
229: new AbstractAction("Go to") {
230: public void actionPerformed(ActionEvent e) {
231: goToRegion();
232: }
233: },
234:
235: new AbstractAction("Remove") {
236: public void actionPerformed(ActionEvent e) {
237: for (Breakpoint bp : getSelectedRegions())
238: _model.getBreakpointManager().removeRegion(
239: bp);
240: }
241: } };
242: return acts;
243: }
244:
245: /** Go to region. */
246: protected void goToRegion() {
247: ArrayList<Breakpoint> bps = getSelectedRegions();
248: if (bps.size() == 1) {
249: _debugger.scrollToSource(bps.get(0));
250: }
251: }
252:
253: /** Toggle breakpoint's enable/disable flag. */
254: protected void enableDisableBreakpoint() {
255: final ArrayList<Breakpoint> bps = getSelectedRegions();
256: if (bps.size() > 0) {
257: final boolean newState = !bps.get(0).isEnabled();
258: for (Breakpoint bp : bps) {
259: _model.getBreakpointManager().changeRegion(bp,
260: new Lambda<Object, Breakpoint>() {
261: public Object apply(Breakpoint bp) {
262: bp.setEnabled(newState);
263: return null;
264: }
265: });
266: }
267: }
268: }
269:
270: /** Factory method to create user objects put in the tree.
271: * If subclasses extend RegionTreeUserObj, they need to override this method. */
272: protected RegionTreeUserObj<Breakpoint> makeRegionTreeUserObj(
273: Breakpoint bp) {
274: return new BreakpointRegionTreeUserObj(bp);
275: }
276:
277: /** Class that gets put into the tree. The toString() method determines what's displayed in the three. */
278: protected static class BreakpointRegionTreeUserObj extends
279: RegionTreeUserObj<Breakpoint> {
280: public BreakpointRegionTreeUserObj(Breakpoint bp) {
281: super (bp);
282: }
283:
284: public String toString() {
285: final StringBuilder sb = new StringBuilder();
286: _region.getDocument().acquireReadLock();
287: try {
288: sb.append(lineNumber());
289: try {
290: if (!_region.isEnabled()) {
291: sb.append(" (disabled)");
292: }
293: sb.append(": ");
294: int length = Math.min(120, _region.getEndOffset()
295: - _region.getStartOffset());
296: sb.append(_region.getDocument().getText(
297: _region.getStartOffset(), length).trim());
298: } catch (BadLocationException bpe) { /* ignore, just don't display line */
299: }
300: } finally {
301: _region.getDocument().releaseReadLock();
302: }
303: return sb.toString();
304: }
305:
306: public boolean equals(Object other) {
307: BreakpointRegionTreeUserObj o = (BreakpointRegionTreeUserObj) other;
308: return (o.region().getDocument().equals(region()
309: .getDocument()))
310: && (o.region().getStartOffset() == region()
311: .getStartOffset())
312: && (o.region().getEndOffset() == region()
313: .getEndOffset())
314: && (o.region().isEnabled() == region().isEnabled());
315: }
316: }
317: }
|