001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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: * Darrell Meyer <darrell@mygwt.net> - derived implementation
011: * Tom Schindl <tom.schindl@bestsolution.at> - fix in issue: 38
012: *******************************************************************************/package net.mygwt.ui.client.viewer;
013:
014: import java.util.ArrayList;
015: import java.util.List;
016:
017: import net.mygwt.ui.client.Events;
018: import net.mygwt.ui.client.event.BaseEvent;
019: import net.mygwt.ui.client.event.Listener;
020: import net.mygwt.ui.client.util.Observable;
021: import net.mygwt.ui.client.widget.Component;
022:
023: import com.google.gwt.user.client.ui.Widget;
024:
025: /**
026: * A Viewer is a model-based adapter for a <code>Widget</code>. Supports
027: * custom sorting, filtering.
028: */
029: public abstract class Viewer extends Observable implements
030: ISelectionProvider {
031:
032: /**
033: * This viewer's input, or <code>null</code> if none. The viewer's input
034: * provides the "model" for the viewer's content.
035: */
036: protected Object input;
037:
038: protected Object[] elements;
039:
040: private IElementComparer comparer;
041: private IBaseLabelProvider labelProvider;
042: private IContentProvider contentProvider;
043: private List filters;
044: private ViewerSorter sorter;
045: private List selectionListeners;
046:
047: /**
048: * Adds the given filter to this viewer, and triggers refiltering and
049: * resorting of the elements.
050: *
051: * @param filter the filter to be added
052: */
053: public void addFilter(ViewerFilter filter) {
054: if (filters == null) {
055: filters = new ArrayList();
056: }
057: filters.add(filter);
058: applyFilters();
059: }
060:
061: /**
062: * Applies the viewer's filters.
063: */
064: public void applyFilters() {
065: if (elements == null)
066: return;
067: int count = elements.length;
068: for (int i = 0; i < count; i++) {
069: Widget w = findItem(elements[i]);
070: if (w != null) {
071: w.setVisible(!isFiltered(null, elements[i]));
072: }
073: }
074: }
075:
076: public void addSelectionListener(ISelectionChangedListener listener) {
077: if (selectionListeners == null) {
078: selectionListeners = new ArrayList();
079: }
080: if (!selectionListeners.contains(listener)) {
081: selectionListeners.add(listener);
082: }
083: }
084:
085: /**
086: * Finds the widget which represents the given element.
087: *
088: * @param elem the element
089: * @return the corresponding widget, or <code>null</code> if none
090: */
091: public abstract Widget findItem(Object elem);
092:
093: /**
094: * Returns the comparer to use for comparing elements, or <code>null</code>
095: * if none has been set. If specified, the viewer uses this to compare and
096: * hash elements rather than the elements' own equals and hashCode methods.
097: *
098: * @return the comparer to use for comparing elements or <code>null</code>
099: */
100: public IElementComparer getComparer() {
101: return comparer;
102: }
103:
104: /**
105: * Returns the viewer's content provider.
106: *
107: * @return the content provider
108: */
109: public IContentProvider getContentProvider() {
110: return contentProvider;
111: }
112:
113: public Object[] getElements() {
114: return elements;
115: }
116:
117: /**
118: * Returns the active elements in the order being displayed.
119: *
120: * @return the active elements
121: */
122: public Object[] getActiveElements() {
123: ArrayList list = new ArrayList();
124: int count = elements.length;
125: for (int i = 0; i < count; i++) {
126: if (!isFiltered(null, elements[i])) {
127: list.add(elements[i]);
128: }
129: }
130: return list.toArray();
131: }
132:
133: /**
134: * Returns the viewer's filters.
135: *
136: * @return the filters
137: */
138: public ViewerFilter[] getFilters() {
139: if (filters == null) {
140: return new ViewerFilter[0];
141: }
142: ViewerFilter[] result = new ViewerFilter[filters.size()];
143: filters.toArray(result);
144: return result;
145: }
146:
147: /**
148: * Returns the viewer's input.
149: *
150: * @return the input
151: */
152: public Object getInput() {
153: return input;
154: }
155:
156: /**
157: * Returns the viewer's label provider.
158: *
159: * @return the label provider
160: */
161: public IBaseLabelProvider getLabelProvider() {
162: return labelProvider;
163: }
164:
165: /**
166: * Returns the current selection for this provider.
167: *
168: * @return the current selection
169: */
170: public ISelection getSelection() {
171: Widget widget = getWidget();
172: if (widget == null) {
173: return DefaultSelection.EMPTY;
174: }
175: List elements = getSelectedFromWidget();
176: return new DefaultSelection(elements);
177: }
178:
179: /**
180: * Returns this viewer's sorter, or <code>null</code> if it does not have
181: * one.
182: *
183: * @return a viewer sorter, or <code>null</code> if none
184: */
185: public ViewerSorter getSorter() {
186: return sorter;
187: }
188:
189: /**
190: * Returns the primary widget associated with this viewer.
191: *
192: * @return the widget which displays this viewer's content
193: */
194: public abstract Widget getWidget();
195:
196: /**
197: * Returns <code>true</code> if the element is filtered. Filtered elements
198: * will not be displayed by the viewer.
199: *
200: * @param parent the parent element
201: * @param elem the element to test
202: * @return <code>true</code> if the element is filtered
203: */
204: public boolean isFiltered(Object parent, Object elem) {
205: if (filters != null) {
206: for (int i = 0; i < filters.size(); i++) {
207: ViewerFilter filter = (ViewerFilter) filters.get(i);
208: boolean result = filter.select(this , parent, elem);
209: if (!result) {
210: return true;
211: }
212: }
213: }
214: return false;
215: }
216:
217: protected void preserveSelections(ISelection selection) {
218:
219: }
220:
221: /**
222: * Refreshes this viewer completely with information freshly obtained from
223: * this viewer's model.
224: */
225: public void refresh() {
226: DefaultSelection sel = (DefaultSelection) getSelection();
227: if (input != null) {
228: setInput(input);
229: }
230: preserveSelections(sel);
231: setSelection(sel);
232: }
233:
234: /**
235: * Removes the element.
236: *
237: * @param elem the element to be removed
238: */
239: public abstract void remove(Object elem);
240:
241: /**
242: * Removes the given filter from this viewer, and triggers refiltering and
243: * resorting of the elements if required.
244: *
245: * @param filter the filter to be removed
246: */
247: public void removeFilter(ViewerFilter filter) {
248: if (filters != null && filters.contains(filter)) {
249: filters.remove(filter);
250: refresh();
251: }
252: }
253:
254: public void removeSelectionListener(
255: ISelectionChangedListener listener) {
256: if (selectionListeners != null) {
257: selectionListeners.remove(listener);
258: }
259: }
260:
261: /**
262: * Sets the comparer to use for comparing elements, or <code>null</code> to
263: * use the default equals and hashCode methods on the elements themselves.
264: *
265: * @param comparer the comparer to use for comparing elements or null
266: */
267: public void setComparer(IElementComparer comparer) {
268: this .comparer = comparer;
269: }
270:
271: /**
272: * Sets the viewer's content provider.
273: *
274: * @param contentProvider the new content provider
275: */
276: public void setContentProvider(IContentProvider contentProvider) {
277: this .contentProvider = contentProvider;
278: }
279:
280: /**
281: * Sets the viewer's input.
282: *
283: * @param input the new input
284: */
285: public void setInput(final Object input) {
286: contentProvider.inputChanged(this , this .input, input);
287: IStructuredContentProvider cp = (IStructuredContentProvider) contentProvider;
288: cp.getElements(input, new IAsyncContentCallback() {
289: public void setElements(Object[] elems) {
290: elements = elems;
291: onInputReceived(input);
292: }
293: });
294: this .input = input;
295: }
296:
297: /**
298: * Sets the viewer's label provider.
299: *
300: * @param labelProvider the new label provider
301: */
302: public void setLabelProvider(IBaseLabelProvider labelProvider) {
303: this .labelProvider = labelProvider;
304: }
305:
306: /**
307: * The viewer implementation of this <code>ISelectionProvider</code> method
308: * make the new selection for this viewer without making it visible.
309: * <p>
310: * This method is equivalent to <code>setSelection(selection,false)</code>.
311: * </p>
312: */
313: public void setSelection(ISelection selection) {
314: setSelection(selection, false);
315: }
316:
317: /**
318: * Sets a new selection for this viewer and optionally makes it visible.
319: * <p>
320: * Subclasses must implement this method.
321: * </p>
322: *
323: * @param selection the new selection
324: * @param reveal <code>true</code> if the selection is to be made visible,
325: * and <code>false</code> otherwise
326: */
327: public abstract void setSelection(ISelection selection,
328: boolean reveal);
329:
330: /**
331: * Sets this viewer's sorter and triggers refiltering and resorting of this
332: * viewer's element. Passing <code>null</code> turns sorting off.
333: *
334: * @param sorter a viewer sorter, or <code>null</code> if none
335: */
336: public void setSorter(ViewerSorter sorter) {
337: this .sorter = sorter;
338: refresh();
339: }
340:
341: /**
342: * Refreshes labels with information from the viewer's label provider.
343: */
344: public abstract void update();
345:
346: /**
347: * Refreshes labels with information from the viewer's label provider.
348: *
349: * @param elem the element to be updated
350: */
351: public abstract void update(Object elem);
352:
353: /**
354: * Adds the element.
355: *
356: * @param elem the element to be added
357: */
358: protected abstract void add(Object elem);
359:
360: /**
361: * Returns the result of running the given elements through the filters.
362: *
363: * @param elements the elements to filter
364: * @return only the elements which all filters accept
365: */
366: protected Object[] filter(Object[] elements) {
367: if (filters != null) {
368: ArrayList filtered = new ArrayList(elements.length);
369: Object root = getRoot();
370: for (int i = 0; i < elements.length; i++) {
371: boolean add = true;
372: for (int j = 0; j < filters.size(); j++) {
373: add = ((ViewerFilter) filters.get(j)).select(this ,
374: root, elements[i]);
375: if (!add) {
376: break;
377: }
378: }
379: if (add) {
380: filtered.add(elements[i]);
381: }
382: }
383: return filtered.toArray();
384: }
385: return elements;
386: }
387:
388: /**
389: * Notifies any selection listeners that the viewer's selection has changed.
390: *
391: * @param se the selection event
392: */
393: protected void fireSelectionChanged(SelectionChangedEvent se) {
394: if (selectionListeners == null) {
395: selectionListeners = new ArrayList();
396: }
397: for (int i = 0; i < selectionListeners.size(); i++) {
398: ISelectionChangedListener listener = (ISelectionChangedListener) selectionListeners
399: .get(i);
400: listener.selectionChanged(se);
401: }
402: }
403:
404: /**
405: * Returns the root element.
406: * <p>
407: * The default implementation of this framework method forwards to
408: * <code>getInput</code>. Override if the root element is different from
409: * the viewer's input element.
410: * </p>
411: *
412: * @return the root element, or <code>null</code> if none
413: */
414: protected Object getRoot() {
415: return getInput();
416: }
417:
418: /**
419: * Retrieves the selection of the viewer.
420: *
421: * @return the list of selected elements
422: */
423: protected abstract List getSelectedFromWidget();
424:
425: protected void hookWidget(Component widget) {
426: final ISelectionProvider provider = this ;
427: widget.addListener(Events.SelectionChange, new Listener() {
428: public void handleEvent(BaseEvent be) {
429: SelectionChangedEvent se = new SelectionChangedEvent(
430: provider, getSelection());
431: fireSelectionChanged(se);
432: }
433: });
434: }
435:
436: /**
437: * Inserts the element.
438: *
439: * @param elem the element
440: * @param index the insert location
441: */
442: protected abstract void insert(Object elem, int index);
443:
444: /**
445: * Internal hook method called when the input to this viewer is initially set
446: * or subsequently changed.
447: *
448: * @param input the new input
449: */
450: protected abstract void onInputReceived(Object input);
451:
452: protected void removeElement(Object elem) {
453: List list = new ArrayList();
454: for (int i = 0; i < elements.length; i++) {
455: if (elements[i] != elem) {
456: list.add(elements[i]);
457: }
458: }
459: elements = list.toArray();
460: }
461:
462: protected Object[] sortElements(Object[] elements) {
463: if (sorter != null) {
464: sorter.sort(this, elements);
465: }
466: return elements;
467: }
468:
469: }
|