| 1 11 package org.eclipse.debug.internal.ui.viewers; 12 13 import java.util.ArrayList ; 14 import java.util.HashMap ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 import java.util.Map ; 18 import java.util.Map.Entry; 19 20 import org.eclipse.core.runtime.IAdaptable; 21 import org.eclipse.core.runtime.IProgressMonitor; 22 import org.eclipse.core.runtime.IStatus; 23 import org.eclipse.core.runtime.Status; 24 import org.eclipse.debug.internal.ui.DebugUIPlugin; 25 import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter; 26 import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor; 27 import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter; 28 import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation; 29 import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter; 30 import org.eclipse.jface.resource.ImageDescriptor; 31 import org.eclipse.jface.util.Assert; 32 import org.eclipse.jface.viewers.CellEditor; 33 import org.eclipse.jface.viewers.DoubleClickEvent; 34 import org.eclipse.jface.viewers.ICellModifier; 35 import org.eclipse.jface.viewers.ISelection; 36 import org.eclipse.jface.viewers.IStructuredSelection; 37 import org.eclipse.jface.viewers.OpenEvent; 38 import org.eclipse.jface.viewers.StructuredSelection; 39 import org.eclipse.jface.viewers.TreePath; 40 import org.eclipse.jface.viewers.TreeSelection; 41 import org.eclipse.jface.viewers.Viewer; 42 import org.eclipse.swt.SWT; 43 import org.eclipse.swt.custom.TreeEditor; 44 import org.eclipse.swt.events.ControlEvent; 45 import org.eclipse.swt.events.ControlListener; 46 import org.eclipse.swt.events.MouseAdapter; 47 import org.eclipse.swt.events.MouseEvent; 48 import org.eclipse.swt.events.MouseListener; 49 import org.eclipse.swt.events.PaintEvent; 50 import org.eclipse.swt.events.PaintListener; 51 import org.eclipse.swt.events.TreeEvent; 52 import org.eclipse.swt.events.TreeListener; 53 import org.eclipse.swt.graphics.Color; 54 import org.eclipse.swt.graphics.Font; 55 import org.eclipse.swt.graphics.FontData; 56 import org.eclipse.swt.graphics.Image; 57 import org.eclipse.swt.graphics.Point; 58 import org.eclipse.swt.graphics.RGB; 59 import org.eclipse.swt.graphics.Rectangle; 60 import org.eclipse.swt.widgets.Composite; 61 import org.eclipse.swt.widgets.Control; 62 import org.eclipse.swt.widgets.Item; 63 import org.eclipse.swt.widgets.Tree; 64 import org.eclipse.swt.widgets.TreeColumn; 65 import org.eclipse.swt.widgets.TreeItem; 66 import org.eclipse.swt.widgets.Widget; 67 import org.eclipse.ui.IMemento; 68 import org.eclipse.ui.progress.WorkbenchJob; 69 70 81 public class AsynchronousTreeViewer extends AsynchronousViewer { 82 83 86 private Tree fTree; 87 88 91 private TreeEditorImpl fTreeEditorImpl; 92 private TreeEditor fTreeEditor; 93 94 99 private List fPendingExpansion = new ArrayList (); 100 101 104 private IColumnPresentation fColumnPresentation = null; 105 106 109 private IColumnEditor fColumnEditor = null; 110 111 115 private Map fVisibleColumns = new HashMap (); 116 117 120 private Map fColumnSizes = new HashMap (); 121 122 127 private Map fShowColumns = new HashMap (); 128 129 132 private static final String COLUMN_SIZES = "COLUMN_SIZES"; 137 private static final String VISIBLE_COLUMNS = "VISIBLE_COLUMNS"; 142 private static final String SHOW_COLUMNS = "SHOW_COLUMNS"; 147 private static final String SIZE = "SIZE"; 151 private static final String COLUMN = "COLUMN"; 153 158 class ColumnListener implements ControlListener { 159 162 public void controlMoved(ControlEvent e) { 163 } 164 165 168 public void controlResized(ControlEvent e) { 169 persistColumnSizes(); 170 } 171 } 172 173 private ColumnListener fListener = new ColumnListener(); 174 175 185 public AsynchronousTreeViewer(Composite parent) { 186 this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL); 187 } 188 189 199 public AsynchronousTreeViewer(Composite parent, int style) { 200 this(new Tree(parent, style)); 201 } 202 203 211 public AsynchronousTreeViewer(Tree tree) { 212 super(); 213 Assert.isTrue((tree.getStyle() & SWT.VIRTUAL) != 0); 214 fTree = tree; 215 hookControl(fTree); 216 fTreeEditor = new TreeEditor(tree); 217 initTreeViewerImpl(); 218 } 219 220 223 protected void hookControl(Control control) { 224 super.hookControl(control); 225 Tree tree = (Tree)control; 226 tree.addMouseListener(new MouseAdapter() { 227 public void mouseDown(MouseEvent e) { 228 if (isShowColumns()) { 229 Item[] items = fTreeEditorImpl.getSelection(); 230 if (items.length > 0) { 231 TreeItem treeItem = (TreeItem) items[0]; 232 if (treeItem != null) { 233 Object element = treeItem.getData(); 234 updateColumnEditor(element); 235 if (fColumnEditor != null) { 236 int columnToEdit = -1; 237 int columns = fTree.getColumnCount(); 238 if (columns == 0) { 239 columnToEdit = 0; 242 } else { 243 columnToEdit = -1; 244 for (int i = 0; i < columns; i++) { 245 Rectangle bounds = fTreeEditorImpl.getBounds(treeItem, i); 246 if (bounds.contains(e.x, e.y)) { 247 columnToEdit = i; 248 break; 249 } 250 } 251 if (columnToEdit == -1) { 252 return; 253 } 254 } 255 CellEditor cellEditor = fColumnEditor.getCellEditor(getVisibleColumns()[columnToEdit], element, fTree); 256 if (cellEditor == null) { 257 return; 258 } 259 disposeCellEditors(); 260 CellEditor[] newEditors = new CellEditor[columns]; 261 newEditors[columnToEdit] = cellEditor; 262 setCellEditors(newEditors); 263 setCellModifier(fColumnEditor.getCellModifier()); 264 setColumnProperties(getVisibleColumns()); 265 } 266 } 267 } 268 } 269 270 fTreeEditorImpl.handleMouseDown(e); 271 } 272 }); 273 tree.addTreeListener(new TreeListener() { 274 public void treeExpanded(TreeEvent e) { 275 ((TreeItem) e.item).setExpanded(true); 276 ModelNode node = findNode(e.item); 277 if (node != null) { 278 internalRefresh(node); 279 } 280 } 281 282 public void treeCollapsed(TreeEvent e) { 283 } 284 }); 285 286 tree.addMouseListener(new MouseListener() { 287 public void mouseUp(MouseEvent e) { 288 } 289 290 public void mouseDown(MouseEvent e) { 291 } 292 293 public void mouseDoubleClick(MouseEvent e) { 294 TreeItem item = ((Tree) e.widget).getItem(new Point(e.x, e.y)); 295 if (item != null) { 296 if (item.getExpanded()) { 297 item.setExpanded(false); 298 } else { 299 item.setExpanded(true); 300 ModelNode node = findNode(item); 301 if (node != null) { 302 internalRefresh(node); 303 } 304 } 305 } 306 } 307 }); 308 } 309 310 315 protected void updateColumnEditor(Object element) { 316 IColumnEditorFactoryAdapter factoryAdapter = getColumnEditorFactoryAdapter(element); 317 if (factoryAdapter != null) { 318 if (fColumnEditor != null) { 319 if (fColumnEditor.getId().equals(factoryAdapter.getColumnEditorId(getPresentationContext(), element))) { 320 return; 322 } else { 323 fColumnEditor.dispose(); 325 } 326 } 327 fColumnEditor = factoryAdapter.createColumnEditor(getPresentationContext(), element); 329 if (fColumnEditor != null) { 330 fColumnEditor.init(getPresentationContext()); 331 } 332 } else { 333 if (fColumnEditor != null) { 335 fColumnEditor.dispose(); 336 fColumnEditor = null; 337 } 338 } 339 } 340 341 346 public Tree getTree() { 347 return fTree; 348 } 349 350 355 protected void updateHasChildren(ModelNode node) { 356 ((AsynchronousTreeModel)getModel()).updateHasChildren(node); 357 } 358 359 364 public synchronized void expand(ISelection selection) { 365 if (selection instanceof TreeSelection) { 366 TreePath[] paths = ((TreeSelection) selection).getPaths(); 367 for (int i = 0; i < paths.length; i++) { 368 fPendingExpansion.add(paths[i]); 369 } 370 if (getControl().getDisplay().getThread() == Thread.currentThread()) { 371 attemptExpansion(); 372 } else { 373 WorkbenchJob job = new WorkbenchJob("attemptExpansion") { public IStatus runInUIThread(IProgressMonitor monitor) { 375 attemptExpansion(); 376 return Status.OK_STATUS; 377 } 378 379 }; 380 job.setSystem(true); 381 job.schedule(); 382 } 383 } 384 } 385 386 389 synchronized void attemptExpansion() { 390 if (fPendingExpansion != null) { 391 for (Iterator i = fPendingExpansion.iterator(); i.hasNext();) { 392 TreePath path = (TreePath) i.next(); 393 if (attemptExpansion(path)) { 394 i.remove(); 395 } 396 } 397 } 398 } 399 400 407 synchronized boolean attemptExpansion(TreePath path) { 408 int segmentCount = path.getSegmentCount(); 409 for (int j = segmentCount - 1; j >= 0; j--) { 410 Object element = path.getSegment(j); 411 ModelNode[] nodes = getModel().getNodes(element); 412 if (nodes != null) { 413 for (int k = 0; k < nodes.length; k++) { 414 ModelNode node = nodes[k]; 415 TreePath treePath = node.getTreePath(); 416 if (path.startsWith(treePath, null)) { 417 if (!node.isDisposed()) { 418 Widget widget = findItem(node); 419 if (widget == null) { 420 ModelNode parent = node.getParentNode(); 422 ModelNode child = node; 423 widget = findItem(parent); 424 while (widget == null && parent != null) { 425 child = parent; 426 parent = parent.getParentNode(); 427 if (parent != null) { 428 widget = findItem(parent); 429 treePath = parent.getTreePath(); 430 } 431 } 432 int childIndex = parent.getChildIndex(child); 433 if (childIndex < 0) { 434 return false; 435 } 436 TreeItem[] items = getItems(widget); 437 if (childIndex < items.length) { 438 widget = items[childIndex]; 439 mapElement(child, widget); 440 widget.setData(child.getElement()); 441 treePath = child.getTreePath(); 442 node = child; 443 } else { 444 return false; 445 } 446 } 447 if (widget instanceof TreeItem && !widget.isDisposed()) { 448 TreeItem treeItem = (TreeItem) widget; 449 if (treeItem.getExpanded()) { 450 return path.getSegmentCount() == treePath.getSegmentCount(); 451 } 452 if (treeItem.getItemCount() > 0) { 453 updateChildren(node); 454 expand(treeItem); 455 if (path.getSegmentCount() == treePath.getSegmentCount()) { 456 return true; 457 } 458 return false; 459 } 460 } 461 } 462 } 463 } 464 } 465 } 466 return false; 467 } 468 469 474 public Control getControl() { 475 return fTree; 476 } 477 478 479 482 public synchronized void dispose() { 483 if (fColumnPresentation != null) { 484 fColumnPresentation.dispose(); 485 } 486 disposeCellEditors(); 487 if (fColumnEditor != null) { 488 fColumnEditor.dispose(); 489 } 490 super.dispose(); 491 } 492 493 496 protected void disposeCellEditors() { 497 CellEditor[] cellEditors = getCellEditors(); 498 if (cellEditors != null) { 499 for (int i = 0; i < cellEditors.length; i++) { 500 CellEditor editor = cellEditors[i]; 501 if (editor != null) { 502 editor.dispose(); 503 } 504 } 505 } 506 setCellEditors(null); 507 } 508 509 515 synchronized protected void inputChanged(Object input, Object oldInput) { 516 fPendingExpansion.clear(); 517 super.inputChanged(input, oldInput); 518 resetColumns(input); 519 } 520 521 524 public void refreshColumns() { 525 configureColumns(); 526 refresh(); 527 } 528 529 534 protected void resetColumns(Object input) { 535 if (input != null) { 536 IColumnPresentationFactoryAdapter factory = getColumnPresenetationFactoryAdapter(input); 538 PresentationContext context = (PresentationContext) getPresentationContext(); 539 String type = null; 540 if (factory != null) { 541 type = factory.getColumnPresentationId(context, input); 542 } 543 if (type != null) { 544 if (fColumnPresentation != null) { 545 if (!fColumnPresentation.getId().equals(type)) { 546 fColumnPresentation.dispose(); 548 fColumnPresentation = null; 549 } 550 } 551 if (fColumnPresentation == null) { 552 fColumnPresentation = factory.createColumnPresentation(context, input); 553 if (fColumnPresentation != null) { 554 fColumnPresentation.init(context); 555 configureColumns(); 556 } 557 } 558 } else { 559 if (fColumnPresentation != null) { 560 fColumnPresentation.dispose(); 561 fColumnPresentation = null; 562 configureColumns(); 563 } 564 } 565 } 566 } 567 568 573 protected void configureColumns() { 574 if (fColumnPresentation != null) { 575 IColumnPresentation build = null; 576 if (isShowColumns(fColumnPresentation.getId())) { 577 build = fColumnPresentation; 578 } 579 buildColumns(build); 580 } else { 581 buildColumns(null); 583 } 584 } 585 586 593 protected void buildColumns(IColumnPresentation presentation) { 594 Tree tree = getTree(); 596 final TreeColumn[] columns = tree.getColumns(); 597 String [] visibleColumnIds = getVisibleColumns(); 598 for (int i = 0; i < columns.length; i++) { 599 TreeColumn treeColumn = columns[i]; 600 treeColumn.removeControlListener(fListener); 601 treeColumn.dispose(); 602 } 603 PresentationContext presentationContext = (PresentationContext) getPresentationContext(); 604 if (presentation != null) { 605 for (int i = 0; i < visibleColumnIds.length; i++) { 606 String id = visibleColumnIds[i]; 607 String header = presentation.getHeader(id); 608 TreeColumn column = new TreeColumn(tree, SWT.LEFT, i); 610 column.setMoveable(true); 611 column.setText(header); 612 column.setWidth(1); 613 ImageDescriptor image = presentation.getImageDescriptor(id); 614 if (image != null) { 615 column.setImage(getImage(image)); 616 } 617 column.setData(id); 618 } 619 tree.setHeaderVisible(true); 620 tree.setLinesVisible(true); 621 presentationContext.setColumns(getVisibleColumns()); 622 } else { 623 tree.setHeaderVisible(false); 624 tree.setLinesVisible(false); 625 presentationContext.setColumns(null); 626 } 627 628 int avg = tree.getSize().x; 629 if (visibleColumnIds != null) 630 avg /= visibleColumnIds.length; 631 632 if (avg == 0) { 633 tree.addPaintListener(new PaintListener() { 634 public void paintControl(PaintEvent e) { 635 Tree tree2 = getTree(); 636 String [] visibleColumns = getVisibleColumns(); 637 if (visibleColumns != null) { 638 int avg1 = tree2.getSize().x / visibleColumns.length; 639 initColumns(avg1); 640 } 641 tree2.removePaintListener(this); 642 } 643 }); 644 } else { 645 initColumns(avg); 646 } 647 } 648 649 private void initColumns(int widthHint) { 650 TreeColumn[] columns = getTree().getColumns(); 651 for (int i = 0; i < columns.length; i++) { 652 TreeColumn treeColumn = columns[i]; 653 Integer width = (Integer ) fColumnSizes.get(treeColumn.getData()); 654 if (width == null) { 655 treeColumn.setWidth(widthHint); 656 } else { 657 treeColumn.setWidth(width.intValue()); 658 } 659 treeColumn.addControlListener(fListener); 660 } 661 } 662 665 protected void persistColumnSizes() { 666 Tree tree = getTree(); 667 TreeColumn[] columns = tree.getColumns(); 668 for (int i = 0; i < columns.length; i++) { 669 TreeColumn treeColumn = columns[i]; 670 Object id = treeColumn.getData(); 671 fColumnSizes.put(id, new Integer (treeColumn.getWidth())); 672 } 673 } 674 675 681 protected IColumnPresentationFactoryAdapter getColumnPresenetationFactoryAdapter(Object input) { 682 if (input instanceof IColumnPresentationFactoryAdapter) { 683 return (IColumnPresentationFactoryAdapter) input; 684 } 685 if (input instanceof IAdaptable) { 686 IAdaptable adaptable = (IAdaptable) input; 687 return (IColumnPresentationFactoryAdapter) adaptable.getAdapter(IColumnPresentationFactoryAdapter.class); 688 } 689 return null; 690 } 691 692 698 protected IColumnEditorFactoryAdapter getColumnEditorFactoryAdapter(Object input) { 699 if (input instanceof IColumnEditorFactoryAdapter) { 700 return (IColumnEditorFactoryAdapter) input; 701 } 702 if (input instanceof IAdaptable) { 703 IAdaptable adaptable = (IAdaptable) input; 704 return (IColumnEditorFactoryAdapter) adaptable.getAdapter(IColumnEditorFactoryAdapter.class); 705 } 706 return null; 707 } 708 709 718 protected synchronized TreePath getTreePath(TreeItem item) { 719  
|