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.DialogCellEditor;
|
|
14
|
|
15 import dwtx.jface.viewers.CellEditor;
|
|
16
|
|
17 import dwt.DWT;
|
|
18 import dwt.events.FocusEvent;
|
|
19 import dwt.events.FocusListener;
|
|
20 import dwt.events.KeyAdapter;
|
|
21 import dwt.events.KeyEvent;
|
|
22 import dwt.events.SelectionAdapter;
|
|
23 import dwt.events.SelectionEvent;
|
|
24 import dwt.graphics.Color;
|
|
25 import dwt.graphics.Font;
|
|
26 import dwt.graphics.Point;
|
|
27 import dwt.graphics.Rectangle;
|
|
28 import dwt.widgets.Button;
|
|
29 import dwt.widgets.Composite;
|
|
30 import dwt.widgets.Control;
|
|
31 import dwt.widgets.Label;
|
|
32 import dwt.widgets.Layout;
|
|
33 import dwtx.jface.resource.ImageDescriptor;
|
|
34 import dwtx.jface.resource.ImageRegistry;
|
|
35 import dwtx.jface.resource.JFaceResources;
|
|
36
|
|
37 import dwt.dwthelper.utils;
|
|
38 import tango.text.convert.Format;
|
|
39
|
|
40 /**
|
|
41 * An abstract cell editor that uses a dialog.
|
|
42 * Dialog cell editors usually have a label control on the left and a button on
|
|
43 * the right. Pressing the button opens a dialog window (for example, a color dialog
|
|
44 * or a file dialog) to change the cell editor's value.
|
|
45 * The cell editor's value is the value of the dialog.
|
|
46 * <p>
|
|
47 * Subclasses may override the following methods:
|
|
48 * <ul>
|
|
49 * <li><code>createButton</code>: creates the cell editor's button control</li>
|
|
50 * <li><code>createContents</code>: creates the cell editor's 'display value' control</li>
|
|
51 * <li><code>updateContents</code>: updates the cell editor's 'display value' control
|
|
52 * after its value has changed</li>
|
|
53 * <li><code>openDialogBox</code>: opens the dialog box when the end user presses
|
|
54 * the button</li>
|
|
55 * </ul>
|
|
56 * </p>
|
|
57 */
|
|
58 public abstract class DialogCellEditor : CellEditor {
|
|
59
|
|
60 /**
|
|
61 * Image registry key for three dot image (value <code>"cell_editor_dots_button_image"</code>).
|
|
62 */
|
|
63 public static const String CELL_EDITOR_IMG_DOTS_BUTTON = "cell_editor_dots_button_image";//$NON-NLS-1$
|
|
64
|
|
65 /**
|
|
66 * The editor control.
|
|
67 */
|
|
68 private Composite editor;
|
|
69
|
|
70 /**
|
|
71 * The current contents.
|
|
72 */
|
|
73 private Control contents;
|
|
74
|
|
75 /**
|
|
76 * The label that gets reused by <code>updateLabel</code>.
|
|
77 */
|
|
78 private Label defaultLabel;
|
|
79
|
|
80 /**
|
|
81 * The button.
|
|
82 */
|
|
83 private Button button;
|
|
84
|
|
85 /**
|
|
86 * Listens for 'focusLost' events and fires the 'apply' event as long
|
|
87 * as the focus wasn't lost because the dialog was opened.
|
|
88 */
|
|
89 private FocusListener buttonFocusListener;
|
|
90
|
|
91 /**
|
|
92 * The value of this cell editor; initially <code>null</code>.
|
|
93 */
|
|
94 private Object value = null;
|
|
95
|
|
96 static this() {
|
|
97 ImageRegistry reg = JFaceResources.getImageRegistry();
|
|
98 reg.put(CELL_EDITOR_IMG_DOTS_BUTTON, ImageDescriptor.createFromFile(
|
42
|
99 getImportData!("dwtx.jface.images.dots_button.gif")));//$NON-NLS-1$
|
10
|
100 }
|
|
101
|
|
102 /**
|
|
103 * Internal class for laying out the dialog.
|
|
104 */
|
|
105 private class DialogCellLayout : Layout {
|
|
106 public void layout(Composite editor, bool force) {
|
|
107 Rectangle bounds = editor.getClientArea();
|
|
108 Point size = button.computeSize(DWT.DEFAULT, DWT.DEFAULT, force);
|
|
109 if (contents !is null) {
|
|
110 contents.setBounds(0, 0, bounds.width - size.x, bounds.height);
|
|
111 }
|
|
112 button.setBounds(bounds.width - size.x, 0, size.x, bounds.height);
|
|
113 }
|
|
114
|
|
115 public Point computeSize(Composite editor, int wHint, int hHint,
|
|
116 bool force) {
|
|
117 if (wHint !is DWT.DEFAULT && hHint !is DWT.DEFAULT) {
|
|
118 return new Point(wHint, hHint);
|
|
119 }
|
|
120 Point contentsSize = contents.computeSize(DWT.DEFAULT, DWT.DEFAULT,
|
|
121 force);
|
|
122 Point buttonSize = button.computeSize(DWT.DEFAULT, DWT.DEFAULT,
|
|
123 force);
|
|
124 // Just return the button width to ensure the button is not clipped
|
|
125 // if the label is long.
|
|
126 // The label will just use whatever extra width there is
|
|
127 Point result = new Point(buttonSize.x, Math.max(contentsSize.y,
|
|
128 buttonSize.y));
|
|
129 return result;
|
|
130 }
|
|
131 }
|
|
132
|
|
133 /**
|
|
134 * Default DialogCellEditor style
|
|
135 */
|
|
136 private static const int defaultStyle = DWT.NONE;
|
|
137
|
|
138 /**
|
|
139 * Creates a new dialog cell editor with no control
|
|
140 * @since 2.1
|
|
141 */
|
|
142 public this() {
|
|
143 setStyle(defaultStyle);
|
|
144 }
|
|
145
|
|
146 /**
|
|
147 * Creates a new dialog cell editor parented under the given control.
|
|
148 * The cell editor value is <code>null</code> initially, and has no
|
|
149 * validator.
|
|
150 *
|
|
151 * @param parent the parent control
|
|
152 */
|
|
153 protected this(Composite parent) {
|
|
154 this(parent, defaultStyle);
|
|
155 }
|
|
156
|
|
157 /**
|
|
158 * Creates a new dialog cell editor parented under the given control.
|
|
159 * The cell editor value is <code>null</code> initially, and has no
|
|
160 * validator.
|
|
161 *
|
|
162 * @param parent the parent control
|
|
163 * @param style the style bits
|
|
164 * @since 2.1
|
|
165 */
|
|
166 protected this(Composite parent, int style) {
|
|
167 super(parent, style);
|
|
168 }
|
|
169
|
|
170 /**
|
|
171 * Creates the button for this cell editor under the given parent control.
|
|
172 * <p>
|
|
173 * The default implementation of this framework method creates the button
|
|
174 * display on the right hand side of the dialog cell editor. Subclasses
|
|
175 * may extend or reimplement.
|
|
176 * </p>
|
|
177 *
|
|
178 * @param parent the parent control
|
|
179 * @return the new button control
|
|
180 */
|
|
181 protected Button createButton(Composite parent) {
|
|
182 Button result = new Button(parent, DWT.DOWN);
|
|
183 result.setText("..."); //$NON-NLS-1$
|
|
184 return result;
|
|
185 }
|
|
186
|
|
187 /**
|
|
188 * Creates the controls used to show the value of this cell editor.
|
|
189 * <p>
|
|
190 * The default implementation of this framework method creates
|
|
191 * a label widget, using the same font and background color as the parent control.
|
|
192 * </p>
|
|
193 * <p>
|
|
194 * Subclasses may reimplement. If you reimplement this method, you
|
|
195 * should also reimplement <code>updateContents</code>.
|
|
196 * </p>
|
|
197 *
|
|
198 * @param cell the control for this cell editor
|
|
199 * @return the underlying control
|
|
200 */
|
|
201 protected Control createContents(Composite cell) {
|
|
202 defaultLabel = new Label(cell, DWT.LEFT);
|
|
203 defaultLabel.setFont(cell.getFont());
|
|
204 defaultLabel.setBackground(cell.getBackground());
|
|
205 return defaultLabel;
|
|
206 }
|
|
207
|
|
208 /* (non-Javadoc)
|
|
209 * Method declared on CellEditor.
|
|
210 */
|
|
211 protected Control createControl(Composite parent) {
|
|
212
|
|
213 Font font = parent.getFont();
|
|
214 Color bg = parent.getBackground();
|
|
215
|
|
216 editor = new Composite(parent, getStyle());
|
|
217 editor.setFont(font);
|
|
218 editor.setBackground(bg);
|
|
219 editor.setLayout(new DialogCellLayout());
|
|
220
|
|
221 contents = createContents(editor);
|
|
222 updateContents(value);
|
|
223
|
|
224 button = createButton(editor);
|
|
225 button.setFont(font);
|
|
226
|
|
227 button.addKeyListener(new class KeyAdapter {
|
|
228 /* (non-Javadoc)
|
|
229 * @see dwt.events.KeyListener#keyReleased(dwt.events.KeyEvent)
|
|
230 */
|
|
231 public void keyReleased(KeyEvent e) {
|
|
232 if (e.character is '\u001b') { // Escape
|
|
233 fireCancelEditor();
|
|
234 }
|
|
235 }
|
|
236 });
|
|
237
|
|
238 button.addFocusListener(getButtonFocusListener());
|
|
239
|
|
240 button.addSelectionListener(new class SelectionAdapter {
|
|
241 /* (non-Javadoc)
|
|
242 * @see dwt.events.SelectionListener#widgetSelected(dwt.events.SelectionEvent)
|
|
243 */
|
|
244 public void widgetSelected(SelectionEvent event) {
|
|
245 // Remove the button's focus listener since it's guaranteed
|
|
246 // to lose focus when the dialog opens
|
|
247 button.removeFocusListener(getButtonFocusListener());
|
|
248
|
|
249 Object newValue = openDialogBox(editor);
|
|
250
|
|
251 // Re-add the listener once the dialog closes
|
|
252 button.addFocusListener(getButtonFocusListener());
|
|
253
|
|
254 if (newValue !is null) {
|
|
255 bool newValidState = isCorrect(newValue);
|
|
256 if (newValidState) {
|
|
257 markDirty();
|
|
258 doSetValue(newValue);
|
|
259 } else {
|
|
260 // try to insert the current value into the error message.
|
|
261 setErrorMessage(Format(getErrorMessage(),
|
|
262 newValue.toString() ));
|
|
263 }
|
|
264 fireApplyEditorValue();
|
|
265 }
|
|
266 }
|
|
267 });
|
|
268
|
|
269 setValueValid(true);
|
|
270
|
|
271 return editor;
|
|
272 }
|
|
273
|
|
274 /* (non-Javadoc)
|
|
275 *
|
|
276 * Override in order to remove the button's focus listener if the celleditor
|
|
277 * is deactivating.
|
|
278 *
|
|
279 * @see dwtx.jface.viewers.CellEditor#deactivate()
|
|
280 */
|
|
281 public void deactivate() {
|
|
282 if (button !is null && !button.isDisposed()) {
|
|
283 button.removeFocusListener(getButtonFocusListener());
|
|
284 }
|
|
285
|
|
286 super.deactivate();
|
|
287 }
|
|
288
|
|
289 /* (non-Javadoc)
|
|
290 * Method declared on CellEditor.
|
|
291 */
|
|
292 protected Object doGetValue() {
|
|
293 return value;
|
|
294 }
|
|
295
|
|
296 /* (non-Javadoc)
|
|
297 * Method declared on CellEditor.
|
|
298 * The focus is set to the cell editor's button.
|
|
299 */
|
|
300 protected void doSetFocus() {
|
|
301 button.setFocus();
|
|
302
|
|
303 // add a FocusListener to the button
|
|
304 button.addFocusListener(getButtonFocusListener());
|
|
305 }
|
|
306
|
|
307 /**
|
|
308 * Return a listener for button focus.
|
|
309 * @return FocusListener
|
|
310 */
|
|
311 private FocusListener getButtonFocusListener() {
|
|
312 if (buttonFocusListener is null) {
|
|
313 buttonFocusListener = new class FocusListener {
|
|
314
|
|
315 /* (non-Javadoc)
|
|
316 * @see dwt.events.FocusListener#focusGained(dwt.events.FocusEvent)
|
|
317 */
|
|
318 public void focusGained(FocusEvent e) {
|
|
319 // Do nothing
|
|
320 }
|
|
321
|
|
322 /* (non-Javadoc)
|
|
323 * @see dwt.events.FocusListener#focusLost(dwt.events.FocusEvent)
|
|
324 */
|
|
325 public void focusLost(FocusEvent e) {
|
|
326 this.outer.focusLost();
|
|
327 }
|
|
328 };
|
|
329 }
|
|
330
|
|
331 return buttonFocusListener;
|
|
332 }
|
|
333
|
|
334 /* (non-Javadoc)
|
|
335 * Method declared on CellEditor.
|
|
336 */
|
|
337 protected void doSetValue(Object value) {
|
|
338 this.value = value;
|
|
339 updateContents(value);
|
|
340 }
|
|
341
|
|
342 /**
|
|
343 * Returns the default label widget created by <code>createContents</code>.
|
|
344 *
|
|
345 * @return the default label widget
|
|
346 */
|
|
347 protected Label getDefaultLabel() {
|
|
348 return defaultLabel;
|
|
349 }
|
|
350
|
|
351 /**
|
|
352 * Opens a dialog box under the given parent control and returns the
|
|
353 * dialog's value when it closes, or <code>null</code> if the dialog
|
|
354 * was canceled or no selection was made in the dialog.
|
|
355 * <p>
|
|
356 * This framework method must be implemented by concrete subclasses.
|
|
357 * It is called when the user has pressed the button and the dialog
|
|
358 * box must pop up.
|
|
359 * </p>
|
|
360 *
|
|
361 * @param cellEditorWindow the parent control cell editor's window
|
|
362 * so that a subclass can adjust the dialog box accordingly
|
|
363 * @return the selected value, or <code>null</code> if the dialog was
|
|
364 * canceled or no selection was made in the dialog
|
|
365 */
|
|
366 protected abstract Object openDialogBox(Control cellEditorWindow);
|
|
367
|
|
368 /**
|
|
369 * Updates the controls showing the value of this cell editor.
|
|
370 * <p>
|
|
371 * The default implementation of this framework method just converts
|
|
372 * the passed object to a string using <code>toString</code> and
|
|
373 * sets this as the text of the label widget.
|
|
374 * </p>
|
|
375 * <p>
|
|
376 * Subclasses may reimplement. If you reimplement this method, you
|
|
377 * should also reimplement <code>createContents</code>.
|
|
378 * </p>
|
|
379 *
|
|
380 * @param value the new value of this cell editor
|
|
381 */
|
|
382 protected void updateContents(Object value) {
|
|
383 if (defaultLabel is null) {
|
|
384 return;
|
|
385 }
|
|
386
|
|
387 String text = "";//$NON-NLS-1$
|
|
388 if (value !is null) {
|
|
389 text = value.toString();
|
|
390 }
|
|
391 defaultLabel.setText(text);
|
|
392 }
|
|
393 }
|