KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > internal > ui > viewers > model > InternalTreeModelViewer


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.debug.internal.ui.viewers.model;
12
13 import java.util.HashMap JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.Map JavaDoc;
16 import java.util.Map.Entry;
17
18 import org.eclipse.core.runtime.IAdaptable;
19 import org.eclipse.core.runtime.PlatformObject;
20 import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
21 import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
22 import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
23 import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
24 import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
25 import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory;
26 import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
27 import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
28 import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
29 import org.eclipse.debug.internal.ui.views.launch.DebugElementAdapterFactory;
30 import org.eclipse.jface.resource.ImageDescriptor;
31 import org.eclipse.jface.viewers.CellEditor;
32 import org.eclipse.jface.viewers.ICellModifier;
33 import org.eclipse.jface.viewers.IContentProvider;
34 import org.eclipse.jface.viewers.ILazyTreePathContentProvider;
35 import org.eclipse.jface.viewers.ISelection;
36 import org.eclipse.jface.viewers.IStructuredSelection;
37 import org.eclipse.jface.viewers.StructuredSelection;
38 import org.eclipse.jface.viewers.TreePath;
39 import org.eclipse.jface.viewers.TreeViewer;
40 import org.eclipse.swt.SWT;
41 import org.eclipse.swt.events.ControlEvent;
42 import org.eclipse.swt.events.ControlListener;
43 import org.eclipse.swt.events.DisposeEvent;
44 import org.eclipse.swt.events.PaintEvent;
45 import org.eclipse.swt.events.PaintListener;
46 import org.eclipse.swt.graphics.Color;
47 import org.eclipse.swt.graphics.Font;
48 import org.eclipse.swt.graphics.Image;
49 import org.eclipse.swt.widgets.Composite;
50 import org.eclipse.swt.widgets.Control;
51 import org.eclipse.swt.widgets.Event;
52 import org.eclipse.swt.widgets.Item;
53 import org.eclipse.swt.widgets.Listener;
54 import org.eclipse.swt.widgets.Tree;
55 import org.eclipse.swt.widgets.TreeColumn;
56 import org.eclipse.swt.widgets.TreeItem;
57 import org.eclipse.swt.widgets.Widget;
58 import org.eclipse.ui.IMemento;
59
60 /**
61  * A tree viewer that displays a model.
62  *
63  * @since 3.3
64  */

65 public class InternalTreeModelViewer extends TreeViewer {
66     
67     private IPresentationContext fContext;
68     
69     /**
70      * Current column presentation or <code>null</code>
71      */

72     private IColumnPresentation fColumnPresentation = null;
73     
74     /**
75      * Map of columns presentation id to its visible columns id's (String[])
76      * When a columns presentation is not in the map, default settings are used.
77      */

78     private Map JavaDoc fVisibleColumns = new HashMap JavaDoc();
79     
80     /**
81      * Map of column id's to persisted sizes
82      */

83     private Map JavaDoc fColumnSizes = new HashMap JavaDoc();
84     
85     /**
86      * Map of column presentation id's to an array of integers representing the column order
87      * for that presentation, or <code>null</code> if default.
88      */

89     private Map JavaDoc fColumnOrder = new HashMap JavaDoc();
90     
91     /**
92      * Map of column presentation id to whether columns should be displayed
93      * for that presentation (the user can toggle columns on/off when a
94      * presentation is optional.
95      */

96     private Map JavaDoc fShowColumns = new HashMap JavaDoc();
97     
98     /**
99      * Item's tree path cache
100      */

101     private static final String JavaDoc TREE_PATH_KEY = "TREE_PATH_KEY"; //$NON-NLS-1$
102

103     /**
104      * Memento type for column sizes. Sizes are keyed by column presentation id
105      */

106     private static final String JavaDoc COLUMN_SIZES = "COLUMN_SIZES"; //$NON-NLS-1$
107
/**
108      * Memento type for the column order for a presentation context.
109      * A memento is created for each column presentation
110      */

111     private static final String JavaDoc COLUMN_ORDER = "COLUMN_ORDER"; //$NON-NLS-1$
112
/**
113      * Memento type for the visible columns for a presentation context.
114      * A memento is created for each column presentation keyed by column number
115      */

116     private static final String JavaDoc VISIBLE_COLUMNS = "VISIBLE_COLUMNS"; //$NON-NLS-1$
117
/**
118      * Memento type for whether columns are visible for a presentation context.
119      * Booleans are keyed by column presentation id
120      */

121     private static final String JavaDoc SHOW_COLUMNS = "SHOW_COLUMNS"; //$NON-NLS-1$
122
/**
123      * Memento key for the number of visible columns in a VISIBLE_COLUMNS memento
124      * or for the width of a column
125      */

126     private static final String JavaDoc SIZE = "SIZE"; //$NON-NLS-1$
127
/**
128      * Memento key prefix a visible column
129      */

130     private static final String JavaDoc COLUMN = "COLUMN"; //$NON-NLS-1$
131

132     /**
133      * True while performing an insert... we allow insert with filters
134      */

135     private boolean fInserting = false;
136     
137     /**
138      * Whether to notify the content provider when an element is unmapped
139      */

140     private boolean fNotifyUnmap = true;
141     
142     /**
143      * Persist column sizes when they change.
144      *
145      * @since 3.2
146      */

147     class ColumnListener implements ControlListener {
148         /* (non-Javadoc)
149          * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
150          */

151         public void controlMoved(ControlEvent e) {
152             persistColumnOrder();
153         }
154
155         /* (non-Javadoc)
156          * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent)
157          */

158         public void controlResized(ControlEvent e) {
159             persistColumnSizes();
160         }
161     }
162     
163     private ColumnListener fListener = new ColumnListener();
164
165     /**
166      * Proxy to cell modifier/editor support
167      */

168     class CellModifierProxy implements ICellModifier {
169         
170         private ICellModifier fModifier;
171
172         /* (non-Javadoc)
173          * @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object, java.lang.String)
174          */

175         public boolean canModify(Object JavaDoc element, String JavaDoc property) {
176             IElementEditor editor = getElementEditorAdapter(element);
177             if (editor != null) {
178                 fModifier = editor.getCellModifier(getPresentationContext(), element);
179                 if (fModifier != null) {
180                     if (fModifier.canModify(element, property)) {
181                         // install cell editor
182
CellEditor cellEditor = editor.getCellEditor(getPresentationContext(), property, element, (Composite)getControl());
183                         if (cellEditor != null) {
184                             disposeCellEditors();
185                             CellEditor[] newEditors = new CellEditor[getVisibleColumns().length];
186                             for (int i = 0; i < newEditors.length; i++) {
187                                 newEditors[i] = cellEditor;
188                             }
189                             setCellEditors(newEditors);
190                             return true;
191                         }
192                     }
193                 }
194             }
195             return false;
196         }
197
198         /* (non-Javadoc)
199          * @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object, java.lang.String)
200          */

201         public Object JavaDoc getValue(Object JavaDoc element, String JavaDoc property) {
202             if (fModifier != null) {
203                 return fModifier.getValue(element, property);
204             }
205             return null;
206         }
207
208         /* (non-Javadoc)
209          * @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object, java.lang.String, java.lang.Object)
210          */

211         public void modify(Object JavaDoc element, String JavaDoc property, Object JavaDoc value) {
212             if (fModifier != null) {
213                 if (element instanceof Item) {
214                     element = ((Item)element).getData();
215                 }
216                 fModifier.modify(element, property, value);
217             }
218         }
219         
220         /**
221          * Disposes client's column editor and cell editors
222          */

223         protected void dispose() {
224             fModifier = null;
225             disposeCellEditors();
226             setCellEditors(null);
227         }
228
229         /**
230          * Disposes current cell editors
231          */

232         protected void disposeCellEditors() {
233             CellEditor[] cellEditors = getCellEditors();
234             if (cellEditors != null) {
235                 for (int i = 0; i < cellEditors.length; i++) {
236                     CellEditor editor = cellEditors[i];
237                     if (editor != null) {
238                         editor.dispose();
239                     }
240                 }
241             }
242         }
243         
244         /**
245          * Returns the element editor for the given element or <code>null</code>.
246          *
247          * @param input
248          * @return element editor or <code>null</code>
249          */

250         protected IElementEditor getElementEditorAdapter(Object JavaDoc input) {
251             if (input instanceof IElementEditor) {
252                 return (IElementEditor) input;
253             }
254             if (input instanceof IAdaptable) {
255                 IAdaptable adaptable = (IAdaptable) input;
256                 return (IElementEditor) adaptable.getAdapter(IElementEditor.class);
257             }
258             return null;
259         }
260     }
261     
262     private CellModifierProxy fCellModifier;
263     
264     /**
265      * @param parent
266      * @param style
267      */

268     public InternalTreeModelViewer(Composite parent, int style, IPresentationContext context) {
269         super(parent, style);
270         if ((style & SWT.VIRTUAL) == 0) {
271             throw new IllegalArgumentException JavaDoc("style must include SWT.VIRTUAL"); //$NON-NLS-1$
272
}
273         setUseHashlookup(true);
274         fCellModifier = new CellModifierProxy();
275         fContext = context;
276         setContentProvider(createContentProvider());
277         setLabelProvider(createLabelProvider());
278     }
279     
280     /**
281      * @return content provider for this tree viewer
282      */

283     protected TreeModelContentProvider createContentProvider()
284     {
285         return new TreeModelContentProvider();
286     }
287     
288     /**
289      * @return label provider for this tree viewer
290      */

291     protected TreeModelLabelProvider createLabelProvider()
292     {
293         return new TreeModelLabelProvider(this);
294     }
295     
296     /* (non-Javadoc)
297      *
298      * Workaround for bug 159461: when an item is cleared it's label is cleared. To avoid
299      * flashing, restore its label to its previous value.
300      *
301      * @see org.eclipse.jface.viewers.TreeViewer#hookControl(org.eclipse.swt.widgets.Control)
302      */

303     protected void hookControl(Control control) {
304         Tree treeControl = (Tree) control;
305         treeControl.addListener(SWT.SetData, new Listener() {
306             public void handleEvent(Event event) {
307                 // to avoid flash, reset previous label data
308
TreeItem item = (TreeItem) event.item;
309                 preserveItem(item);
310             }
311         });
312         super.hookControl(control);
313     }
314     
315     /**
316      * @param item
317      */

318     private void preserveItem(TreeItem item) {
319         Object JavaDoc[] labels = (Object JavaDoc[]) item.getData(LabelUpdate.PREV_LABEL_KEY);
320         if (labels != null) {
321             for (int i = 0; i < labels.length; i++) {
322                 if (labels[i] != null) {
323                     item.setText(i, (String JavaDoc)labels[i]);
324                 }
325             }
326         }
327         Object JavaDoc[] images = (Object JavaDoc[]) item.getData(LabelUpdate.PREV_IMAGE_KEY);
328         if (images != null) {
329             for (int i = 0; i < images.length; i++) {
330                 item.setImage(i, (Image) images[i]);
331             }
332         }
333         Object JavaDoc[] fonts = (Object JavaDoc[]) item.getData(LabelUpdate.PREV_FONT_KEY);
334         if (fonts != null) {
335             for (int i = 0; i < fonts.length; i++) {
336                 item.setFont(i, (Font) fonts[i]);
337             }
338         }
339         Object JavaDoc[] foregrounds = (Object JavaDoc[]) item.getData(LabelUpdate.PREV_FOREGROUND_KEY);
340         if (foregrounds != null) {
341             for (int i = 0; i < foregrounds.length; i++) {
342                 item.setForeground(i, (Color) foregrounds[i]);
343             }
344         }
345         Object JavaDoc[] backgrounds = (Object JavaDoc[]) item.getData(LabelUpdate.PREV_BACKGROUND_KEY);
346         if (backgrounds != null) {
347             for (int i = 0; i < backgrounds.length; i++) {
348                 item.setBackground(i, (Color) backgrounds[i]);
349             }
350         }
351     }
352
353     /* (non-Javadoc)
354      * @see org.eclipse.jface.viewers.StructuredViewer#handleInvalidSelection
355      *
356      * Override the default handler for invalid selection to allow model
357      * selection policy to select the new selection.
358      */

359     protected void handleInvalidSelection(ISelection selection, ISelection newSelection) {
360         IModelSelectionPolicy selectionPolicy = getSelectionPolicy(selection);
361         if (selectionPolicy != null) {
362             ISelection temp = newSelection;
363             newSelection = selectionPolicy.replaceInvalidSelection(selection, newSelection);
364             if (temp != newSelection) {
365                 if (newSelection == null) {
366                     newSelection = new StructuredSelection();
367                 }
368                 // call super.setSelection(...) to avoid asking the selection policy
369
// if the selection should be overridden
370
super.setSelection(newSelection, false);
371                 return;
372             }
373         }
374         super.handleInvalidSelection(selection, newSelection);
375     }
376         
377
378     /* (non-Javadoc)
379      * @see org.eclipse.jface.viewers.ContentViewer#handleDispose(org.eclipse.swt.events.DisposeEvent)
380      */

381     protected void handleDispose(DisposeEvent event) {
382         if (fColumnPresentation != null) {
383             fColumnPresentation.dispose();
384         }
385         fCellModifier.dispose();
386         fContext.dispose();
387         super.handleDispose(event);
388     }
389     
390     /**
391      * Returns this viewer's presentation context.
392      *
393      * @return presentation context
394      */

395     public IPresentationContext getPresentationContext() {
396         return fContext;
397     }
398     
399     protected void unmapElement(Object JavaDoc element, Widget widget) {
400         if (fNotifyUnmap) {
401             // TODO: should we update the filter with the "new non-identical element"?
402
IContentProvider provider = getContentProvider();
403             if (provider instanceof ModelContentProvider) {
404                 ((ModelContentProvider) provider).unmapPath((TreePath) widget.getData(TREE_PATH_KEY));
405             }
406         }
407         super.unmapElement(element, widget);
408     }
409     
410     protected void associate(Object JavaDoc element, Item item) {
411         // see AbstractTreeViewer.associate(...)
412
Object JavaDoc data = item.getData();
413         if (data != null && data != element && equals(data, element)) {
414             // elements are equal but not identical
415
// -> being removed from map, but should not change filters
416
try {
417                 fNotifyUnmap = false;
418                 super.associate(element, item);
419             } finally {
420                 fNotifyUnmap = true;
421             }
422         } else {
423             super.associate(element, item);
424         }
425     }
426
427     /* (non-Javadoc)
428      *
429      * We need tree paths when disposed/unmapped in any order so cache the tree path.
430      *
431      * @see org.eclipse.jface.viewers.TreeViewer#mapElement(java.lang.Object, org.eclipse.swt.widgets.Widget)
432      */

433     protected void mapElement(Object JavaDoc element, Widget widget) {
434         super.mapElement(element, widget);
435         if (widget instanceof Item) {
436             widget.setData(TREE_PATH_KEY, getTreePathFromItem((Item)widget));
437         } else {
438             widget.setData(TREE_PATH_KEY, ModelContentProvider.EMPTY_TREE_PATH);
439         }
440     }
441     
442     /* (non-Javadoc)
443      *
444      * Override because we allow inserting with filters present.
445      *
446      * @see org.eclipse.jface.viewers.AbstractTreeViewer#insert(java.lang.Object, java.lang.Object, int)
447      */

448     public void insert(Object JavaDoc parentElementOrTreePath, Object JavaDoc element, int position) {
449         try {
450             fInserting = true;
451             super.insert(parentElementOrTreePath, element, position);
452         } finally {
453             fInserting = false;
454         }
455     }
456     
457     /* (non-Javadoc)
458      *
459      * Override because we allow inserting with filters present.
460      *
461      * @see org.eclipse.jface.viewers.StructuredViewer#hasFilters()
462      */

463     protected boolean hasFilters() {
464         if (fInserting) {
465             return false;
466         }
467         return super.hasFilters();
468     }
469     
470     /* (non-Javadoc)
471      * @see org.eclipse.jface.viewers.AbstractTreeViewer#inputChanged(java.lang.Object, java.lang.Object)
472      */

473     protected void inputChanged(Object JavaDoc input, Object JavaDoc oldInput) {
474         super.inputChanged(input, oldInput);
475         resetColumns(input);
476     }
477
478     /**
479      * Configures the columns for the given viewer input.
480      *
481      * @param input
482      */

483     protected void resetColumns(Object JavaDoc input) {
484         if (input != null) {
485             // only change columns if the input is non-null (persist when empty)
486
IColumnPresentationFactory factory = getColumnPresenetationFactoryAdapter(input);
487             PresentationContext context = (PresentationContext) getPresentationContext();
488             String JavaDoc type = null;
489             if (factory != null) {
490                 type = factory.getColumnPresentationId(context, input);
491             }
492             if (type != null) {
493                 if (fColumnPresentation != null) {
494                     if (!fColumnPresentation.getId().equals(type)) {
495                         // dispose old, create new
496
fColumnPresentation.dispose();
497                         fColumnPresentation = null;
498                     }
499                 }
500                 if (fColumnPresentation == null) {
501                     fColumnPresentation = factory.createColumnPresentation(context, input);
502                     if (fColumnPresentation != null) {
503                         fColumnPresentation.init(context);
504                         configureColumns();
505                     }
506                 }
507             } else {
508                 if (fColumnPresentation != null) {
509                     fColumnPresentation.dispose();
510                     fColumnPresentation = null;
511                     configureColumns();
512                 }
513             }
514         }
515     }
516     
517     /**
518      * Returns the column presentation factory for the given element or <code>null</code>.
519      *
520      * @param input
521      * @return column presentation factory of <code>null</code>
522      */

523     protected IColumnPresentationFactory getColumnPresenetationFactoryAdapter(Object JavaDoc input) {
524         if (input instanceof IColumnPresentationFactory) {
525             return (IColumnPresentationFactory) input;
526         }
527         if (input instanceof IAdaptable) {
528             IAdaptable adaptable = (IAdaptable) input;
529             return (IColumnPresentationFactory) adaptable.getAdapter(IColumnPresentationFactory.class);
530         }
531         return null;
532     }
533         
534     /**
535      * Configures the columns based on the current settings.
536      *
537      * @param input
538      */

539     protected void configureColumns() {
540         if (fColumnPresentation != null) {
541             IColumnPresentation build = null;
542             if (isShowColumns(fColumnPresentation.getId())) {
543                 build = fColumnPresentation;
544             }
545             buildColumns(build);
546         } else {
547             // get rid of columns
548
buildColumns(null);
549         }
550     }
551     
552     /**
553      * Toggles columns on/off for the current column presentation, if any.
554      *
555      * @param show whether to show columns if the current input supports
556      * columns
557      */

558     public void setShowColumns(boolean show) {
559         if (show) {
560             if (!isShowColumns()) {
561                 fShowColumns.remove(fColumnPresentation.getId());
562             }
563         } else {
564             if (isShowColumns()){
565                 fShowColumns.put(fColumnPresentation.getId(), Boolean.FALSE);
566             }
567         }
568         refreshColumns();
569     }
570     
571     /**
572      * Resets any persisted column size for the given columns
573      */

574     public void resetColumnSizes(String JavaDoc[] columnIds) {
575         for (int i = 0; i < columnIds.length; i++) {
576             fColumnSizes.remove(columnIds[i]);
577         }
578     }
579     
580     /**
581      * Sets the id's of visible columns, or <code>null</code> to set default columns.
582      * Only effects the current column presentation.
583      *
584      * @param ids visible columns
585      */

586     public void setVisibleColumns(String JavaDoc[] ids) {
587         if (ids != null && ids.length == 0) {
588             ids = null;
589         }
590         IColumnPresentation presentation = getColumnPresentation();
591         if (presentation != null) {
592             fColumnOrder.remove(presentation.getId());
593             fVisibleColumns.remove(presentation.getId());
594             if (ids != null) {
595                 // put back in table if not default
596
String JavaDoc[] columns = presentation.getInitialColumns();
597                 if (columns.length == ids.length) {
598                     for (int i = 0; i < columns.length; i++) {
599                         if (!ids[i].equals(columns[i])) {
600                             fVisibleColumns.put(presentation.getId(), ids);
601                             break;
602                         }
603                     }
604                 } else {
605                     fVisibleColumns.put(presentation.getId(), ids);
606                 }
607             }
608             PresentationContext presentationContext = (PresentationContext) getPresentationContext();
609             presentationContext.setColumns(getVisibleColumns());
610             refreshColumns();
611         }
612     }
613     
614     /**
615      * Refreshes the columns in the view, based on the viewer input.
616      */

617     protected void refreshColumns() {
618         configureColumns();
619         refresh();
620     }
621     
622     /**
623      * Returns whether columns are being displayed currently.
624      *
625      * @return
626      */

627     public boolean isShowColumns() {
628         if (fColumnPresentation != null) {
629             return isShowColumns(fColumnPresentation.getId());
630         }
631         return false;
632     }
633     
634     /**
635      * Returns whether columns can be toggled on/off for the current input.
636      *
637      * @return whether columns can be toggled on/off for the current input
638      */

639     public boolean canToggleColumns() {
640         return fColumnPresentation != null && fColumnPresentation.isOptional();
641     }
642     
643     protected boolean isShowColumns(String JavaDoc columnPresentationId) {
644         Boolean JavaDoc bool = (Boolean JavaDoc) fShowColumns.get(columnPresentationId);
645         if (bool == null) {
646             return true;
647         }
648         return bool.booleanValue();
649     }
650     
651     /**
652      * Creates new columns for the given presentation.
653      *
654      * TODO: does this need to be asynchronous?
655      *
656      * @param presentation
657      */

658     protected void buildColumns(IColumnPresentation presentation) {
659         // dispose current columns, persisting their weights
660
Tree tree = getTree();
661         final TreeColumn[] columns = tree.getColumns();
662         String JavaDoc[] visibleColumnIds = getVisibleColumns();
663         for (int i = 0; i < columns.length; i++) {
664             TreeColumn treeColumn = columns[i];
665             treeColumn.removeControlListener(fListener);
666             treeColumn.dispose();
667         }
668         PresentationContext presentationContext = (PresentationContext) getPresentationContext();
669         if (presentation != null) {
670             for (int i = 0; i < visibleColumnIds.length; i++) {
671                 String JavaDoc id = visibleColumnIds[i];
672                 String JavaDoc header = presentation.getHeader(id);
673                 // TODO: allow client to specify style
674
TreeColumn column = new TreeColumn(tree, SWT.LEFT, i);
675                 column.setMoveable(true);
676                 column.setText(header);
677                 column.setWidth(1);
678                 ImageDescriptor image = presentation.getImageDescriptor(id);
679                 if (image != null) {
680                     column.setImage(((TreeModelLabelProvider)getLabelProvider()).getImage(image));
681                 }
682                 column.setData(id);
683             }
684             int[] order = (int[]) fColumnOrder.get(presentation.getId());
685             if (order != null) {
686                 tree.setColumnOrder(order);
687             }
688             tree.setHeaderVisible(true);
689             tree.setLinesVisible(true);
690             presentationContext.setColumns(getVisibleColumns());
691             setColumnProperties(getVisibleColumns());
692             setCellModifier(fCellModifier);
693         } else {
694             tree.setHeaderVisible(false);
695             tree.setLinesVisible(false);
696             presentationContext.setColumns(null);
697             setCellModifier(null);
698             setColumnProperties(null);
699         }
700         
701
702         int avg = tree.getSize().x;
703         if (visibleColumnIds != null)
704             avg /= visibleColumnIds.length;
705         
706         if (avg == 0) {
707             tree.addPaintListener(new PaintListener() {
708                 public void paintControl(PaintEvent e) {
709                     Tree tree2 = getTree();
710                     String JavaDoc[] visibleColumns = getVisibleColumns();
711                     if (visibleColumns != null) {
712                         int avg1 = tree2.getSize().x / visibleColumns.length;
713                         initColumns(avg1);
714                     }
715                     tree2.removePaintListener(this);
716                 }
717             });
718         } else {
719             initColumns(avg);
720         }
721     }
722
723     private void initColumns(int widthHint) {
724         TreeColumn[] columns = getTree().getColumns();
725         for (int i = 0; i < columns.length; i++) {
726             TreeColumn treeColumn = columns[i];
727             Integer JavaDoc width = (Integer JavaDoc) fColumnSizes.get(treeColumn.getData());
728             if (width == null) {
729                 treeColumn.setWidth(widthHint);
730             } else {
731                 treeColumn.setWidth(width.intValue());
732             }
733             treeColumn.addControlListener(fListener);
734         }
735     }
736     
737     /**
738      * Returns the current column presentation for this viewer, or <code>null</code>
739      * if none.
740      *
741      * @return column presentation or <code>null</code>
742      */

743     public IColumnPresentation getColumnPresentation() {
744         return fColumnPresentation;
745     }
746     
747     /**
748      * Returns identifiers of the visible columns in this viewer, or <code>null</code>
749      * if there is currently no column presentation.
750      *
751      * @return visible columns or <code>null</code>
752      */

753     public String JavaDoc[] getVisibleColumns() {
754         if (isShowColumns()) {
755             IColumnPresentation presentation = getColumnPresentation();
756             if (presentation != null) {
757                 String JavaDoc[] columns = (String JavaDoc[]) fVisibleColumns.get(presentation.getId());
758                 if (columns == null) {
759                     return presentation.getInitialColumns();
760                 }
761                 return columns;
762             }
763         }
764         return null;
765     }
766     
767     /**
768      * Persists column sizes in cache
769      */

770     protected void persistColumnSizes() {
771         Tree tree = getTree();
772         TreeColumn[] columns = tree.getColumns();
773         for (int i = 0; i < columns.length; i++) {
774             TreeColumn treeColumn = columns[i];
775             Object JavaDoc id = treeColumn.getData();
776             fColumnSizes.put(id, new Integer JavaDoc(treeColumn.getWidth()));
777         }
778     }
779     
780     /**
781      * Persists column ordering
782      */

783     protected void persistColumnOrder() {
784         IColumnPresentation presentation = getColumnPresentation();
785         if (presentation != null) {
786             Tree tree = getTree();
787             int[] order = tree.getColumnOrder();
788             if (order.length > 0) {
789                 for (int i = 0; i < order.length; i++) {
790                     if (i != order[i]) {
791                         // non default order
792
fColumnOrder.put(presentation.getId(), order);
793                         return;
794                     }
795                 }
796             }
797             // default order
798
fColumnOrder.remove(presentation.getId());
799         }
800     }
801     
802     /**
803      * Save viewer state into the given memento.
804      *
805      * @param memento
806      */

807     public void saveState(IMemento memento) {
808         if (!fColumnSizes.isEmpty()) {
809             Iterator JavaDoc iterator = fColumnSizes.entrySet().iterator();
810             while (iterator.hasNext()) {
811                 Map.Entry JavaDoc entry = (Entry) iterator.next();
812                 IMemento sizes = memento.createChild(COLUMN_SIZES, (String JavaDoc)entry.getKey());
813                 sizes.putInteger(SIZE, ((Integer JavaDoc)entry.getValue()).intValue());
814             }
815         }
816         if (!fShowColumns.isEmpty()) {
817             Iterator JavaDoc iterator = fShowColumns.entrySet().iterator();
818             while (iterator.hasNext()) {
819                 Map.Entry JavaDoc entry = (Entry) iterator.next();
820                 IMemento sizes = memento.createChild(SHOW_COLUMNS, (String JavaDoc)entry.getKey());
821                 sizes.putString(SHOW_COLUMNS, ((Boolean JavaDoc)entry.getValue()).toString());
822             }
823         }
824         if (!fVisibleColumns.isEmpty()) {
825             Iterator JavaDoc iterator = fVisibleColumns.entrySet().iterator();
826             while (iterator.hasNext()) {
827                 Map.Entry JavaDoc entry = (Entry) iterator.next();
828                 String JavaDoc id = (String JavaDoc) entry.getKey();
829                 IMemento visible = memento.createChild(VISIBLE_COLUMNS, id);
830                 String JavaDoc[] columns = (String JavaDoc[]) entry.getValue();
831                 visible.putInteger(SIZE, columns.length);
832                 for (int i = 0; i < columns.length; i++) {
833                     visible.putString(COLUMN+Integer.toString(i), columns[i]);
834                 }
835             }
836         }
837         if (!fColumnOrder.isEmpty()) {
838             Iterator JavaDoc iterator = fColumnOrder.entrySet().iterator();
839             while (iterator.hasNext()) {
840                 Map.Entry JavaDoc entry = (Entry) iterator.next();
841                 String JavaDoc id = (String JavaDoc) entry.getKey();
842                 IMemento orderMemento = memento.createChild(COLUMN_ORDER, id);
843                 int[] order = (int[]) entry.getValue();
844                 orderMemento.putInteger(SIZE, order.length);
845                 for (int i = 0; i < order.length; i++) {
846                     orderMemento.putInteger(COLUMN+Integer.toString(i), order[i]);
847                 }
848             }
849         }
850     }
851     
852     /**
853      * Initializes viewer state from the memento
854      *
855      * @param memento
856      */

857     public void initState(IMemento memento) {
858         IMemento[] mementos = memento.getChildren(COLUMN_SIZES);
859         for (int i = 0; i < mementos.length; i++) {
860             IMemento child = mementos[i];
861             String JavaDoc id = child.getID();
862             Integer JavaDoc size = child.getInteger(SIZE);
863             if (size != null) {
864                 fColumnSizes.put(id, size);
865             }
866         }
867         mementos = memento.getChildren(SHOW_COLUMNS);
868         for (int i = 0; i < mementos.length; i++) {
869             IMemento child = mementos[i];
870             String JavaDoc id = child.getID();
871             Boolean JavaDoc bool = Boolean.valueOf(child.getString(SHOW_COLUMNS));
872             if (!bool.booleanValue()) {
873                 fShowColumns.put(id, bool);
874             }
875         }
876         mementos = memento.getChildren(VISIBLE_COLUMNS);
877         for (int i = 0; i < mementos.length; i++) {
878             IMemento child = mementos[i];
879             String JavaDoc id = child.getID();
880             Integer JavaDoc integer = child.getInteger(SIZE);
881             if (integer != null) {
882                 int length = integer.intValue();
883                 String JavaDoc[] columns = new String JavaDoc[length];
884                 for (int j = 0; j < length; j++) {
885                     columns[j] = child.getString(COLUMN+Integer.toString(j));
886                 }
887                 fVisibleColumns.put(id, columns);
888             }
889         }
890         mementos = memento.getChildren(COLUMN_ORDER);
891         for (int i = 0; i < mementos.length; i++) {
892             IMemento child = mementos[i];
893             String JavaDoc id = child.getID();
894             Integer JavaDoc integer = child.getInteger(SIZE);
895             if (integer != null) {
896                 int length = integer.intValue();
897                 int[] order = new int[length];
898                 for (int j = 0; j < length; j++) {
899                     order[j] = child.getInteger(COLUMN+Integer.toString(j)).intValue();
900                 }
901                 fColumnOrder.put(id, order);
902             }
903         }
904     }
905     
906     /**
907      * Returns whether the candidate selection should override the current
908      * selection.
909      *
910      * @param current
911      * @param curr
912      * @return
913      */

914     protected boolean overrideSelection(ISelection current, ISelection candidate) {
915         IModelSelectionPolicy selectionPolicy = getSelectionPolicy(current);
916         if (selectionPolicy == null) {
917             return true;
918         }
919         if (selectionPolicy.contains(candidate, getPresentationContext())) {
920             return selectionPolicy.overrides(current, candidate, getPresentationContext());
921         }
922         return !selectionPolicy.isSticky(current, getPresentationContext());
923     }
924     
925     /**
926      * Returns the selection policy associated with the given selection
927      * or <code>null</code> if none.
928      *
929      * @param selection or <code>null</code>
930      * @return selection policy or <code>null</code>
931      */

932     protected IModelSelectionPolicy getSelectionPolicy(ISelection selection) {
933         if (selection instanceof IStructuredSelection) {
934             IStructuredSelection ss = (IStructuredSelection) selection;
935             Object JavaDoc element = ss.getFirstElement();
936             if (element instanceof IAdaptable) {
937                 IAdaptable adaptable = (IAdaptable) element;
938                 IModelSelectionPolicyFactory factory = (IModelSelectionPolicyFactory) adaptable.getAdapter(IModelSelectionPolicyFactory.class);
939                 if (factory == null && !(element instanceof PlatformObject)) {
940                     // for objects that don't properly subclass PlatformObject to inherit default
941
// adapters, just delegate to the adapter factory
942
factory = (IModelSelectionPolicyFactory) new DebugElementAdapterFactory().getAdapter(element, IModelSelectionPolicyFactory.class);
943                 }
944                 if (factory != null) {
945                     return factory.createModelSelectionPolicyAdapter(adaptable, getPresentationContext());
946                 }
947             }
948         }
949         return null;
950     }
951
952     /* (non-Javadoc)
953      *
954      * Consider selection policy
955      *
956      * @see org.eclipse.jface.viewers.StructuredViewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean)
957      */

958     public void setSelection(ISelection selection, boolean reveal) {
959         if (!overrideSelection(getSelection(), selection)) {
960             return;
961         }
962         super.setSelection(selection, reveal);
963     }
964     
965     /**
966      * Sets the selection in the viewer to the specified selection.
967      *
968      * @param selection the selection
969      * @param reveal whether to reveal the selection
970      * @param force whether to force the selection (i.e. <code>true</code> to
971      * override the model selection policy)
972      */

973     public void setSelection(ISelection selection, boolean reveal, boolean force) {
974         if (force) {
975             super.setSelection(selection, reveal);
976         } else {
977             setSelection(selection, reveal);
978         }
979     }
980     
981     /**
982      * Registers the specified listener for view update notifications.
983      *
984      * @param listener listener
985      */

986     public void addViewerUpdateListener(IViewerUpdateListener listener) {
987         ((ModelContentProvider)getContentProvider()).addViewerUpdateListener(listener);
988     }
989     
990     /**
991      * Removes the specified listener from update notifications.
992      *
993      * @param listener listener
994      */

995     public void removeViewerUpdateListener(IViewerUpdateListener listener) {
996         ModelContentProvider cp = (ModelContentProvider)getContentProvider();
997         if (cp != null) {
998             cp.removeViewerUpdateListener(listener);
999         }
1000    }
1001    
1002    /**
1003     * Registers the given listener for model delta notification.
1004     *
1005     * @param listener model delta listener
1006     */

1007    public void addModelChangedListener(IModelChangedListener listener) {
1008        ((ModelContentProvider)getContentProvider()).addModelChangedListener(listener);
1009    }
1010    
1011    /**
1012     * Unregisters the given listener from model delta notification.
1013     *
1014     * @param listener model delta listener
1015     */

1016    public void removeModelChangedListener(IModelChangedListener listener) {
1017        ModelContentProvider cp = (ModelContentProvider)getContentProvider();
1018        if (cp != null) {
1019            cp.removeModelChangedListener(listener);
1020        }
1021    }
1022    
1023    /*
1024     * (non-Javadoc) Method declared in AbstractTreeViewer.
1025     */

1026    protected void doUpdateItem(final Item item, Object JavaDoc element) {
1027        if (!(item instanceof TreeItem)) {
1028            return;
1029        }
1030        TreeItem treeItem = (TreeItem) item;
1031        if (treeItem.isDisposed()) {
1032            unmapElement(element, treeItem);
1033            return;
1034        }
1035        
1036        ((TreeModelLabelProvider)getLabelProvider()).update(getTreePathFromItem(item), getViewerRowFromItem(treeItem));
1037
1038        // As it is possible for user code to run the event
1039
// loop check here.
1040
if (item.isDisposed()) {
1041            unmapElement(element, item);
1042        }
1043    }
1044    
1045    /**
1046     * Forces unmapped virtual items to populate
1047     */

1048    boolean populateVitrualItems() {
1049        Tree tree = getTree();
1050        return populateVitrualItems(TreePath.EMPTY, tree.getItems());
1051    }
1052
1053    /**
1054     * @param items
1055     */

1056    private boolean populateVitrualItems(TreePath parentPath, TreeItem[] items) {
1057        boolean queued = false;
1058        for (int i = 0; i < items.length; i++) {
1059            TreeItem treeItem = items[i];
1060            if (treeItem.getData() == null) {
1061                queued = true;
1062                ((ILazyTreePathContentProvider)getContentProvider()).updateElement(parentPath, i);
1063            }
1064            if (treeItem.getExpanded()) {
1065                queued = populateVitrualItems(parentPath.createChildPath(treeItem.getData()), treeItem.getItems()) | queued;
1066            }
1067        }
1068        return queued;
1069    }
1070    
1071    void addLabelUpdateListener(ILabelUpdateListener listener) {
1072        ((TreeModelLabelProvider)getLabelProvider()).addLabelUpdateListener(listener);
1073    }
1074    
1075    void removeLabelUpdateListener(ILabelUpdateListener listener) {
1076        ((TreeModelLabelProvider)getLabelProvider()).removeLabelUpdateListener(listener);
1077    }
1078    
1079    /**
1080     * Returns the item for the element at the given tree path or <code>null</code>
1081     * if none.
1082     *
1083     * @param path tree path
1084     * @return item or <code>null</code>
1085     */

1086    Widget findItem(TreePath path) {
1087        if (path.getSegmentCount() == 0) {
1088            return getTree();
1089        }
1090        Widget[] items = super.findItems(path.getLastSegment());
1091        if (items.length == 1) {
1092            return items[0];
1093        }
1094        for (int i = 0; i < items.length; i++) {
1095            if (getTreePathFromItem((Item)items[i]).equals(path)) {
1096                return items[i];
1097            }
1098        }
1099        return null;
1100    }
1101    
1102    public Item[] getChildren(Widget widget) {
1103        return super.getChildren(widget);
1104    }
1105    
1106    /**
1107     * Returns the tree path for the given item.
1108     * @param item
1109     * @return {@link TreePath}
1110     */

1111    protected TreePath getTreePathFromItem(Item item) {
1112        return super.getTreePathFromItem(item);
1113    }
1114
1115//**************************************************************************
1116
// These methods were copied from TreeViewer as a workaround for bug 183463:
1117
// Expanded nodes in tree viewer flash on refresh
1118

1119    /*
1120     * (non-Javadoc)
1121     *
1122     * workaround for bug 183463
1123     *
1124     * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefreshStruct(org.eclipse.swt.widgets.Widget,
1125     * java.lang.Object, boolean)
1126     */

1127    protected void internalRefreshStruct(Widget widget, Object JavaDoc element,
1128            boolean updateLabels) {
1129        // clear all starting with the given widget
1130
if (widget instanceof Tree) {
1131            ((Tree) widget).clearAll(true);
1132        } else if (widget instanceof TreeItem) {
1133            ((TreeItem) widget).clearAll(true);
1134        }
1135        int index = 0;
1136        Widget parent = null;
1137        if (widget instanceof TreeItem) {
1138            TreeItem treeItem = (TreeItem) widget;
1139            parent = treeItem.getParentItem();
1140            if (parent == null) {
1141                parent = treeItem.getParent();
1142            }
1143            if (parent instanceof Tree) {
1144                index = ((Tree) parent).indexOf(treeItem);
1145            } else {
1146                index = ((TreeItem) parent).indexOf(treeItem);
1147            }
1148        }
1149        virtualRefreshExpandedItems(parent, widget, element, index);
1150    }
1151    
1152    /**
1153     * Traverses the visible (expanded) part of the tree and updates child
1154     * counts.
1155     * <p>
1156     * workaround for bug 183463
1157     * </p>
1158     * @param parent the parent of the widget, or <code>null</code> if the widget is the tree
1159     * @param widget
1160     * @param element
1161     * @param index the index of the widget in the children array of its parent, or 0 if the widget is the tree
1162     */

1163    private void virtualRefreshExpandedItems(Widget parent, Widget widget, Object JavaDoc element, int index) {
1164        if (widget instanceof Tree) {
1165            if (element == null) {
1166                ((Tree) widget).setItemCount(0);
1167                return;
1168            }
1169            virtualLazyUpdateChildCount(widget, getChildren(widget).length);
1170        } else if (((TreeItem) widget).getExpanded()) {
1171            // prevent SetData callback
1172
preserveItem((TreeItem)widget);
1173            //((TreeItem)widget).setText(" "); //$NON-NLS-1$
1174
virtualLazyUpdateWidget(parent, index);
1175        } else {
1176            return;
1177        }
1178        Item[] items = getChildren(widget);
1179        for (int i = 0; i < items.length; i++) {
1180            Item item = items[i];
1181            Object JavaDoc data = item.getData();
1182            virtualRefreshExpandedItems(widget, item, data, i);
1183        }
1184    }
1185    
1186    /**
1187     * workaround for bug 183463
1188     *
1189     * Update the child count
1190     * @param widget
1191     * @param currentChildCount
1192     */

1193    private void virtualLazyUpdateChildCount(Widget widget, int currentChildCount) {
1194        TreePath treePath;
1195        if (widget instanceof Item) {
1196            treePath = getTreePathFromItem((Item) widget);
1197        } else {
1198            treePath = TreePath.EMPTY;
1199        }
1200        ((ILazyTreePathContentProvider) getContentProvider())
1201                .updateChildCount(treePath, currentChildCount);
1202    }
1203    
1204    /**
1205     * Update the widget at index.
1206     * <p>
1207     * workaround for bug 183463
1208     * </p>
1209     * @param widget
1210     * @param index
1211     */

1212    private void virtualLazyUpdateWidget(Widget widget, int index) {
1213        TreePath treePath;
1214        if (widget instanceof Item) {
1215            if (widget.getData() == null) {
1216                // we need to materialize the parent first
1217
// see bug 167668
1218
// however, that would be too risky
1219
// see bug 182782 and bug 182598
1220
// so we just ignore this call altogether
1221
// and don't do this: virtualMaterializeItem((TreeItem) widget);
1222
return;
1223            }
1224            treePath = getTreePathFromItem((Item) widget);
1225        } else {
1226            treePath = TreePath.EMPTY;
1227        }
1228        ((ILazyTreePathContentProvider) getContentProvider())
1229                .updateElement(treePath, index);
1230    }
1231}
1232
Popular Tags