1 19 20 package org.netbeans.modules.scripting.php.dbginterface.models; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.beans.PropertyChangeSupport ; 25 import java.lang.ref.WeakReference ; 26 import java.util.*; 27 import javax.security.auth.RefreshFailedException ; 28 import javax.security.auth.Refreshable ; 29 import javax.swing.JToolTip ; 30 import org.netbeans.api.debugger.Watch; 31 import org.netbeans.api.debugger.DebuggerManager; 32 import org.netbeans.api.debugger.DebuggerManagerAdapter; 33 import org.netbeans.modules.scripting.php.dbginterface.DbgDebuggerImpl; 34 import org.netbeans.modules.scripting.php.dbginterface.api.VariableNode; 35 import org.netbeans.spi.debugger.ContextProvider; 36 import org.netbeans.spi.debugger.ui.Constants; 37 import org.netbeans.spi.viewmodel.ModelEvent; 38 import org.netbeans.spi.viewmodel.TreeModel; 39 import org.netbeans.spi.viewmodel.ModelListener; 40 import org.netbeans.spi.viewmodel.NodeModel; 41 import org.netbeans.spi.viewmodel.TableModel; 42 import org.netbeans.spi.viewmodel.UnknownTypeException; 43 import org.openide.util.RequestProcessor; 44 45 46 50 public class WatchesModel implements TreeModel, NodeModel, TableModel { 51 private DbgDebuggerImpl debugger; 52 private Listener listener; 53 private Vector<ModelListener> listeners = new Vector<ModelListener>(); 54 private ContextProvider lookupProvider; 55 private DebugFrame currentFrame; 56 57 private Map<Watch, ScriptWatchEvaluating> watchToValue = 59 new WeakHashMap<Watch, ScriptWatchEvaluating>(); 60 61 public WatchesModel(ContextProvider lookupProvider) { 62 this.debugger = (DbgDebuggerImpl)lookupProvider.lookupFirst(null, DbgDebuggerImpl.class); 63 this.lookupProvider = lookupProvider; 64 } 65 66 74 public Object getRoot() { 75 return ROOT; 76 } 77 78 82 public Object [] getChildren(Object parent, int from, int to) throws UnknownTypeException { 83 if(parent == ROOT) { 84 Watch [] ws = DebuggerManager.getDebuggerManager().getWatches(); 86 to = Math.min(ws.length, to); 87 from = Math.min(ws.length, from); 88 Watch [] fws = new Watch [to - from]; 89 System.arraycopy(ws, from, fws, 0, to - from); 90 91 int i, k = fws.length; 93 ScriptWatchEvaluating[] jws = new ScriptWatchEvaluating[k]; 94 for(i = 0; i < k; i++) { 95 ScriptWatchEvaluating jw = watchToValue.get(fws[i]); 96 if(jw == null) { 97 jw = new ScriptWatchEvaluating(this, fws[i], debugger); 98 watchToValue.put(fws[i], jw); 99 } 100 jws[i] = jw; 101 102 } 104 105 if(listener == null) { 106 listener = new Listener (this, debugger); 107 } 108 return jws; 109 } 110 else if(parent instanceof VariableNode) { 111 return getLocalsTreeModel().getChildren(parent, from, to); 112 } 113 return getLocalsTreeModel().getChildren(parent, from, to); 114 } 115 116 125 public int getChildrenCount(Object node) throws UnknownTypeException { 126 if(node == ROOT) { 127 if(listener == null) { 128 listener = new Listener (this, debugger); 129 } 130 return Integer.MAX_VALUE; } 133 else if(node instanceof VariableNode) { 134 return getLocalsTreeModel().getChildrenCount(node); 135 } 136 137 return getLocalsTreeModel().getChildrenCount(node); 138 } 139 140 public boolean isLeaf(Object node) throws UnknownTypeException { 141 if(node == ROOT) { 142 return false; 143 } 144 else if(node instanceof VariableNode) { 145 return ((VariableNode) node).isLeaf(); 146 } 147 148 return getLocalsTreeModel().isLeaf(node); 149 } 150 151 public Object getValueAt(Object node, String columnID) throws UnknownTypeException { 155 if(Constants.WATCH_TYPE_COLUMN_ID.equals(columnID)) { 156 if(node instanceof VariableNode) { 157 String className = ((VariableNode)node).getTypeName(); 158 return (className == null) ? "" : className; 159 } 160 else if(node instanceof JToolTip ) { 161 Object row = ((JToolTip )node).getClientProperty("getShortDescription"); 163 164 if(row instanceof VariableNode) { 165 if(row instanceof Refreshable && !((Refreshable ) row).isCurrent()) { 166 return ""; 167 } 168 return ((VariableNode)row).getTypeName(); 169 } 170 } 171 } 172 else if(Constants.WATCH_VALUE_COLUMN_ID.equals(columnID)) { 173 if(node instanceof VariableNode) { 174 Object value = ((VariableNode)node).getValue(); 175 return value == null ? "null" : value; 176 } 177 } 178 179 throw new UnknownTypeException(node); 180 } 181 182 public boolean isReadOnly(Object node, String string) throws UnknownTypeException { 183 return true; 184 } 185 186 public void setValueAt(Object node, String string, Object value) throws UnknownTypeException { 187 throw new UnknownTypeException(node); 188 } 189 190 public String getDisplayName(Object node) throws UnknownTypeException { 194 if (node == null) { 195 return "null"; 196 } 197 else if (node == ROOT) { 198 return ROOT; 199 } 200 else if (node instanceof VariableNode) { 201 return ((VariableNode)node).getDisplayName(); 202 } 203 204 throw new UnknownTypeException(node); 205 } 206 207 public String getIconBase(Object node) throws UnknownTypeException { 208 if (node == null || node == ROOT) { 209 return VariableNode.LOCAL_VARIABLE_ICON; 210 } 211 else if (node instanceof VariableNode) { 212 return ((VariableNode)node).getIconBase(); 213 } 214 215 throw new UnknownTypeException(node); 216 } 217 218 public String getShortDescription(Object node) throws UnknownTypeException { 219 if (node == null || node == ROOT) { 220 return null; 221 } 222 else if (node instanceof VariableNode) { 223 return ((VariableNode)node).getShortDescription(); 224 } 225 226 throw new UnknownTypeException(node); 227 } 228 229 230 public void addModelListener(ModelListener l) { 231 listeners.add(l); 232 } 233 234 public void removeModelListener(ModelListener l) { 235 listeners.remove(l); 236 } 237 238 private void fireTreeChanged() { 239 synchronized(watchToValue) { 240 for (ScriptWatchEvaluating swe : watchToValue.values()) { 241 swe.setEvaluated(null); 242 } 243 } 244 245 fireModelChanged(new ModelEvent.TreeChanged(this)); 246 } 247 248 private void fireWatchesChanged() { 249 fireModelChanged(new ModelEvent.NodeChanged(this, ROOT, ModelEvent.NodeChanged.CHILDREN_MASK)); 250 } 251 252 void fireTableValueChangedChanged(Object node, String propertyName) { 253 ((ScriptWatchEvaluating) node).setEvaluated(null); 254 fireTableValueChangedComputed(node, propertyName); 255 } 256 257 void fireTableValueChangedComputed(Object node, String propertyName) { 258 fireModelChanged(new ModelEvent.TableValueChanged(this, node, propertyName)); 259 260 } 261 262 private void fireModelChanged(ModelEvent event) { 263 Vector<ModelListener> v = new Vector<ModelListener>(); 264 265 synchronized (listeners) { 266 v = new Vector<ModelListener>(listeners); 267 } 268 269 for (ModelListener ml : v) { 270 ml.modelChanged(event); 271 } 272 } 273 274 276 DbgDebuggerImpl getDebugger() { 277 return debugger; 278 } 279 280 private volatile VariablesModel localsModel; 281 282 private VariablesModel getLocalsTreeModel() { 283 if(localsModel == null) { 284 localsModel = debugger != null ? debugger.getVariablesModel() : null; 285 } 286 return localsModel; 287 } 288 289 292 public DebugFrame getCurrentFrame() { 293 return currentFrame; 294 } 295 296 300 public void setStackFrame(DebugFrame frame) { 301 currentFrame = frame; 302 fireTreeChanged(); 303 } 304 305 306 308 static class ScriptWatchEvaluating 309 implements VariableNode, Refreshable , PropertyChangeListener { 310 311 private WatchesModel model; 312 private Watch w; 313 private DbgDebuggerImpl debugger; 314 private VariableNode evaluatedWatch; 315 316 private boolean [] evaluating = new boolean [] { false }; 317 private PropertyChangeSupport propSupp = new PropertyChangeSupport (this); 318 319 public ScriptWatchEvaluating(WatchesModel model, Watch w, DbgDebuggerImpl debugger) { 320 this.model = model; 321 this.w = w; 322 this.debugger = debugger; 323 324 parseExpression(w.getExpression()); 325 } 326 327 private void parseExpression(String exprStr) { 328 setEvaluated(debugger.evaluateExpr(model.getCurrentFrame(), exprStr)); 329 } 330 331 public void setEvaluated(VariableNode evaluatedWatch) { 332 synchronized(this) { 333 this.evaluatedWatch = evaluatedWatch; 334 } 335 } 336 337 synchronized VariableNode getEvaluatedWatch() { 338 return evaluatedWatch; 339 } 340 341 public void expressionChanged() { 342 setEvaluated(null); 343 parseExpression(w.getExpression()); 344 } 345 346 public synchronized String getExceptionDescription() { 347 return null; 348 } 349 350 public synchronized String getExpression() { 351 return w.getExpression(); 352 } 353 354 355 public synchronized void remove() { 356 w.remove(); 357 } 358 359 public void setExpression(String expression) { 360 w.setExpression(expression); 361 expressionChanged(); 362 } 363 364 public synchronized void setValue(String value) { } 372 373 private VariableNode getUpdatedEvaluatedWatch() { 374 synchronized(this) { 375 VariableNode evaluatedWatch = this.evaluatedWatch; 376 } 377 if(evaluatedWatch == null) { 378 getValue(); } 380 return evaluatedWatch; 381 } 382 383 public String getName() { 387 return w.getExpression(); 388 } 389 390 public String getDisplayName() { 391 return w.getExpression(); 392 } 393 394 public String getShortDescription() { 395 return w.getExpression(); 396 } 397 398 public String getIconBase() { 399 return WATCH_ICON; 400 } 401 402 public int getType() { 403 return TYPE_WATCH; 404 } 405 406 public String getTypeName() { 407 VariableNode evalWatch = getUpdatedEvaluatedWatch(); 408 return evalWatch != null ? evalWatch.getTypeName() : "Evaluating..."; 409 } 410 411 public String getValue() { 412 synchronized(evaluating) { 413 if(evaluating[0]) { 414 try { 415 evaluating.wait(); 416 } catch(InterruptedException iex) { 417 return null; 418 } 419 } 420 synchronized(this) { 421 if(evaluatedWatch != null) { 422 Object value = evaluatedWatch.getValue(); 423 return(value != null) ? value.toString() : null; 424 } 425 } 426 evaluating[0] = true; 427 } 428 429 VariableNode vn = null; 430 try { 431 vn = debugger.evaluateExpr(model.getCurrentFrame(), w.getExpression()); 432 } finally { 433 setEvaluated(vn); 434 synchronized(evaluating) { 435 evaluating[0] = false; 436 evaluating.notifyAll(); 437 } 438 } 439 440 Object value = (vn != null) ? vn.getValue() : "no value yet..."; 441 return (value != null) ? value.toString() : null; 442 } 443 444 public String getTooltipValue() { 445 Object v = getValue(); 446 return (v != null) ? v.toString() : null; 447 } 448 449 public VariableNode[] getChildren(int from, int to) { 450 VariableNode evalWatch = getUpdatedEvaluatedWatch(); 451 return evalWatch != null ? evalWatch.getChildren(from, to) : new VariableNode[0]; 452 } 453 454 public boolean isLeaf() { 455 VariableNode evalWatch = getUpdatedEvaluatedWatch(); 456 return evalWatch != null ? evalWatch.isLeaf() : false; 457 } 458 459 public int getChildrenCount() { 460 VariableNode evalWatch = getUpdatedEvaluatedWatch(); 461 return evalWatch != null ? evalWatch.getChildrenCount() : 0; 462 } 463 464 public boolean isReadOnly() { 465 return true; 466 } 467 468 public void collectUpdates(Object source, 469 Collection<ModelEvent> events, 470 VariableNode newVar) { 471 throw new IllegalStateException ("This API valid on VariableNodeImpl only"); 472 } 473 474 public void addPropertyChangeListener(PropertyChangeListener l) { 478 propSupp.addPropertyChangeListener(l); 479 } 480 481 public void removePropertyChangeListener(PropertyChangeListener l) { 482 propSupp.removePropertyChangeListener(l); 483 } 484 485 486 public void propertyChange(PropertyChangeEvent evt) { 490 model.fireTableValueChangedChanged(this, null); 491 } 492 493 494 498 public void refresh() throws RefreshFailedException { 499 synchronized(evaluating) { 500 if(evaluating[0]) { 501 try { 502 evaluating.wait(); 503 } catch(InterruptedException iex) { 504 throw new RefreshFailedException (iex.getLocalizedMessage()); 505 } 506 } 507 } 508 } 509 510 512 public synchronized boolean isCurrent() { 513 return evaluatedWatch != null; 514 } 515 } 516 517 private static class Listener extends DebuggerManagerAdapter 518 implements PropertyChangeListener { 519 520 private WeakReference <WatchesModel> model; 521 private WeakReference <DbgDebuggerImpl> debugger; 522 523 private Listener( 524 WatchesModel tm, 525 DbgDebuggerImpl debugger 526 ) { 527 model = new WeakReference <WatchesModel>(tm); 528 this.debugger = new WeakReference <DbgDebuggerImpl>(debugger); 529 DebuggerManager.getDebuggerManager().addDebuggerListener( 530 DebuggerManager.PROP_WATCHES, 531 this 532 ); 533 Watch[] ws = DebuggerManager.getDebuggerManager().getWatches(); 535 int i, k = ws.length; 536 for(i = 0; i < k; i++) { 537 ws [i].addPropertyChangeListener(this); 538 } 539 } 540 541 private WatchesModel getModel() { 542 WatchesModel m = model.get(); 543 if(m == null) { 544 destroy(); 545 } 546 return m; 547 } 548 549 public void watchAdded(Watch watch) { 550 WatchesModel m = getModel(); 551 if(m == null) { 552 return; 553 } 554 watch.addPropertyChangeListener(this); 555 m.fireWatchesChanged(); 556 } 557 558 public void watchRemoved(Watch watch) { 559 WatchesModel m = getModel(); 560 if(m == null) { 561 return; 562 } 563 watch.removePropertyChangeListener(this); 564 m.fireWatchesChanged(); 565 } 566 567 private RequestProcessor.Task task; 570 571 public void propertyChange(PropertyChangeEvent evt) { 572 String propName = evt.getPropertyName(); 573 if(DebuggerManager.PROP_WATCHES.equals(propName)) { 575 return; 576 } 577 final WatchesModel m = getModel(); 578 if(m == null) { 579 return; 580 } 581 589 if(evt.getSource() instanceof Watch) { 590 Object node; 591 synchronized(m.watchToValue) { 592 node = m.watchToValue.get(evt.getSource()); 593 } 594 if(node != null) { 595 m.fireTableValueChangedChanged(node, null); 596 return ; 597 } 598 } 599 600 if(task == null) { 601 task = RequestProcessor.getDefault().create(new Runnable () { 602 public void run() { 603 System.err.println("WM do task " + task); 604 m.fireTreeChanged(); 605 } 606 }); 607 System.err.println("WM create task " + task); 608 } 609 task.schedule(100); 610 } 611 612 private void destroy() { 613 DebuggerManager.getDebuggerManager().removeDebuggerListener( 614 DebuggerManager.PROP_WATCHES, 615 this 616 ); 617 DbgDebuggerImpl d = debugger.get(); 618 if(d != null) { 619 } 621 622 Watch[] ws = DebuggerManager.getDebuggerManager().getWatches(); 623 int i, k = ws.length; 624 for(i = 0; i < k; i++) { 625 ws [i].removePropertyChangeListener(this); 626 } 627 628 if(task != null) { 629 task.cancel(); 631 System.err.println("WM cancel old task " + task); 632 task = null; 633 } 634 } 635 } 636 } 637 | Popular Tags |