10
|
1 /*******************************************************************************
|
|
2 * Copyright (c) 2000, 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 * Port to the D programming language:
|
|
11 * Frank Benoit <benoit@tionex.de>
|
|
12 *******************************************************************************/
|
|
13 module dwtx.jface.viewers.Viewer;
|
|
14
|
|
15 import dwtx.jface.viewers.IInputSelectionProvider;
|
|
16 import dwtx.jface.viewers.ISelectionChangedListener;
|
|
17 import dwtx.jface.viewers.SelectionChangedEvent;
|
|
18 import dwtx.jface.viewers.ISelection;
|
|
19
|
|
20 import dwt.events.HelpEvent;
|
|
21 import dwt.events.HelpListener;
|
|
22 import dwt.widgets.Control;
|
|
23 import dwt.widgets.Item;
|
|
24 import dwtx.core.runtime.Assert;
|
|
25 import dwtx.core.runtime.ListenerList;
|
|
26 import dwtx.jface.util.SafeRunnable;
|
|
27
|
|
28 import dwt.dwthelper.utils;
|
|
29
|
|
30 /**
|
|
31 * A viewer is a model-based adapter on a widget.
|
|
32 * <p>
|
|
33 * A viewer can be created as an adapter on a pre-existing control (e.g.,
|
|
34 * creating a <code>ListViewer</code> on an existing <code>List</code> control).
|
|
35 * All viewers also provide a convenience constructor for creating the control.
|
|
36 * </p>
|
|
37 * <p>
|
|
38 * Implementing a concrete viewer typically involves the following steps:
|
|
39 * <ul>
|
|
40 * <li>
|
|
41 * create DWT controls for viewer (in constructor) (optional)
|
|
42 * </li>
|
|
43 * <li>
|
|
44 * initialize DWT controls from input (inputChanged)
|
|
45 * </li>
|
|
46 * <li>
|
|
47 * define viewer-specific update methods
|
|
48 * </li>
|
|
49 * <li>
|
|
50 * support selections (<code>setSelection</code>, <code>getSelection</code>)
|
|
51 * </li>
|
|
52 * </ul>
|
|
53 * </p>
|
|
54 */
|
|
55 public abstract class Viewer : IInputSelectionProvider {
|
|
56
|
|
57 /**
|
|
58 * List of selection change listeners (element type: <code>ISelectionChangedListener</code>).
|
|
59 *
|
|
60 * @see #fireSelectionChanged
|
|
61 */
|
|
62 private ListenerList selectionChangedListeners;
|
|
63
|
|
64 /**
|
|
65 * List of help request listeners (element type: <code>dwt.events.HelpListener</code>).
|
|
66 * Help request listeners.
|
|
67 *
|
|
68 * @see #handleHelpRequest
|
|
69 */
|
|
70 private ListenerList helpListeners;
|
|
71
|
|
72 /**
|
|
73 * The names of this viewer's properties.
|
|
74 * <code>null</code> if this viewer has no properties.
|
|
75 *
|
|
76 * @see #setData
|
|
77 */
|
|
78 private String[] keys;
|
|
79
|
|
80 /**
|
|
81 * The values of this viewer's properties.
|
|
82 * <code>null</code> if this viewer has no properties.
|
|
83 * This array parallels the value of the <code>keys</code> field.
|
|
84 *
|
|
85 * @see #setData
|
|
86 */
|
|
87 private Object[] values;
|
|
88
|
|
89 /**
|
|
90 * Remembers whether we've hooked the help listener on the control or not.
|
|
91 */
|
|
92 private bool helpHooked = false;
|
|
93
|
|
94 /**
|
|
95 * Help listener for the control, created lazily when client's first help listener is added.
|
|
96 */
|
|
97 private HelpListener helpListener = null;
|
|
98
|
|
99 /**
|
|
100 * Unique key for associating element data with widgets.
|
|
101 * @see dwt.widgets.Widget#setData(String, Object)
|
|
102 */
|
|
103 protected static const String WIDGET_DATA_KEY = "dwtx.jface.viewers.WIDGET_DATA";//$NON-NLS-1$
|
|
104
|
|
105 /**
|
|
106 * Creates a new viewer.
|
|
107 */
|
|
108 protected this() {
|
|
109 selectionChangedListeners = new ListenerList();
|
|
110 helpListeners = new ListenerList();
|
|
111 }
|
|
112
|
|
113 /**
|
|
114 * Adds a listener for help requests in this viewer.
|
|
115 * Has no effect if an identical listener is already registered.
|
|
116 *
|
|
117 * @param listener a help listener
|
|
118 */
|
|
119 public void addHelpListener(HelpListener listener) {
|
|
120 helpListeners.add(cast(Object)listener);
|
|
121 if (!helpHooked) {
|
|
122 Control control = getControl();
|
|
123 if (control !is null && !control.isDisposed()) {
|
|
124 if (this.helpListener is null) {
|
|
125 this.helpListener = new class HelpListener {
|
|
126 public void helpRequested(HelpEvent event) {
|
|
127 handleHelpRequest(event);
|
|
128 }
|
|
129 };
|
|
130 }
|
|
131 control.addHelpListener(this.helpListener);
|
|
132 helpHooked = true;
|
|
133 }
|
|
134 }
|
|
135 }
|
|
136
|
|
137 /* (non-Javadoc)
|
|
138 * Method declared on ISelectionProvider.
|
|
139 */
|
|
140 public void addSelectionChangedListener(ISelectionChangedListener listener) {
|
|
141 selectionChangedListeners.add(cast(Object)listener);
|
|
142 }
|
|
143
|
|
144 /**
|
|
145 * Notifies any help listeners that help has been requested.
|
|
146 * Only listeners registered at the time this method is called are notified.
|
|
147 *
|
|
148 * @param event a help event
|
|
149 *
|
|
150 * @see HelpListener#helpRequested(dwt.events.HelpEvent)
|
|
151 */
|
|
152 protected void fireHelpRequested(HelpEvent event) {
|
|
153 Object[] listeners = helpListeners.getListeners();
|
|
154 for (int i = 0; i < listeners.length; ++i) {
|
|
155 (cast(HelpListener) listeners[i]).helpRequested(event);
|
|
156 }
|
|
157 }
|
|
158
|
|
159 /**
|
|
160 * Notifies any selection changed listeners that the viewer's selection has changed.
|
|
161 * Only listeners registered at the time this method is called are notified.
|
|
162 *
|
|
163 * @param event a selection changed event
|
|
164 *
|
|
165 * @see ISelectionChangedListener#selectionChanged
|
|
166 */
|
|
167 protected void fireSelectionChanged(SelectionChangedEvent event) {
|
|
168 Object[] listeners = selectionChangedListeners.getListeners();
|
|
169 for (int i = 0; i < listeners.length; ++i) {
|
|
170 SafeRunnable.run(new class SafeRunnable {
|
|
171 ISelectionChangedListener l;
|
|
172 SelectionChangedEvent event_;
|
|
173 this(){
|
|
174 event_=event;
|
|
175 l = cast(ISelectionChangedListener) listeners[i];
|
|
176 }
|
|
177 public void run() {
|
|
178 l.selectionChanged(event_);
|
|
179 }
|
|
180 });
|
|
181 }
|
|
182 }
|
|
183
|
|
184 /**
|
|
185 * Returns the primary control associated with this viewer.
|
|
186 *
|
|
187 * @return the DWT control which displays this viewer's content
|
|
188 */
|
|
189 public abstract Control getControl();
|
|
190
|
|
191 /**
|
|
192 * Returns the value of the property with the given name,
|
|
193 * or <code>null</code> if the property is not found.
|
|
194 * <p>
|
|
195 * The default implementation performs a (linear) search of
|
|
196 * an internal table. Overriding this method is generally not
|
|
197 * required if the number of different keys is small. If a more
|
|
198 * efficient representation of a viewer's properties is required,
|
|
199 * override both <code>getData</code> and <code>setData</code>.
|
|
200 * </p>
|
|
201 *
|
|
202 * @param key the property name
|
|
203 * @return the property value, or <code>null</code> if
|
|
204 * the property is not found
|
|
205 */
|
|
206 public Object getData(String key) {
|
|
207 Assert.isNotNull(key);
|
|
208 if (keys is null) {
|
|
209 return null;
|
|
210 }
|
|
211 for (int i = 0; i < keys.length; i++) {
|
|
212 if (keys[i].equals(key)) {
|
|
213 return values[i];
|
|
214 }
|
|
215 }
|
|
216 return null;
|
|
217 }
|
|
218
|
|
219 /* (non-Javadoc)
|
|
220 * Copy-down of method declared on <code>IInputProvider</code>.
|
|
221 */
|
|
222 public abstract Object getInput();
|
|
223
|
|
224 /* (non-Javadoc)
|
|
225 * Copy-down of method declared on <code>ISelectionProvider</code>.
|
|
226 */
|
|
227 public abstract ISelection getSelection();
|
|
228
|
|
229 /**
|
|
230 * Handles a help request from the underlying DWT control.
|
|
231 * The default behavior is to fire a help request,
|
|
232 * with the event's data modified to hold this viewer.
|
|
233 * @param event the event
|
|
234 *
|
|
235 */
|
|
236 protected void handleHelpRequest(HelpEvent event) {
|
|
237 Object oldData = event.data;
|
|
238 event.data = this;
|
|
239 fireHelpRequested(event);
|
|
240 event.data = oldData;
|
|
241 }
|
|
242
|
|
243 /**
|
|
244 * Internal hook method called when the input to this viewer is
|
|
245 * initially set or subsequently changed.
|
|
246 * <p>
|
|
247 * The default implementation does nothing. Subclassers may override
|
|
248 * this method to do something when a viewer's input is set.
|
|
249 * A typical use is populate the viewer.
|
|
250 * </p>
|
|
251 *
|
|
252 * @param input the new input of this viewer, or <code>null</code> if none
|
|
253 * @param oldInput the old input element or <code>null</code> if there
|
|
254 * was previously no input
|
|
255 */
|
|
256 protected void inputChanged(Object input, Object oldInput) {
|
|
257 }
|
|
258
|
|
259 /**
|
|
260 * Refreshes this viewer completely with information freshly obtained from this
|
|
261 * viewer's model.
|
|
262 */
|
|
263 public abstract void refresh();
|
|
264
|
|
265 /**
|
|
266 * Removes the given help listener from this viewer.
|
|
267 * Has no affect if an identical listener is not registered.
|
|
268 *
|
|
269 * @param listener a help listener
|
|
270 */
|
|
271 public void removeHelpListener(HelpListener listener) {
|
|
272 helpListeners.remove(cast(Object)listener);
|
|
273 if (helpListeners.size() is 0) {
|
|
274 Control control = getControl();
|
|
275 if (control !is null && !control.isDisposed()) {
|
|
276 control.removeHelpListener(this.helpListener);
|
|
277 helpHooked = false;
|
|
278 }
|
|
279 }
|
|
280 }
|
|
281
|
|
282 /* (non-Javadoc)
|
|
283 * Method declared on ISelectionProvider.
|
|
284 */
|
|
285 public void removeSelectionChangedListener(
|
|
286 ISelectionChangedListener listener) {
|
|
287 selectionChangedListeners.remove(cast(Object)listener);
|
|
288 }
|
|
289
|
|
290 /**
|
|
291 * Scrolls the viewer's control down by one item from the given
|
|
292 * display-relative coordinates. Returns the newly revealed Item,
|
|
293 * or <code>null</code> if no scrolling occurred or if the viewer
|
|
294 * doesn't represent an item-based widget.
|
|
295 *
|
|
296 * @param x horizontal coordinate
|
|
297 * @param y vertical coordinate
|
|
298 * @return the item scrolled down to
|
|
299 */
|
|
300 public Item scrollDown(int x, int y) {
|
|
301 return null;
|
|
302 }
|
|
303
|
|
304 /**
|
|
305 * Scrolls the viewer's control up by one item from the given
|
|
306 * display-relative coordinates. Returns the newly revealed Item,
|
|
307 * or <code>null</code> if no scrolling occurred or if the viewer
|
|
308 * doesn't represent an item-based widget.
|
|
309 *
|
|
310 * @param x horizontal coordinate
|
|
311 * @param y vertical coordinate
|
|
312 * @return the item scrolled up to
|
|
313 */
|
|
314 public Item scrollUp(int x, int y) {
|
|
315 return null;
|
|
316 }
|
|
317
|
|
318 /**
|
|
319 * Sets the value of the property with the given name to the
|
|
320 * given value, or to <code>null</code> if the property is to be
|
|
321 * removed. If this viewer has such a property, its value is
|
|
322 * replaced; otherwise a new property is added.
|
|
323 * <p>
|
|
324 * The default implementation records properties in an internal
|
|
325 * table which is searched linearly. Overriding this method is generally not
|
|
326 * required if the number of different keys is small. If a more
|
|
327 * efficient representation of a viewer's properties is required,
|
|
328 * override both <code>getData</code> and <code>setData</code>.
|
|
329 * </p>
|
|
330 *
|
|
331 * @param key the property name
|
|
332 * @param value the property value, or <code>null</code> if
|
|
333 * the property is not found
|
|
334 */
|
|
335 public void setData(String key, Object value) {
|
|
336 Assert.isNotNull(key);
|
|
337 /* Remove the key/value pair */
|
|
338 if (value is null) {
|
|
339 if (keys is null) {
|
|
340 return;
|
|
341 }
|
|
342 int index = 0;
|
|
343 while (index < keys.length && !keys[index].equals(key)) {
|
|
344 index++;
|
|
345 }
|
|
346 if (index is keys.length) {
|
|
347 return;
|
|
348 }
|
|
349 if (keys.length is 1) {
|
|
350 keys = null;
|
|
351 values = null;
|
|
352 } else {
|
|
353 String[] newKeys = new String[keys.length - 1];
|
|
354 Object[] newValues = new Object[values.length - 1];
|
|
355 System.arraycopy(keys, 0, newKeys, 0, index);
|
|
356 System.arraycopy(keys, index + 1, newKeys, index,
|
|
357 newKeys.length - index);
|
|
358 System.arraycopy(values, 0, newValues, 0, index);
|
|
359 System.arraycopy(values, index + 1, newValues, index,
|
|
360 newValues.length - index);
|
|
361 keys = newKeys;
|
|
362 values = newValues;
|
|
363 }
|
|
364 return;
|
|
365 }
|
|
366
|
|
367 /* Add the key/value pair */
|
|
368 if (keys is null) {
|
|
369 keys = [ key ];
|
|
370 values = [ value ];
|
|
371 return;
|
|
372 }
|
|
373 for (int i = 0; i < keys.length; i++) {
|
|
374 if (keys[i].equals(key)) {
|
|
375 values[i] = value;
|
|
376 return;
|
|
377 }
|
|
378 }
|
|
379 String[] newKeys = new String[](keys.length + 1);
|
|
380 Object[] newValues = new Object[](values.length + 1);
|
|
381 System.arraycopy(keys, 0, newKeys, 0, keys.length);
|
|
382 System.arraycopy(values, 0, newValues, 0, values.length);
|
|
383 newKeys[keys.length] = key;
|
|
384 newValues[values.length] = value;
|
|
385 keys = newKeys;
|
|
386 values = newValues;
|
|
387 }
|
|
388
|
|
389 /**
|
|
390 * Sets or clears the input for this viewer.
|
|
391 *
|
|
392 * @param input the input of this viewer, or <code>null</code> if none
|
|
393 */
|
|
394 public abstract void setInput(Object input);
|
|
395
|
|
396 /**
|
|
397 * The viewer implementation of this <code>ISelectionProvider</code>
|
|
398 * method make the new selection for this viewer without making it visible.
|
|
399 * <p>
|
|
400 * This method is equivalent to <code>setSelection(selection,false)</code>.
|
|
401 * </p>
|
|
402 * <p>
|
|
403 * Note that some implementations may not be able to set the selection
|
|
404 * without also revealing it, for example (as of 3.3) TreeViewer.
|
|
405 * </p>
|
|
406 */
|
|
407 public void setSelection(ISelection selection) {
|
|
408 setSelection(selection, false);
|
|
409 }
|
|
410
|
|
411 /**
|
|
412 * Sets a new selection for this viewer and optionally makes it visible.
|
|
413 * <p>
|
|
414 * Subclasses must implement this method.
|
|
415 * </p>
|
|
416 *
|
|
417 * @param selection the new selection
|
|
418 * @param reveal <code>true</code> if the selection is to be made
|
|
419 * visible, and <code>false</code> otherwise
|
|
420 */
|
|
421 public abstract void setSelection(ISelection selection, bool reveal);
|
|
422 }
|