001: /*******************************************************************************
002: * Copyright (c) 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: ******************************************************************************/package org.eclipse.ui.internal.provisional.views.markers;
011:
012: import java.util.ArrayList;
013: import java.util.Collection;
014: import java.util.HashMap;
015: import java.util.HashSet;
016: import java.util.Iterator;
017: import java.util.List;
018:
019: import org.eclipse.jface.dialogs.Dialog;
020: import org.eclipse.jface.viewers.CheckStateChangedEvent;
021: import org.eclipse.jface.viewers.CheckboxTreeViewer;
022: import org.eclipse.jface.viewers.ColumnWeightData;
023: import org.eclipse.jface.viewers.ICheckStateListener;
024: import org.eclipse.jface.viewers.ITreeContentProvider;
025: import org.eclipse.jface.viewers.LabelProvider;
026: import org.eclipse.jface.viewers.TableLayout;
027: import org.eclipse.jface.viewers.Viewer;
028: import org.eclipse.jface.viewers.ViewerComparator;
029: import org.eclipse.swt.SWT;
030: import org.eclipse.swt.events.SelectionEvent;
031: import org.eclipse.swt.events.SelectionListener;
032: import org.eclipse.swt.layout.GridData;
033: import org.eclipse.swt.layout.GridLayout;
034: import org.eclipse.swt.widgets.Button;
035: import org.eclipse.swt.widgets.Composite;
036: import org.eclipse.swt.widgets.Tree;
037: import org.eclipse.swt.widgets.TreeColumn;
038: import org.eclipse.ui.internal.provisional.views.markers.api.MarkerFieldFilter;
039: import org.eclipse.ui.views.markers.internal.MarkerMessages;
040: import org.eclipse.ui.views.markers.internal.MarkerSupportRegistry;
041: import org.eclipse.ui.views.markers.internal.MarkerType;
042:
043: /**
044: * TypesConfigurationArea is the FilterConfigurationArea that handles type
045: * selection for the filter.
046: *
047: * @since 3.4
048: *
049: */
050: public class TypesConfigurationArea extends
051: GroupFilterConfigurationArea {
052:
053: private class CategoryEntry extends TypesEntry {
054:
055: private Collection children = new ArrayList();
056: private String name;
057:
058: /**
059: * Create a new instance of the receiver.
060: *
061: * @param categoryName
062: */
063: public CategoryEntry(String categoryName) {
064: name = categoryName;
065: }
066:
067: /**
068: * Add the node to the receiver.
069: *
070: * @param node
071: */
072: public void add(MarkerTypeEntry node) {
073: children.add(node);
074: node.setParent(this );
075:
076: }
077:
078: /*
079: * (non-Javadoc)
080: *
081: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#addElementsMatching(java.util.Collection,
082: * java.util.Collection)
083: */
084: public void addElementsMatching(Collection selectedTypes,
085: Collection entries) {
086: Iterator childIterator = children.iterator();
087: while (childIterator.hasNext()) {
088: ((MarkerTypeEntry) childIterator.next())
089: .addElementsMatching(selectedTypes, entries);
090: }
091:
092: }
093:
094: /*
095: * (non-Javadoc)
096: *
097: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#getChildren()
098: */
099: public Collection getChildren() {
100: return children;
101: }
102:
103: /*
104: * (non-Javadoc)
105: *
106: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#getLabel()
107: */
108: public String getLabel() {
109: return name;
110: }
111:
112: /*
113: * (non-Javadoc)
114: *
115: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#getParent()
116: */
117: public TypesEntry getParent() {
118: return null;
119: }
120:
121: /*
122: * (non-Javadoc)
123: *
124: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#hasChildren()
125: */
126: public boolean hasChildren() {
127: return children.size() > 0;
128: }
129:
130: }
131:
132: private class MarkerTypeEntry extends TypesEntry {
133:
134: private CategoryEntry category;
135: private MarkerType markerType;
136:
137: /**
138: * Create an instance of the receiver.
139: *
140: * @param markerType
141: */
142: public MarkerTypeEntry(MarkerType markerType) {
143: this .markerType = markerType;
144: }
145:
146: /*
147: * (non-Javadoc)
148: *
149: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#addElementsMatching(java.util.Collection,
150: * java.util.Collection)
151: */
152: public void addElementsMatching(Collection selectedTypes,
153: Collection entries) {
154: if (selectedTypes.contains(markerType))
155: entries.add(this );
156:
157: }
158:
159: /*
160: * (non-Javadoc)
161: *
162: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#getChildren()
163: */
164: public Collection getChildren() {
165: return EMPTY_COLLECTION;
166: }
167:
168: /*
169: * (non-Javadoc)
170: *
171: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#getLabel()
172: */
173: public String getLabel() {
174: return markerType.getLabel();
175: }
176:
177: /**
178: * Return the marker type for the receiver.
179: *
180: * @return MarkerType
181: */
182: public MarkerType getMarkerType() {
183: return markerType;
184: }
185:
186: /*
187: * (non-Javadoc)
188: *
189: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#getParent()
190: */
191: public TypesEntry getParent() {
192: return category;
193: }
194:
195: /*
196: * (non-Javadoc)
197: *
198: * @see org.eclipse.ui.internal.provisional.views.markers.TypesConfigurationArea.TypesEntry#hasChildren()
199: */
200: public boolean hasChildren() {
201: return false;
202: }
203:
204: /**
205: * Set the category of the receiver.
206: *
207: * @param categoryEntry
208: */
209: public void setParent(CategoryEntry categoryEntry) {
210: category = categoryEntry;
211:
212: }
213:
214: }
215:
216: private abstract class TypesEntry {
217:
218: /**
219: * Add any elements that contain a type in selectedTypes tp entries.
220: *
221: * @param selectedTypes
222: * @param entries
223: */
224: public abstract void addElementsMatching(
225: Collection selectedTypes, Collection entries);
226:
227: /**
228: * Return the children of the receiver.
229: *
230: * @return TypesEntry[]
231: */
232: public abstract Collection getChildren();
233:
234: /**
235: * Return the label for the receiver.
236: *
237: * @return String
238: */
239: public abstract String getLabel();
240:
241: /**
242: * Return the parent of the receiver.
243: *
244: * @return
245: */
246: public abstract TypesEntry getParent();
247:
248: /**
249: * Return whether or not the receiver has children.
250: *
251: * @return boolean
252: */
253: public abstract boolean hasChildren();
254:
255: }
256:
257: private static Collection EMPTY_COLLECTION = new HashSet();
258:
259: private HashMap models = new HashMap(0);
260:
261: private CheckboxTreeViewer typesViewer;
262:
263: /*
264: * (non-Javadoc)
265: *
266: * @see org.eclipse.ui.internal.provisional.views.markers.api.FilterConfigurationArea#apply(org.eclipse.ui.internal.provisional.views.markers.api.MarkerFieldFilter)
267: */
268: public void apply(MarkerFieldFilter filter) {
269: Collection selectedTypes = new ArrayList();
270: Object[] elements = typesViewer.getCheckedElements();
271: for (int i = 0; i < elements.length; i++) {
272: if (elements[i] instanceof MarkerTypeEntry)
273: selectedTypes.add(((MarkerTypeEntry) elements[i])
274: .getMarkerType());
275: }
276: ((MarkerTypeFieldFilter) filter)
277: .setSelectedTypes(selectedTypes);
278:
279: }
280:
281: /*
282: * (non-Javadoc)
283: *
284: * @see org.eclipse.ui.internal.provisional.views.markers.FilterConfigurationArea#applyToGroup(org.eclipse.ui.internal.provisional.views.markers.MarkerFieldFilterGroup)
285: */
286: public void applyToGroup(MarkerFieldFilterGroup group) {
287: // Nothing to set at the group level
288: }
289:
290: /*
291: * (non-Javadoc)
292: *
293: * @see org.eclipse.ui.internal.provisional.views.markers.FilterConfigurationArea#createContents(org.eclipse.swt.widgets.Composite)
294: */
295: public void createContents(Composite parent) {
296:
297: Composite composite = new Composite(parent, SWT.NONE);
298: composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
299: true));
300: GridLayout layout = new GridLayout();
301: layout.numColumns = 2;
302: composite.setLayout(layout);
303:
304: Tree tree = new Tree(composite, SWT.CHECK | SWT.H_SCROLL
305: | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION
306: | SWT.BORDER);
307: tree.setLinesVisible(true);
308: tree.setHeaderVisible(false);
309: TableLayout tableLayout = new TableLayout();
310: tree.setLayout(tableLayout);
311: tableLayout.addColumnData(new ColumnWeightData(100, true));
312: new TreeColumn(tree, SWT.NONE, 0);
313:
314: typesViewer = new CheckboxTreeViewer(tree);
315: initializeFontMetrics(tree);
316:
317: GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
318: gridData.widthHint = Dialog.convertVerticalDLUsToPixels(
319: getFontMetrics(), 100);
320: gridData.heightHint = Dialog.convertVerticalDLUsToPixels(
321: getFontMetrics(), 75);
322:
323: final ITreeContentProvider typesContentProvider = getTypesContentProvider();
324: typesViewer.getControl().setLayoutData(gridData);
325: typesViewer.setContentProvider(typesContentProvider);
326: typesViewer.setLabelProvider(new LabelProvider() {
327: /*
328: * (non-Javadoc)
329: *
330: * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
331: */
332: public String getText(Object element) {
333: return ((TypesEntry) element).getLabel();
334: }
335: });
336: typesViewer.setComparator(new ViewerComparator() {
337: /*
338: * (non-Javadoc)
339: *
340: * @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer,
341: * java.lang.Object, java.lang.Object)
342: */
343: public int compare(Viewer viewer, Object e1, Object e2) {
344: return ((TypesEntry) e1).getLabel().compareTo(
345: ((TypesEntry) e2).getLabel());
346: }
347: });
348: typesViewer.addCheckStateListener(new ICheckStateListener() {
349: public void checkStateChanged(CheckStateChangedEvent event) {
350: Object element = event.getElement();
351: boolean checked = event.getChecked();
352: setChildrenChecked(element, checked);
353: setParentCheckState(element, checked);
354: }
355:
356: /**
357: * Set the check state of the children of element to
358: * <code>true</code>.
359: *
360: * @param element
361: * @param checked
362: */
363: private void setChildrenChecked(Object element,
364: boolean checked) {
365:
366: Object[] children = typesContentProvider
367: .getChildren(element);
368: if (children.length > 0) {
369: for (int i = 0; i < children.length; i++) {
370: typesViewer.setChecked(children[i], checked);
371: }
372: }
373:
374: }
375:
376: /**
377: * Update the parent check state based on the state of the element
378: *
379: * @param element
380: * @param checked
381: */
382: private void setParentCheckState(Object element,
383: boolean checked) {
384:
385: Object parent = typesContentProvider.getParent(element);
386: if (parent == null)
387: return;
388:
389: Object[] children = typesContentProvider
390: .getChildren(parent);
391:
392: for (int i = 0; i < children.length; i++) {// At least one
393: // different
394: if (typesViewer.getChecked(children[i]) != checked) {
395: typesViewer.setGrayChecked(parent, true);
396: return;
397: }
398: }
399: // All are the same - update the parent
400: typesViewer.setChecked(parent, checked);
401:
402: }
403: });
404:
405: Composite buttonComposite = new Composite(composite, SWT.NONE);
406: GridLayout buttonLayout = new GridLayout();
407: buttonLayout.marginWidth = 0;
408: buttonComposite.setLayout(buttonLayout);
409: GridData buttonsData = new GridData();
410: buttonsData.verticalAlignment = GridData.BEGINNING;
411: buttonComposite.setLayoutData(buttonsData);
412:
413: Button selectAllButton = new Button(buttonComposite, SWT.PUSH);
414: selectAllButton
415: .setText(MarkerMessages.filtersDialog_selectAllTypes);
416: selectAllButton.addSelectionListener(new SelectionListener() {
417: /*
418: * (non-Javadoc)
419: *
420: * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
421: */
422: public void widgetDefaultSelected(SelectionEvent e) {
423:
424: }
425:
426: /*
427: * (non-Javadoc)
428: *
429: * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
430: */
431: public void widgetSelected(SelectionEvent e) {
432: typesViewer.setAllChecked(true);
433: }
434: });
435: setButtonLayoutData(selectAllButton);
436:
437: Button deselectAllButton = new Button(buttonComposite, SWT.PUSH);
438: deselectAllButton
439: .setText(MarkerMessages.filtersDialog_deselectAllTypes);
440: deselectAllButton
441: .addSelectionListener(getSelectionButtonListener(false));
442: setButtonLayoutData(deselectAllButton);
443: }
444:
445: /**
446: * Return the elements for MarkerFieldFilterGroup groip.
447: *
448: * @param group
449: * @return List of TypesEntry
450: */
451: protected List elementsForGroup(MarkerFieldFilterGroup group) {
452:
453: if (models.containsKey(group))
454: return (List) models.get(group);
455: Iterator roots = group.getAllTypes().iterator();
456: List markerNodes = new ArrayList();
457: HashMap categories = new HashMap();
458: while (roots.hasNext()) {
459: MarkerType markerType = (MarkerType) roots.next();
460:
461: String categoryName = MarkerSupportRegistry.getInstance()
462: .getCategory(markerType.getId());
463:
464: if (categoryName == null) {
465: markerNodes.add(new MarkerTypeEntry(markerType));
466: } else {
467: CategoryEntry category;
468: if (categories.containsKey(categoryName)) {
469: category = (CategoryEntry) categories
470: .get(categoryName);
471: } else {
472: category = new CategoryEntry(categoryName);
473: categories.put(categoryName, category);
474: markerNodes.add(category);
475: }
476: MarkerTypeEntry node = new MarkerTypeEntry(markerType);
477: category.add(node);
478: }
479:
480: }
481: models.put(group, markerNodes);
482: return markerNodes;
483: }
484:
485: /**
486: * Find the type entries for group that correspond to it's current selection
487: * and add them to the checked or grey checked lists as appropriate.
488: *
489: * @param group
490: * @param entries
491: * @param greyEntries
492: */
493: private void findTypeEntries(MarkerFieldFilterGroup group,
494: Collection entries, Collection greyEntries) {
495: Iterator elements = elementsForGroup(group).iterator();
496:
497: Collection selectedTypes = ((MarkerTypeFieldFilter) group
498: .getFilter(this .getField())).getSelectedTypes();
499: while (elements.hasNext()) {
500: TypesEntry entry = (TypesEntry) elements.next();
501: entry.addElementsMatching(selectedTypes, entries);
502: if (entry.hasChildren()) {// Is it a category?
503: Collection children = entry.getChildren();
504: if (entries.containsAll(children))
505: entries.add(entry);
506: else {// See if we need to gray check it
507: Iterator iterator = children.iterator();
508: while (iterator.hasNext()) {
509: if (entries.contains(iterator.next())) {
510: greyEntries.add(entry);
511: break;
512: }
513: }
514: }
515: }
516:
517: }
518: }
519:
520: /**
521: * Get a listener for the button selection of a checked button.
522: *
523: * @param checkAll
524: * @return SelectionListener
525: */
526: private SelectionListener getSelectionButtonListener(
527: final boolean checkAll) {
528: return new SelectionListener() {
529: /*
530: * (non-Javadoc)
531: *
532: * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
533: */
534: public void widgetDefaultSelected(SelectionEvent e) {
535:
536: }
537:
538: /*
539: * (non-Javadoc)
540: *
541: * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
542: */
543: public void widgetSelected(SelectionEvent e) {
544: typesViewer.setAllChecked(checkAll);
545: }
546: };
547: }
548:
549: /**
550: * Get the content provider for the types.
551: *
552: * @return ITreeContentProvider
553: */
554: private ITreeContentProvider getTypesContentProvider() {
555: return new ITreeContentProvider() {
556:
557: /*
558: * (non-Javadoc)
559: *
560: * @see org.eclipse.jface.viewers.IContentProvider#dispose()
561: */
562: public void dispose() {
563: }
564:
565: /*
566: * (non-Javadoc)
567: *
568: * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
569: */
570: public Object[] getChildren(Object parentElement) {
571: return ((TypesEntry) parentElement).getChildren()
572: .toArray();
573: }
574:
575: /*
576: * (non-Javadoc)
577: *
578: * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
579: */
580: public Object[] getElements(Object inputElement) {
581: return elementsForGroup(
582: (MarkerFieldFilterGroup) inputElement)
583: .toArray();
584: }
585:
586: /*
587: * (non-Javadoc)
588: *
589: * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
590: */
591: public Object getParent(Object element) {
592: return ((TypesEntry) element).getParent();
593: }
594:
595: /*
596: * (non-Javadoc)
597: *
598: * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
599: */
600: public boolean hasChildren(Object element) {
601: return ((TypesEntry) element).hasChildren();
602: }
603:
604: /*
605: * (non-Javadoc)
606: *
607: * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
608: * java.lang.Object, java.lang.Object)
609: */
610: public void inputChanged(Viewer viewer, Object oldInput,
611: Object newInput) {
612: }
613: };
614: }
615:
616: /* (non-Javadoc)
617: * @see org.eclipse.ui.internal.provisional.views.markers.api.FilterConfigurationArea#initialize(org.eclipse.ui.internal.provisional.views.markers.api.MarkerFieldFilter)
618: */
619: public void initialize(MarkerFieldFilter filter) {
620: // This was already done when initialising from the group.
621:
622: }
623:
624: /*
625: * (non-Javadoc)
626: *
627: * @see org.eclipse.ui.internal.provisional.views.markers.FilterConfigurationArea#initializeFromGroup(org.eclipse.ui.internal.provisional.views.markers.MarkerFieldFilterGroup)
628: */
629: public void initializeFromGroup(MarkerFieldFilterGroup group) {
630: typesViewer.setInput(group);
631: typesViewer.refresh();
632: Collection checked = new HashSet();
633: Collection greyed = new HashSet();
634: findTypeEntries(group, checked, greyed);
635: typesViewer.setCheckedElements(checked.toArray());
636: typesViewer.setGrayedElements(greyed.toArray());
637: }
638:
639: }
|