001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.debugger.importd;
043:
044: import java.util.*;
045: import javax.swing.text.StyledDocument;
046:
047: import org.openide.cookies.EditorCookie;
048: import org.openide.debugger.*;
049: import org.openide.text.Line;
050: import org.openide.text.NbDocument;
051: import org.openide.util.MapFormat;
052: import org.openide.util.NbBundle;
053:
054: import org.netbeans.modules.debugger.*;
055: import org.netbeans.modules.debugger.support.DebuggerAnnotation;
056: import org.netbeans.modules.debugger.support.SecondaryDebuggerSupport;
057: import org.netbeans.modules.debugger.support.StateSupport;
058: import org.netbeans.modules.debugger.support.util.Utils;
059: import org.netbeans.modules.debugger.support.util.ValidatorImpl;
060:
061: /**
062: * Example of Debugger Implementation. It "debugs" import statements
063: * in Java files (so it does not need compiled .class files). Step
064: * Into on "import java.awt.Button" opens .java file for Button and
065: * puts current line to the first line of it.
066: *
067: * @author Jan Jancura
068: */
069: public class ImportDebugger extends SecondaryDebuggerSupport {
070:
071: // static ..................................................................
072:
073: /** generated Serialized Version UID */
074: static final long serialVersionUID = 84466455228078708L;
075: /** bundle to obtain text information from */
076: private static ResourceBundle bundle;
077:
078: static String getLocString(String s) {
079: if (bundle == null)
080: bundle = NbBundle.getBundle(ImportDebugger.class);
081: return bundle.getString(s);
082: }
083:
084: /** debugger State constant. */
085: public static final State STATE_STOPPED = new StateSupport(
086: StateSupport.PAUSE | StateSupport.STEP_OVER
087: | StateSupport.STEP_INTO | StateSupport.STEP_OUT);
088: /** debugger State constant. */
089: public static final State STATE_RUNNING = new StateSupport(
090: StateSupport.PAUSE);
091:
092: static DebuggerAnnotation.CurrentPC currentLineAnnotation = new DebuggerAnnotation.CurrentPC();
093:
094: // variables ...............................................................
095:
096: transient private ValidatorImpl validator;
097:
098: // init ....................................................................
099:
100: public ImportDebugger() {
101: validator = new ValidatorImpl();
102: }
103:
104: // Debugger implementation .................................................
105:
106: /** Starts the debugger. The method stops the current debugging (if any)
107: * and takes information from the provided info (containing the class to start and
108: * arguments to pass it and name of class to stop debugging in) and starts
109: * new debugging session.
110: *
111: * @param info debugger info about class to start
112: * @exception DebuggerException if an error occures during the start of the debugger
113: */
114: public void startDebugger(DebuggerInfo info)
115: throws DebuggerException {
116: boolean stopOnMain = info.getStopClassName() != null;
117:
118: super .startDebugger(info);
119: setState(Debugger.DEBUGGER_RUNNING);
120: String stopClassName = info.getClassName();
121: Line l = Utils.getLine(stopClassName, 1);
122: stack = new Stack();
123: stack.push(l);
124: isOnStack = new HashSet();
125: isOnStack.add(l.getDataObject());
126:
127: // stop on main
128: if (stopOnMain) {
129: setState(DEBUGGER_STOPPED);
130: setCurrentLine(l);
131: refreshWatches();
132: } else
133: go();
134: }
135:
136: /**
137: * Finishes debugger.
138: */
139: public void finishDebugger() throws DebuggerException {
140: super .finishDebugger();
141: }
142:
143: /**
144: * Trace into.
145: */
146: synchronized public void traceInto() throws DebuggerException {
147: setState(DEBUGGER_RUNNING);
148: Line l = step();
149: if (l == null) {
150: finishDebugger();
151: refreshWatches();
152: return;
153: }
154: setCurrentLine(l);
155: setState(DEBUGGER_STOPPED);
156: setLastAction(ACTION_TRACE_INTO);
157: refreshWatches();
158: }
159:
160: /**
161: * Trace over.
162: */
163: synchronized public void traceOver() throws DebuggerException {
164: setState(DEBUGGER_RUNNING);
165: int d = stack.size();
166: Line l = null;
167: do {
168: l = step();
169: if (l == null) {
170: finishDebugger();
171: refreshWatches();
172: return;
173: }
174: } while (stack.size() > d);
175: setCurrentLine(l);
176: setState(DEBUGGER_STOPPED);
177: setLastAction(ACTION_TRACE_OVER);
178: refreshWatches();
179: }
180:
181: /**
182: * Go.
183: */
184: synchronized public void go() throws DebuggerException {
185: setLastAction(ACTION_CONTINUE);
186: setState(DEBUGGER_RUNNING);
187:
188: Line l = null;
189: do {
190: l = step();
191: } while (l != null);
192: finishDebugger();
193: refreshWatches();
194: }
195:
196: /**
197: * Step out.
198: */
199: synchronized public void stepOut() throws DebuggerException {
200: setLastAction(ACTION_STEP_OUT);
201: setState(DEBUGGER_RUNNING);
202:
203: int d = stack.size() - 1;
204: Line l = null;
205: do {
206: l = step();
207: if (l == null) {
208: finishDebugger();
209: refreshWatches();
210: return;
211: }
212: } while (stack.size() > d);
213: setCurrentLine(l);
214: setState(DEBUGGER_STOPPED);
215: setLastAction(ACTION_TRACE_INTO);
216: refreshWatches();
217: }
218:
219: /**
220: * Jumps to the next call site (towards the top of the call-stack).
221: */
222: public void goToCalledMethod() {
223: }
224:
225: /**
226: * Jumps to the previous call site (towards the bottom of the call-stack).
227: */
228: public void goToCallingMethod() {
229: }
230:
231: /**
232: * Jumps to a given line.
233: *
234: * @param l a line jump to
235: */
236: public void runToCursor(Line l) {
237: }
238:
239: /**
240: * Pauses debugging.
241: */
242: public void pause() {
243: }
244:
245: public void setCurrentLine(Line l) {
246: Line old = getCurrentLine();
247: if (old != null) {
248: // old.unmarkCurrentLine ();
249: currentLineAnnotation.detachLine();
250: }
251: if (l != null) {
252: Utils.showInEditor(l);
253: //l.markCurrentLine ();
254: currentLineAnnotation.attachLine(l);
255: }
256: super .setCurrentLine(l);
257: }
258:
259: protected void setState(int state) {
260: super .setState(state);
261: switch (state) {
262: case DEBUGGER_NOT_RUNNING:
263: setDebuggerState(STATE_NOT_RUNNING);
264: break;
265: case DEBUGGER_RUNNING:
266: setDebuggerState(STATE_RUNNING);
267: break;
268: case DEBUGGER_STOPPED:
269: setDebuggerState(STATE_STOPPED);
270: break;
271: }
272: }
273:
274: /** Creates new uninitialized watch. The watch is visible (not hidden).
275: *
276: * @return new uninitialized watch
277: */
278: public Watch createWatch() {
279: ImportWatch w = new ImportWatch(this , false);
280: addWatch(w);
281: return w;
282: }
283:
284: /** Creates a watch its expression is set to initial value. Also
285: * allows to create a watch not presented to the user, for example
286: * for internal usage in the editor to obtain values of variables
287: * under the mouse pointer.
288: *
289: * @param expr expresion to watch for
290: * @param hidden allows to specify whether the watch should be presented
291: * to the user or not (be only of internal usage of the IDE).
292: * @return new watch
293: */
294: public Watch createWatch(String expr, boolean hidden) {
295: ImportWatch w = new ImportWatch(this , hidden);
296: w.setVariableName(expr);
297: addWatch(w);
298: return w;
299: }
300:
301: // inner debugger implementation ...........................................
302:
303: Validator getValidator() {
304: return validator;
305: }
306:
307: void refreshWatches() {
308: validator.validate();
309: }
310:
311: // inner debugger implementation ...........................................
312:
313: private Stack stack = new Stack();
314: private HashSet isOnStack = new HashSet();
315: HashMap lineBreakpoints = new HashMap();
316:
317: Stack getStack() {
318: return stack;
319: }
320:
321: Line step() {
322: Line l = (Line) stack.lastElement();
323: try {
324: // Trace into
325: String str = getText(l);
326: if (str.startsWith("import ")) {
327: str = str.substring(7, str.length() - 1); //.replace ('.', File.separatorChar);
328: Line ll = Utils.getLine(str, 1);
329: if (ll != null)
330: if (!isOnStack.contains(ll.getDataObject())) {
331: stack.push(ll);
332: isOnStack.add(ll.getDataObject());
333: return ll;
334: }
335: }
336: } catch (Exception e) {
337: }
338:
339: stack.pop();
340:
341: // trace over
342: try {
343: if (l.getLineNumber() < 50) {
344: Line ll = Utils.getLine(l.getDataObject()
345: .getPrimaryFile().getPackageName('.'), l
346: .getLineNumber() + 2);
347: if (ll != null) {
348: stack.push(ll);
349: return ll;
350: }
351: }
352: } catch (Exception e) {
353: }
354:
355: // Step out
356: if (stack.empty())
357: return null;
358: Line ll = (Line) stack.pop();
359: if (ll.getLineNumber() < 50)
360: try {
361: ll = Utils.getLine(ll.getDataObject().getPrimaryFile()
362: .getPackageName('.'), ll.getLineNumber() + 2);
363: } catch (Exception e) {
364: }
365: stack.push(ll);
366: return ll;
367: }
368:
369: static String getText(Line l) throws Exception {
370: EditorCookie ec = (EditorCookie) l.getDataObject().getCookie(
371: EditorCookie.class);
372: StyledDocument doc = ec.openDocument();
373: if (doc == null)
374: return "";
375: int off = NbDocument.findLineOffset(doc, l.getLineNumber());
376: int len = NbDocument.findLineOffset(doc, l.getLineNumber() + 1)
377: - off - 1;
378: return doc.getText(off, len);
379: }
380: }
|