1 19 20 package org.netbeans.modules.debugger.jpda.models; 21 22 import com.sun.jdi.AbsentInformationException; 23 import com.sun.jdi.IncompatibleThreadStateException; 24 import java.beans.PropertyChangeEvent ; 25 import java.beans.PropertyChangeListener ; 26 import java.lang.ref.WeakReference ; 27 import java.util.Collection ; 28 import java.util.HashSet ; 29 30 import org.netbeans.api.debugger.jpda.CallStackFrame; 31 import org.netbeans.api.debugger.jpda.JPDAThread; 32 import org.netbeans.spi.debugger.ContextProvider; 33 import org.netbeans.api.debugger.jpda.JPDADebugger; 34 import org.netbeans.spi.viewmodel.ModelEvent; 35 import org.netbeans.spi.viewmodel.TreeModel; 36 import org.netbeans.spi.viewmodel.ModelListener; 37 import org.netbeans.spi.viewmodel.UnknownTypeException; 38 39 import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl; 40 import org.openide.util.RequestProcessor; 41 import org.openide.util.WeakListeners; 42 43 44 49 public class CallStackTreeModel implements TreeModel { 50 51 private static boolean verbose = 52 (System.getProperty ("netbeans.debugger.viewrefresh") != null) && 53 (System.getProperty ("netbeans.debugger.viewrefresh").indexOf ('c') >= 0); 54 55 private JPDADebuggerImpl debugger; 56 private Collection <ModelListener> listeners = new HashSet <ModelListener>(); 57 private Listener listener; 58 59 60 public CallStackTreeModel (ContextProvider lookupProvider) { 61 debugger = (JPDADebuggerImpl) lookupProvider. 62 lookupFirst (null, JPDADebugger.class); 63 } 64 65 69 public Object [] getChildren (Object parent, int from, int to) 70 throws UnknownTypeException { 71 if ( parent.equals (ROOT) || 72 (parent instanceof JPDAThread) 73 ) { 74 JPDAThread thread; 76 if (parent.equals (ROOT)) { 77 thread = debugger.getCurrentThread (); 78 } else { 79 thread = (JPDAThread) parent; 80 } 81 if (thread == null) { 82 return new String [] {"No current thread"}; } 84 85 try { 87 CallStackFrame[] sfs = thread.getCallStack(from, to); 88 return sfs; 89 } catch (AbsentInformationException aiex) { 90 if (aiex.getCause() instanceof IncompatibleThreadStateException) { 91 return new String [] {"Thread is running"}; } else { 93 return new String [] {"No call stack information available."}; } 95 } 96 } else 97 throw new UnknownTypeException (parent); 98 } 99 100 109 public int getChildrenCount (Object parent) throws UnknownTypeException { 110 if ( parent.equals (ROOT) || 111 (parent instanceof JPDAThread) 112 ) { 113 return Integer.MAX_VALUE; 115 129 } else 130 throw new UnknownTypeException (parent); 131 } 132 133 137 public Object getRoot () { 138 return ROOT; 139 } 140 141 public boolean isLeaf (Object node) throws UnknownTypeException { 142 if (node.equals (ROOT)) return false; 143 if (node instanceof CallStackFrame) return true; 144 throw new UnknownTypeException (node); 145 } 146 147 151 public void addModelListener (ModelListener l) { 152 synchronized (listeners) { 153 listeners.add (l); 154 if (listener == null) { 155 listener = new Listener (this, debugger); 156 } 157 } 158 } 159 160 164 public void removeModelListener (ModelListener l) { 165 synchronized (listeners) { 166 listeners.remove (l); 167 if (listeners.size () == 0) { 168 listener.destroy (); 169 listener = null; 170 } 171 } 172 } 173 174 public void fireTreeChanged () { 175 ModelListener[] ls; 176 synchronized (listeners) { 177 ls = listeners.toArray(new ModelListener[0]); 178 } 179 ModelEvent ev = new ModelEvent.TreeChanged(this); 180 for (int i = 0; i < ls.length; i++) { 181 ls[i].modelChanged (ev); 182 } 183 } 184 185 186 189 private static class Listener implements PropertyChangeListener { 190 191 private JPDADebugger debugger; 192 private WeakReference <CallStackTreeModel> model; 193 194 public Listener ( 195 CallStackTreeModel tm, 196 JPDADebugger debugger 197 ) { 198 this.debugger = debugger; 199 model = new WeakReference <CallStackTreeModel>(tm); 200 debugger.addPropertyChangeListener (this); 201 JPDAThreadImpl lastCurrentThread = (JPDAThreadImpl) debugger.getCurrentThread(); 202 if (lastCurrentThread != null) { 203 lastCurrentThread.addPropertyChangeListener( 204 WeakListeners.propertyChange(this, lastCurrentThread)); 205 } 206 } 207 208 private CallStackTreeModel getModel () { 209 CallStackTreeModel tm = model.get (); 210 if (tm == null) { 211 destroy (); 212 } 213 return tm; 214 } 215 216 void destroy () { 217 debugger.removePropertyChangeListener (this); 218 if (task != null) { 219 task.cancel (); 221 if (verbose) 222 System.out.println("CSTM cancel old task " + task); 223 task = null; 224 } 225 } 226 227 private RequestProcessor.Task task; 230 231 public synchronized void propertyChange (PropertyChangeEvent e) { 234 boolean refresh = false; 235 String propertyName = e.getPropertyName(); 236 if (propertyName == debugger.PROP_CURRENT_THREAD) { 237 JPDAThreadImpl lastCurrentThread = (JPDAThreadImpl) debugger.getCurrentThread(); 238 if (lastCurrentThread != null) { 239 lastCurrentThread.addPropertyChangeListener( 240 WeakListeners.propertyChange(this, lastCurrentThread)); 241 refresh = true; 242 } 243 } 244 if (propertyName == JPDAThreadImpl.PROP_SUSPENDED 245 && Boolean.TRUE.equals(e.getNewValue())) { 246 if (e.getSource() == debugger.getCurrentThread()) { 247 refresh = true; 248 } 249 } 250 if ((propertyName == debugger.PROP_STATE) 251 && (debugger.getState() == debugger.STATE_STOPPED) 252 ) { 253 refresh = true; 254 } 255 if (refresh) { 256 synchronized (this) { 257 if (task == null) { 258 task = RequestProcessor.getDefault().create(new Refresher()); 259 } 260 task.schedule(200); 261 } 262 } 263 } 264 265 private class Refresher extends Object implements Runnable { 266 public void run() { 267 if (debugger.getState () == debugger.STATE_STOPPED) { 268 CallStackTreeModel tm = getModel (); 269 if (tm != null) { 270 tm.fireTreeChanged(); 271 } 272 } 273 } 274 } 275 } 276 } 277 278 | Popular Tags |