Mercurial > projects > dwt-addons
comparison dwtx/jface/viewers/TextCellEditor.d @ 10:b6c35faf97c8
Viewers
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 31 Mar 2008 00:47:19 +0200 |
parents | |
children | ea8ff534f622 |
comparison
equal
deleted
inserted
replaced
9:6c14e54dfc11 | 10:b6c35faf97c8 |
---|---|
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 | |
14 module dwtx.jface.viewers.TextCellEditor; | |
15 | |
16 import dwtx.jface.viewers.CellEditor; | |
17 | |
18 import dwt.DWT; | |
19 import dwt.events.FocusAdapter; | |
20 import dwt.events.FocusEvent; | |
21 import dwt.events.KeyAdapter; | |
22 import dwt.events.KeyEvent; | |
23 import dwt.events.ModifyEvent; | |
24 import dwt.events.ModifyListener; | |
25 import dwt.events.MouseAdapter; | |
26 import dwt.events.MouseEvent; | |
27 import dwt.events.SelectionAdapter; | |
28 import dwt.events.SelectionEvent; | |
29 import dwt.events.TraverseEvent; | |
30 import dwt.events.TraverseListener; | |
31 import dwt.widgets.Composite; | |
32 import dwt.widgets.Control; | |
33 import dwt.widgets.Text; | |
34 import dwtx.core.runtime.Assert; | |
35 | |
36 import dwt.dwthelper.utils; | |
37 import tango.text.convert.Format; | |
38 | |
39 /** | |
40 * A cell editor that manages a text entry field. | |
41 * The cell editor's value is the text string itself. | |
42 * <p> | |
43 * This class may be instantiated; it is not intended to be subclassed. | |
44 * </p> | |
45 */ | |
46 public class TextCellEditor : CellEditor { | |
47 | |
48 /** | |
49 * The text control; initially <code>null</code>. | |
50 */ | |
51 protected Text text; | |
52 | |
53 private ModifyListener modifyListener; | |
54 | |
55 /** | |
56 * State information for updating action enablement | |
57 */ | |
58 private bool isSelection = false; | |
59 | |
60 private bool isDeleteable = false; | |
61 | |
62 private bool isSelectable = false; | |
63 | |
64 /** | |
65 * Default TextCellEditor style | |
66 * specify no borders on text widget as cell outline in table already | |
67 * provides the look of a border. | |
68 */ | |
69 private static const int defaultStyle = DWT.SINGLE; | |
70 | |
71 /** | |
72 * Creates a new text string cell editor with no control | |
73 * The cell editor value is the string itself, which is initially the empty | |
74 * string. Initially, the cell editor has no cell validator. | |
75 * | |
76 * @since 2.1 | |
77 */ | |
78 public this() { | |
79 setStyle(defaultStyle); | |
80 } | |
81 | |
82 /** | |
83 * Creates a new text string cell editor parented under the given control. | |
84 * The cell editor value is the string itself, which is initially the empty string. | |
85 * Initially, the cell editor has no cell validator. | |
86 * | |
87 * @param parent the parent control | |
88 */ | |
89 public this(Composite parent) { | |
90 this(parent, defaultStyle); | |
91 } | |
92 | |
93 /** | |
94 * Creates a new text string cell editor parented under the given control. | |
95 * The cell editor value is the string itself, which is initially the empty string. | |
96 * Initially, the cell editor has no cell validator. | |
97 * | |
98 * @param parent the parent control | |
99 * @param style the style bits | |
100 * @since 2.1 | |
101 */ | |
102 public this(Composite parent, int style) { | |
103 super(parent, style); | |
104 } | |
105 | |
106 /** | |
107 * Checks to see if the "deletable" state (can delete/ | |
108 * nothing to delete) has changed and if so fire an | |
109 * enablement changed notification. | |
110 */ | |
111 private void checkDeleteable() { | |
112 bool oldIsDeleteable = isDeleteable; | |
113 isDeleteable = isDeleteEnabled(); | |
114 if (oldIsDeleteable !is isDeleteable) { | |
115 fireEnablementChanged(DELETE); | |
116 } | |
117 } | |
118 | |
119 /** | |
120 * Checks to see if the "selectable" state (can select) | |
121 * has changed and if so fire an enablement changed notification. | |
122 */ | |
123 private void checkSelectable() { | |
124 bool oldIsSelectable = isSelectable; | |
125 isSelectable = isSelectAllEnabled(); | |
126 if (oldIsSelectable !is isSelectable) { | |
127 fireEnablementChanged(SELECT_ALL); | |
128 } | |
129 } | |
130 | |
131 /** | |
132 * Checks to see if the selection state (selection / | |
133 * no selection) has changed and if so fire an | |
134 * enablement changed notification. | |
135 */ | |
136 private void checkSelection() { | |
137 bool oldIsSelection = isSelection; | |
138 isSelection = text.getSelectionCount() > 0; | |
139 if (oldIsSelection !is isSelection) { | |
140 fireEnablementChanged(COPY); | |
141 fireEnablementChanged(CUT); | |
142 } | |
143 } | |
144 | |
145 /* (non-Javadoc) | |
146 * Method declared on CellEditor. | |
147 */ | |
148 protected Control createControl(Composite parent) { | |
149 text = new Text(parent, getStyle()); | |
150 text.addSelectionListener(new class SelectionAdapter { | |
151 public void widgetDefaultSelected(SelectionEvent e) { | |
152 handleDefaultSelection(e); | |
153 } | |
154 }); | |
155 text.addKeyListener(new class KeyAdapter { | |
156 // hook key pressed - see PR 14201 | |
157 public void keyPressed(KeyEvent e) { | |
158 keyReleaseOccured(e); | |
159 | |
160 // as a result of processing the above call, clients may have | |
161 // disposed this cell editor | |
162 if ((getControl() is null) || getControl().isDisposed()) { | |
163 return; | |
164 } | |
165 checkSelection(); // see explanation below | |
166 checkDeleteable(); | |
167 checkSelectable(); | |
168 } | |
169 }); | |
170 text.addTraverseListener(new class TraverseListener { | |
171 public void keyTraversed(TraverseEvent e) { | |
172 if (e.detail is DWT.TRAVERSE_ESCAPE | |
173 || e.detail is DWT.TRAVERSE_RETURN) { | |
174 e.doit = false; | |
175 } | |
176 } | |
177 }); | |
178 // We really want a selection listener but it is not supported so we | |
179 // use a key listener and a mouse listener to know when selection changes | |
180 // may have occurred | |
181 text.addMouseListener(new class MouseAdapter { | |
182 public void mouseUp(MouseEvent e) { | |
183 checkSelection(); | |
184 checkDeleteable(); | |
185 checkSelectable(); | |
186 } | |
187 }); | |
188 text.addFocusListener(new class FocusAdapter { | |
189 public void focusLost(FocusEvent e) { | |
190 this.outer.focusLost(); | |
191 } | |
192 }); | |
193 text.setFont(parent.getFont()); | |
194 text.setBackground(parent.getBackground()); | |
195 text.setText("");//$NON-NLS-1$ | |
196 text.addModifyListener(getModifyListener()); | |
197 return text; | |
198 } | |
199 | |
200 /** | |
201 * The <code>TextCellEditor</code> implementation of | |
202 * this <code>CellEditor</code> framework method returns | |
203 * the text string. | |
204 * | |
205 * @return the text string | |
206 */ | |
207 protected Object doGetValue() { | |
208 return new ArrayWrapperString(text.getText()); | |
209 } | |
210 | |
211 /* (non-Javadoc) | |
212 * Method declared on CellEditor. | |
213 */ | |
214 protected void doSetFocus() { | |
215 if (text !is null) { | |
216 text.selectAll(); | |
217 text.setFocus(); | |
218 checkSelection(); | |
219 checkDeleteable(); | |
220 checkSelectable(); | |
221 } | |
222 } | |
223 | |
224 /** | |
225 * The <code>TextCellEditor</code> implementation of | |
226 * this <code>CellEditor</code> framework method accepts | |
227 * a text string (type <code>String</code>). | |
228 * | |
229 * @param value a text string (type <code>String</code>) | |
230 */ | |
231 protected void doSetValue(Object value) { | |
232 Assert.isTrue(text !is null && ( cast(ArrayWrapperString)value )); | |
233 text.removeModifyListener(getModifyListener()); | |
234 text.setText((cast(ArrayWrapperString)value).array); | |
235 text.addModifyListener(getModifyListener()); | |
236 } | |
237 | |
238 /** | |
239 * Processes a modify event that occurred in this text cell editor. | |
240 * This framework method performs validation and sets the error message | |
241 * accordingly, and then reports a change via <code>fireEditorValueChanged</code>. | |
242 * Subclasses should call this method at appropriate times. Subclasses | |
243 * may extend or reimplement. | |
244 * | |
245 * @param e the DWT modify event | |
246 */ | |
247 protected void editOccured(ModifyEvent e) { | |
248 String value = text.getText(); | |
249 if (value is null) { | |
250 value = "";//$NON-NLS-1$ | |
251 } | |
252 Object typedValue = new ArrayWrapperString(value); | |
253 bool oldValidState = isValueValid(); | |
254 bool newValidState = isCorrect(typedValue); | |
255 if (typedValue is null && newValidState) { | |
256 Assert.isTrue(false, | |
257 "Validator isn't limiting the cell editor's type range");//$NON-NLS-1$ | |
258 } | |
259 if (!newValidState) { | |
260 // try to insert the current value into the error message. | |
261 setErrorMessage(Format(getErrorMessage(), value )); | |
262 } | |
263 valueChanged(oldValidState, newValidState); | |
264 } | |
265 | |
266 /** | |
267 * Since a text editor field is scrollable we don't | |
268 * set a minimumSize. | |
269 */ | |
270 public LayoutData getLayoutData() { | |
271 return new LayoutData(); | |
272 } | |
273 | |
274 /** | |
275 * Return the modify listener. | |
276 */ | |
277 private ModifyListener getModifyListener() { | |
278 if (modifyListener is null) { | |
279 modifyListener = new class ModifyListener { | |
280 public void modifyText(ModifyEvent e) { | |
281 editOccured(e); | |
282 } | |
283 }; | |
284 } | |
285 return modifyListener; | |
286 } | |
287 | |
288 /** | |
289 * Handles a default selection event from the text control by applying the editor | |
290 * value and deactivating this cell editor. | |
291 * | |
292 * @param event the selection event | |
293 * | |
294 * @since 3.0 | |
295 */ | |
296 protected void handleDefaultSelection(SelectionEvent event) { | |
297 // same with enter-key handling code in keyReleaseOccured(e); | |
298 fireApplyEditorValue(); | |
299 deactivate(); | |
300 } | |
301 | |
302 /** | |
303 * The <code>TextCellEditor</code> implementation of this | |
304 * <code>CellEditor</code> method returns <code>true</code> if | |
305 * the current selection is not empty. | |
306 */ | |
307 public bool isCopyEnabled() { | |
308 if (text is null || text.isDisposed()) { | |
309 return false; | |
310 } | |
311 return text.getSelectionCount() > 0; | |
312 } | |
313 | |
314 /** | |
315 * The <code>TextCellEditor</code> implementation of this | |
316 * <code>CellEditor</code> method returns <code>true</code> if | |
317 * the current selection is not empty. | |
318 */ | |
319 public bool isCutEnabled() { | |
320 if (text is null || text.isDisposed()) { | |
321 return false; | |
322 } | |
323 return text.getSelectionCount() > 0; | |
324 } | |
325 | |
326 /** | |
327 * The <code>TextCellEditor</code> implementation of this | |
328 * <code>CellEditor</code> method returns <code>true</code> | |
329 * if there is a selection or if the caret is not positioned | |
330 * at the end of the text. | |
331 */ | |
332 public bool isDeleteEnabled() { | |
333 if (text is null || text.isDisposed()) { | |
334 return false; | |
335 } | |
336 return text.getSelectionCount() > 0 | |
337 || text.getCaretPosition() < text.getCharCount(); | |
338 } | |
339 | |
340 /** | |
341 * The <code>TextCellEditor</code> implementation of this | |
342 * <code>CellEditor</code> method always returns <code>true</code>. | |
343 */ | |
344 public bool isPasteEnabled() { | |
345 if (text is null || text.isDisposed()) { | |
346 return false; | |
347 } | |
348 return true; | |
349 } | |
350 | |
351 /** | |
352 * Check if save all is enabled | |
353 * @return true if it is | |
354 */ | |
355 public bool isSaveAllEnabled() { | |
356 if (text is null || text.isDisposed()) { | |
357 return false; | |
358 } | |
359 return true; | |
360 } | |
361 | |
362 /** | |
363 * Returns <code>true</code> if this cell editor is | |
364 * able to perform the select all action. | |
365 * <p> | |
366 * This default implementation always returns | |
367 * <code>false</code>. | |
368 * </p> | |
369 * <p> | |
370 * Subclasses may override | |
371 * </p> | |
372 * @return <code>true</code> if select all is possible, | |
373 * <code>false</code> otherwise | |
374 */ | |
375 public bool isSelectAllEnabled() { | |
376 if (text is null || text.isDisposed()) { | |
377 return false; | |
378 } | |
379 return text.getCharCount() > 0; | |
380 } | |
381 | |
382 /** | |
383 * Processes a key release event that occurred in this cell editor. | |
384 * <p> | |
385 * The <code>TextCellEditor</code> implementation of this framework method | |
386 * ignores when the RETURN key is pressed since this is handled in | |
387 * <code>handleDefaultSelection</code>. | |
388 * An exception is made for Ctrl+Enter for multi-line texts, since | |
389 * a default selection event is not sent in this case. | |
390 * </p> | |
391 * | |
392 * @param keyEvent the key event | |
393 */ | |
394 protected void keyReleaseOccured(KeyEvent keyEvent) { | |
395 if (keyEvent.character is '\r') { // Return key | |
396 // Enter is handled in handleDefaultSelection. | |
397 // Do not apply the editor value in response to an Enter key event | |
398 // since this can be received from the IME when the intent is -not- | |
399 // to apply the value. | |
400 // See bug 39074 [CellEditors] [DBCS] canna input mode fires bogus event from Text Control | |
401 // | |
402 // An exception is made for Ctrl+Enter for multi-line texts, since | |
403 // a default selection event is not sent in this case. | |
404 if (text !is null && !text.isDisposed() | |
405 && (text.getStyle() & DWT.MULTI) !is 0) { | |
406 if ((keyEvent.stateMask & DWT.CTRL) !is 0) { | |
407 super.keyReleaseOccured(keyEvent); | |
408 } | |
409 } | |
410 return; | |
411 } | |
412 super.keyReleaseOccured(keyEvent); | |
413 } | |
414 | |
415 /** | |
416 * The <code>TextCellEditor</code> implementation of this | |
417 * <code>CellEditor</code> method copies the | |
418 * current selection to the clipboard. | |
419 */ | |
420 public void performCopy() { | |
421 text.copy(); | |
422 } | |
423 | |
424 /** | |
425 * The <code>TextCellEditor</code> implementation of this | |
426 * <code>CellEditor</code> method cuts the | |
427 * current selection to the clipboard. | |
428 */ | |
429 public void performCut() { | |
430 text.cut(); | |
431 checkSelection(); | |
432 checkDeleteable(); | |
433 checkSelectable(); | |
434 } | |
435 | |
436 /** | |
437 * The <code>TextCellEditor</code> implementation of this | |
438 * <code>CellEditor</code> method deletes the | |
439 * current selection or, if there is no selection, | |
440 * the character next character from the current position. | |
441 */ | |
442 public void performDelete() { | |
443 if (text.getSelectionCount() > 0) { | |
444 // remove the contents of the current selection | |
445 text.insert(""); //$NON-NLS-1$ | |
446 } else { | |
447 // remove the next character | |
448 int pos = text.getCaretPosition(); | |
449 if (pos < text.getCharCount()) { | |
450 text.setSelection(pos, pos + 1); | |
451 text.insert(""); //$NON-NLS-1$ | |
452 } | |
453 } | |
454 checkSelection(); | |
455 checkDeleteable(); | |
456 checkSelectable(); | |
457 } | |
458 | |
459 /** | |
460 * The <code>TextCellEditor</code> implementation of this | |
461 * <code>CellEditor</code> method pastes the | |
462 * the clipboard contents over the current selection. | |
463 */ | |
464 public void performPaste() { | |
465 text.paste(); | |
466 checkSelection(); | |
467 checkDeleteable(); | |
468 checkSelectable(); | |
469 } | |
470 | |
471 /** | |
472 * The <code>TextCellEditor</code> implementation of this | |
473 * <code>CellEditor</code> method selects all of the | |
474 * current text. | |
475 */ | |
476 public void performSelectAll() { | |
477 text.selectAll(); | |
478 checkSelection(); | |
479 checkDeleteable(); | |
480 } | |
481 | |
482 bool dependsOnExternalFocusListener() { | |
483 return this.classinfo !is TextCellEditor.classinfo; | |
484 } | |
485 } |