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
|
|
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 }
|