|
Lines 16-34
Link Here
|
| 16 |
import java.util.List; |
16 |
import java.util.List; |
| 17 |
|
17 |
|
| 18 |
import org.eclipse.swt.SWT; |
18 |
import org.eclipse.swt.SWT; |
|
|
19 |
import org.eclipse.swt.events.FocusEvent; |
| 20 |
import org.eclipse.swt.events.FocusListener; |
| 19 |
import org.eclipse.swt.events.ModifyEvent; |
21 |
import org.eclipse.swt.events.ModifyEvent; |
| 20 |
import org.eclipse.swt.events.ModifyListener; |
22 |
import org.eclipse.swt.events.ModifyListener; |
| 21 |
import org.eclipse.swt.events.TraverseEvent; |
|
|
| 22 |
import org.eclipse.swt.events.TraverseListener; |
| 23 |
import org.eclipse.swt.graphics.Font; |
23 |
import org.eclipse.swt.graphics.Font; |
| 24 |
import org.eclipse.swt.widgets.Composite; |
24 |
import org.eclipse.swt.widgets.Composite; |
|
|
25 |
import org.eclipse.swt.widgets.Display; |
| 25 |
import org.eclipse.swt.widgets.Event; |
26 |
import org.eclipse.swt.widgets.Event; |
| 26 |
import org.eclipse.swt.widgets.Listener; |
27 |
import org.eclipse.swt.widgets.Listener; |
| 27 |
import org.eclipse.swt.widgets.Text; |
28 |
import org.eclipse.swt.widgets.Text; |
| 28 |
import org.eclipse.ui.keys.CharacterKey; |
|
|
| 29 |
import org.eclipse.ui.keys.KeySequence; |
29 |
import org.eclipse.ui.keys.KeySequence; |
| 30 |
import org.eclipse.ui.keys.KeyStroke; |
30 |
import org.eclipse.ui.keys.KeyStroke; |
| 31 |
import org.eclipse.ui.keys.NaturalKey; |
|
|
| 32 |
import org.eclipse.ui.keys.ParseException; |
31 |
import org.eclipse.ui.keys.ParseException; |
| 33 |
|
32 |
|
| 34 |
/** |
33 |
/** |
|
Lines 53-60
Link Here
|
| 53 |
private KeySequence keySequence = KeySequence.getInstance(); |
52 |
private KeySequence keySequence = KeySequence.getInstance(); |
| 54 |
/** The maximum number of key strokes permitted in the sequence. */ |
53 |
/** The maximum number of key strokes permitted in the sequence. */ |
| 55 |
private int maxStrokes = INFINITE; |
54 |
private int maxStrokes = INFINITE; |
| 56 |
/** The incomplete key stroke, if any. */ |
|
|
| 57 |
private KeyStroke temporaryStroke = null; |
| 58 |
/** The text widget that is wrapped for this class. */ |
55 |
/** The text widget that is wrapped for this class. */ |
| 59 |
private final Text text; |
56 |
private final Text text; |
| 60 |
/** The listener that makes sure that the text widget remains up-to-date |
57 |
/** The listener that makes sure that the text widget remains up-to-date |
|
Lines 92-105
Link Here
|
| 92 |
final Listener keyFilter = new KeyTrapListener(); |
89 |
final Listener keyFilter = new KeyTrapListener(); |
| 93 |
text.addListener(SWT.KeyUp, keyFilter); |
90 |
text.addListener(SWT.KeyUp, keyFilter); |
| 94 |
text.addListener(SWT.KeyDown, keyFilter); |
91 |
text.addListener(SWT.KeyDown, keyFilter); |
| 95 |
|
92 |
|
| 96 |
// Add the traversal listener. |
93 |
// Add the focus listener that attaches the global traversal filter. |
| 97 |
text.addTraverseListener(new FocusTrapListener()); |
94 |
text.addFocusListener(new TraversalFilterManager()); |
| 98 |
|
95 |
|
| 99 |
// Add an internal modify listener. |
96 |
// Add an internal modify listener. |
| 100 |
text.addModifyListener(updateSequenceListener); |
97 |
text.addModifyListener(updateSequenceListener); |
| 101 |
} |
98 |
} |
| 102 |
|
99 |
|
|
|
100 |
/** |
| 101 |
* Changes the font on the underlying text widget. |
| 102 |
* @param font The new font. |
| 103 |
*/ |
| 103 |
public void setFont(Font font) { |
104 |
public void setFont(Font font) { |
| 104 |
text.setFont(font); |
105 |
text.setFont(font); |
| 105 |
} |
106 |
} |
|
Lines 117-124
Link Here
|
| 117 |
* Clears the text field and resets all the internal values. |
118 |
* Clears the text field and resets all the internal values. |
| 118 |
*/ |
119 |
*/ |
| 119 |
public final void clear() { |
120 |
public final void clear() { |
| 120 |
keySequence = null; |
121 |
keySequence = KeySequence.getInstance(); |
| 121 |
temporaryStroke = null; |
|
|
| 122 |
text.setText(EMPTY_STRING); |
122 |
text.setText(EMPTY_STRING); |
| 123 |
} |
123 |
} |
| 124 |
|
124 |
|
|
Lines 131-152
Link Here
|
| 131 |
return keySequence; |
131 |
return keySequence; |
| 132 |
} |
132 |
} |
| 133 |
|
133 |
|
| 134 |
/** |
|
|
| 135 |
* An accessor for the <code>KeyStroke</code> that is currently held as an |
| 136 |
* incomplete stroke (i.e., one without a natural key). |
| 137 |
* @return The incomplete stroke; may be <code>null</code> if there are no |
| 138 |
* incomplete strokes. |
| 139 |
*/ |
| 140 |
final KeyStroke getTemporaryStroke() { |
| 141 |
return temporaryStroke; |
| 142 |
} |
| 143 |
|
| 144 |
/** |
134 |
/** |
| 145 |
* An accessor for the underlying text widget used by this entry field. |
135 |
* An accessor for the underlying text widget's contents. |
| 146 |
* @return The <code>Text</code> instance; never <code>null</code>. |
136 |
* @return The text contents of this entry; never <code>null</code>. |
| 147 |
*/ |
137 |
*/ |
| 148 |
final Text getText() { |
138 |
final String getText() { |
| 149 |
return text; |
139 |
return text.getText(); |
| 150 |
} |
140 |
} |
| 151 |
|
141 |
|
| 152 |
/** |
142 |
/** |
|
Lines 155-182
Link Here
|
| 155 |
* <code>false</code> otherwise. |
145 |
* <code>false</code> otherwise. |
| 156 |
*/ |
146 |
*/ |
| 157 |
public final boolean hasIncompleteStroke() { |
147 |
public final boolean hasIncompleteStroke() { |
| 158 |
return (temporaryStroke != null); |
148 |
return !keySequence.isComplete(); |
| 159 |
} |
|
|
| 160 |
|
| 161 |
/** |
| 162 |
* Checks whether the given key stroke is a temporary key stroke or not. |
| 163 |
* @param keyStroke The key stroke to check for completion; may be |
| 164 |
* <code>null</code>, which results in <code>false</code>. |
| 165 |
* @return <code>true</code> if the key stroke has no natural key; |
| 166 |
* <code>false</code> otherwise. |
| 167 |
*/ |
| 168 |
static final boolean isComplete(final KeyStroke keyStroke) { |
| 169 |
if (keyStroke != null) { |
| 170 |
final NaturalKey naturalKey = keyStroke.getNaturalKey(); |
| 171 |
|
| 172 |
if (naturalKey instanceof CharacterKey) { |
| 173 |
final CharacterKey characterKey = (CharacterKey) naturalKey; |
| 174 |
return (characterKey.getCharacter() != '\0'); |
| 175 |
} else |
| 176 |
return true; |
| 177 |
} |
| 178 |
|
| 179 |
return false; |
| 180 |
} |
149 |
} |
| 181 |
|
150 |
|
| 182 |
/** |
151 |
/** |
|
Lines 189-198
Link Here
|
| 189 |
|
158 |
|
| 190 |
/** |
159 |
/** |
| 191 |
* <p> |
160 |
* <p> |
| 192 |
* A mutator for the key sequence and incomplete stroke stored within this |
161 |
* A mutator for the key sequence stored within this widget. The text and |
| 193 |
* widget. This does some checking to see if the incomplete stroke is |
162 |
* caret position are updated. |
| 194 |
* really incomplete; if it is complete, then it is rolled into the key |
|
|
| 195 |
* sequence. The text and caret position are updated. |
| 196 |
* </p> |
163 |
* </p> |
| 197 |
* <p> |
164 |
* <p> |
| 198 |
* All sequences are limited to maxStrokes number of strokes in length. |
165 |
* All sequences are limited to maxStrokes number of strokes in length. |
|
Lines 202-284
Link Here
|
| 202 |
* |
169 |
* |
| 203 |
* @param newKeySequence The new key sequence for this widget; may be |
170 |
* @param newKeySequence The new key sequence for this widget; may be |
| 204 |
* <code>null</code> if none. |
171 |
* <code>null</code> if none. |
| 205 |
* @param incompleteStroke The new incomplete stroke for this widget; may be |
|
|
| 206 |
* <code>null</code> or incomplete -- both conditions are dealt with. |
| 207 |
*/ |
172 |
*/ |
| 208 |
public final void setKeySequence(final KeySequence newKeySequence, final KeyStroke incompleteStroke) { |
173 |
public void setKeySequence(KeySequence newKeySequence) { |
| 209 |
// Figure out whether the stroke should be rolled in. |
174 |
keySequence = newKeySequence; |
| 210 |
if (isComplete(incompleteStroke)) { |
175 |
|
| 211 |
if (newKeySequence == null) { |
176 |
// Trim any extra strokes. |
| 212 |
// This is guaranteed to be possible by setMaxStrokes |
177 |
if (maxStrokes != INFINITE) { |
| 213 |
keySequence = KeySequence.getInstance(incompleteStroke); |
178 |
List keyStrokes = new ArrayList(keySequence.getKeyStrokes()); |
| 214 |
} else { |
179 |
int keyStrokesSize = keyStrokes.size(); |
| 215 |
final List keyStrokes = new ArrayList(newKeySequence.getKeyStrokes()); |
180 |
for (int i = keyStrokesSize - 1; i >= maxStrokes; i--) { |
| 216 |
keyStrokes.add(incompleteStroke); |
181 |
keyStrokes.remove(i); |
| 217 |
if (maxStrokes != INFINITE) { |
|
|
| 218 |
final int keyStrokesSize = keyStrokes.size(); |
| 219 |
for (int i = keyStrokesSize - 1; i >= maxStrokes; i--) { |
| 220 |
keyStrokes.remove(i); |
| 221 |
} |
| 222 |
} |
| 223 |
keySequence = KeySequence.getInstance(keyStrokes); |
| 224 |
} |
| 225 |
temporaryStroke = null; |
| 226 |
} else { |
| 227 |
if ((newKeySequence != null) && (maxStrokes != INFINITE)) { |
| 228 |
final List untrimmedKeyStrokes = newKeySequence.getKeyStrokes(); |
| 229 |
final int keyStrokesSize = untrimmedKeyStrokes.size(); |
| 230 |
if (keyStrokesSize > maxStrokes) { |
| 231 |
final List keyStrokes = new ArrayList(untrimmedKeyStrokes); |
| 232 |
for (int i = keyStrokesSize - 1; i >= maxStrokes; i--) { |
| 233 |
keyStrokes.remove(i); |
| 234 |
} |
| 235 |
keySequence = KeySequence.getInstance(keyStrokes); |
| 236 |
temporaryStroke = null; |
| 237 |
} else if (keyStrokesSize == maxStrokes) { |
| 238 |
keySequence = newKeySequence; |
| 239 |
temporaryStroke = null; |
| 240 |
} else { |
| 241 |
keySequence = newKeySequence; |
| 242 |
temporaryStroke = incompleteStroke; |
| 243 |
} |
| 244 |
} else { |
| 245 |
keySequence = newKeySequence; |
| 246 |
temporaryStroke = incompleteStroke; |
| 247 |
} |
| 248 |
} |
| 249 |
|
| 250 |
/* Create a dummy (and rather invalid) sequence to get localized display |
| 251 |
* formatting |
| 252 |
*/ |
| 253 |
final KeySequence dummySequence; |
| 254 |
if (keySequence == null) { |
| 255 |
if (temporaryStroke == null) { |
| 256 |
dummySequence = KeySequence.getInstance(); |
| 257 |
} else { |
| 258 |
dummySequence = KeySequence.getInstance(temporaryStroke); |
| 259 |
} |
| 260 |
} else { |
| 261 |
final List keyStrokes = new ArrayList(keySequence.getKeyStrokes()); |
| 262 |
if (temporaryStroke != null) { |
| 263 |
keyStrokes.add(temporaryStroke); |
| 264 |
} |
182 |
} |
| 265 |
dummySequence = KeySequence.getInstance(keyStrokes); |
183 |
keySequence = KeySequence.getInstance(keyStrokes); |
| 266 |
} |
184 |
} |
| 267 |
|
185 |
|
| 268 |
// We need to update the text, but we don't need to synchronize. |
186 |
// We need to update the text, but we don't need to synchronize. |
| 269 |
text.removeModifyListener(updateSequenceListener); |
187 |
text.removeModifyListener(updateSequenceListener); |
| 270 |
text.setText(dummySequence.format()); |
188 |
text.setText(keySequence.format()); |
| 271 |
text.addModifyListener(updateSequenceListener); |
189 |
text.addModifyListener(updateSequenceListener); |
| 272 |
|
190 |
|
| 273 |
// Update the caret position. |
191 |
// Update the caret position. |
| 274 |
text.setSelection(text.getText().length()); |
192 |
text.setSelection(getText().length()); |
| 275 |
} |
193 |
} |
| 276 |
|
194 |
|
| 277 |
/** |
195 |
/** |
| 278 |
* A mutator for the layout information associated with the wrapped widget. |
196 |
* A mutator for the layout information associated with the wrapped widget. |
| 279 |
* @param layoutData The layout information; must not be <code>null</code>. |
197 |
* @param layoutData The layout information; must not be <code>null</code>. |
| 280 |
*/ |
198 |
*/ |
| 281 |
public final void setLayoutData(final Object layoutData) { |
199 |
public void setLayoutData(Object layoutData) { |
| 282 |
text.setLayoutData(layoutData); |
200 |
text.setLayoutData(layoutData); |
| 283 |
} |
201 |
} |
| 284 |
|
202 |
|
|
Lines 288-348
Link Here
|
| 288 |
* @param maximumStrokes The maximum number of strokes; should be a positive |
206 |
* @param maximumStrokes The maximum number of strokes; should be a positive |
| 289 |
* integer or <code>INFINITE</code>. |
207 |
* integer or <code>INFINITE</code>. |
| 290 |
*/ |
208 |
*/ |
| 291 |
public final void setMaxStrokes(final int maximumStrokes) { |
209 |
public void setMaxStrokes(int maximumStrokes) { |
| 292 |
if ((maximumStrokes > 0) || (maximumStrokes == INFINITE)) { |
210 |
if ((maximumStrokes > 0) || (maximumStrokes == INFINITE)) { |
| 293 |
maxStrokes = maximumStrokes; |
211 |
maxStrokes = maximumStrokes; |
| 294 |
} |
212 |
} |
| 295 |
} |
213 |
} |
| 296 |
|
214 |
|
| 297 |
/** |
215 |
/** |
| 298 |
* A traversal listener that blocks all traversal except for tabs and arrow |
|
|
| 299 |
* keys. |
| 300 |
*/ |
| 301 |
private final class FocusTrapListener implements TraverseListener { |
| 302 |
|
| 303 |
/** |
| 304 |
* Handles the traverse event on the text field wrapped by this class. |
| 305 |
* It swallows all traverse events example for tab and arrow key |
| 306 |
* navigation. The other forms of navigation can be reached by tabbing |
| 307 |
* off of the control. |
| 308 |
* |
| 309 |
* @param event The trigger event; must not be <code>null</code>. |
| 310 |
*/ |
| 311 |
public final void keyTraversed(final TraverseEvent event) { |
| 312 |
switch (event.detail) { |
| 313 |
case SWT.TRAVERSE_ESCAPE : |
| 314 |
case SWT.TRAVERSE_MNEMONIC : |
| 315 |
case SWT.TRAVERSE_NONE : |
| 316 |
case SWT.TRAVERSE_PAGE_NEXT : |
| 317 |
case SWT.TRAVERSE_PAGE_PREVIOUS : |
| 318 |
case SWT.TRAVERSE_RETURN : |
| 319 |
event.doit = false; |
| 320 |
break; |
| 321 |
|
| 322 |
case SWT.TRAVERSE_TAB_NEXT : |
| 323 |
case SWT.TRAVERSE_TAB_PREVIOUS : |
| 324 |
// Check if modifiers other than just 'Shift' were down. |
| 325 |
if ((event.stateMask & (SWT.MODIFIER_MASK ^ SWT.SHIFT)) != 0) { |
| 326 |
// Modifiers other than shift were down. |
| 327 |
event.doit = false; |
| 328 |
break; |
| 329 |
} |
| 330 |
// fall through -- either no modifiers, or just shift. |
| 331 |
|
| 332 |
case SWT.TRAVERSE_ARROW_NEXT : |
| 333 |
case SWT.TRAVERSE_ARROW_PREVIOUS : |
| 334 |
default : |
| 335 |
// Let the traversal happen, but clear the incomplete stroke |
| 336 |
setKeySequence(getKeySequence(), null); |
| 337 |
} |
| 338 |
} |
| 339 |
} |
| 340 |
|
| 341 |
/** |
| 342 |
* A key listener that traps incoming events and displays them in the |
216 |
* A key listener that traps incoming events and displays them in the |
| 343 |
* wrapped text field. It has no effect on traversal operations. |
217 |
* wrapped text field. It has no effect on traversal operations. |
| 344 |
*/ |
218 |
*/ |
| 345 |
private final class KeyTrapListener implements Listener { |
219 |
private class KeyTrapListener implements Listener { |
| 346 |
/** |
220 |
/** |
| 347 |
* Handles the key pressed and released events on the wrapped text |
221 |
* Handles the key pressed and released events on the wrapped text |
| 348 |
* widget. This makes sure to either add the pressed key to the |
222 |
* widget. This makes sure to either add the pressed key to the |
|
Lines 353-391
Link Here
|
| 353 |
* |
227 |
* |
| 354 |
* @param event The triggering event; must not be <code>null</code>. |
228 |
* @param event The triggering event; must not be <code>null</code>. |
| 355 |
*/ |
229 |
*/ |
| 356 |
public final void handleEvent(final Event event) { |
230 |
public void handleEvent(Event event) { |
|
|
231 |
List keyStrokes = new ArrayList(getKeySequence().getKeyStrokes()); |
| 232 |
|
| 357 |
if (event.type == SWT.KeyDown) { |
233 |
if (event.type == SWT.KeyDown) { |
| 358 |
if ((event.character == SWT.BS) && (event.stateMask == 0)) { |
234 |
if ((event.character == SWT.BS) && (event.stateMask == 0)) { |
| 359 |
// Remove the last key stroke. |
235 |
// Remove the last key stroke. |
| 360 |
if (hasIncompleteStroke()) { |
236 |
if (!keyStrokes.isEmpty()) { |
| 361 |
/* Remove the incomplete stroke. This should not really |
237 |
keyStrokes.remove(keyStrokes.size() - 1); |
| 362 |
* be possible, but it is better to be safe than sorry. |
|
|
| 363 |
*/ |
| 364 |
setKeySequence(getKeySequence(), null); |
| 365 |
} else { |
| 366 |
// Remove the last complete stroke. |
| 367 |
final KeySequence sequence = getKeySequence(); |
| 368 |
final List keyStrokes = new ArrayList(sequence.getKeyStrokes()); |
| 369 |
if (!keyStrokes.isEmpty()) { |
| 370 |
keyStrokes.remove(keyStrokes.size() - 1); |
| 371 |
setKeySequence(KeySequence.getInstance(keyStrokes), null); |
| 372 |
} |
| 373 |
} |
238 |
} |
|
|
239 |
|
| 374 |
} else { |
240 |
} else { |
| 375 |
// Handles the key pressed event. |
241 |
// Handles the key pressed event. |
| 376 |
final int key = KeySupport.convertEventToAccelerator(event); |
242 |
// Remove the incomplete stroke, if any. |
| 377 |
final KeyStroke stroke = KeySupport.convertAcceleratorToKeyStroke(key); |
243 |
if ((hasIncompleteStroke()) && (!keyStrokes.isEmpty())) { |
| 378 |
setKeySequence(getKeySequence(), stroke); |
244 |
keyStrokes.remove(keyStrokes.size() - 1); |
|
|
245 |
} |
| 246 |
|
| 247 |
// Add the new stroke. |
| 248 |
int key = KeySupport.convertEventToUnmodifiedAccelerator(event); |
| 249 |
KeyStroke stroke = KeySupport.convertAcceleratorToKeyStroke(key); |
| 250 |
keyStrokes.add(stroke); |
| 379 |
} |
251 |
} |
| 380 |
|
252 |
|
| 381 |
} else if (hasIncompleteStroke()) { |
253 |
} else if ((event.type == SWT.KeyUp) && (hasIncompleteStroke())) { |
| 382 |
/* Handles the key released event, which is only relevant if |
254 |
/* Handles the key released event, which is only relevant if |
| 383 |
* there is an incomplete stroke. |
255 |
* there is an incomplete stroke. |
| 384 |
*/ |
256 |
*/ |
| 385 |
/* Figure out the SWT integer representation of the remaining |
257 |
/* Figure out the SWT integer representation of the remaining |
| 386 |
* values. |
258 |
* values. |
| 387 |
*/ |
259 |
*/ |
| 388 |
final Event mockEvent = new Event(); |
260 |
Event mockEvent = new Event(); |
| 389 |
if ((event.keyCode & SWT.MODIFIER_MASK) != 0) { |
261 |
if ((event.keyCode & SWT.MODIFIER_MASK) != 0) { |
| 390 |
// This key up is a modifier key being released. |
262 |
// This key up is a modifier key being released. |
| 391 |
mockEvent.stateMask = event.stateMask - event.keyCode; |
263 |
mockEvent.stateMask = event.stateMask - event.keyCode; |
|
Lines 399-414
Link Here
|
| 399 |
/* Get a reasonable facsimile of the stroke that is still |
271 |
/* Get a reasonable facsimile of the stroke that is still |
| 400 |
* pressed. |
272 |
* pressed. |
| 401 |
*/ |
273 |
*/ |
| 402 |
final int key = KeySupport.convertEventToAccelerator(mockEvent); |
274 |
int key = KeySupport.convertEventToUnmodifiedAccelerator(mockEvent); |
| 403 |
final KeyStroke remainingStroke = KeySupport.convertAcceleratorToKeyStroke(key); |
275 |
KeyStroke remainingStroke = KeySupport.convertAcceleratorToKeyStroke(key); |
| 404 |
|
276 |
if (!keyStrokes.isEmpty()) { |
| 405 |
if (remainingStroke.getModifierKeys().isEmpty()) { |
277 |
keyStrokes.remove(keyStrokes.size() - 1); |
| 406 |
setKeySequence(getKeySequence(), null); |
278 |
} |
| 407 |
} else { |
279 |
if (!remainingStroke.getModifierKeys().isEmpty()) { |
| 408 |
setKeySequence(getKeySequence(), remainingStroke); |
280 |
keyStrokes.add(remainingStroke); |
| 409 |
} |
281 |
} |
| 410 |
|
282 |
|
| 411 |
} |
283 |
} |
|
|
284 |
|
| 285 |
// Update the underlying widget. |
| 286 |
setKeySequence(KeySequence.getInstance(keyStrokes)); |
| 412 |
|
287 |
|
| 413 |
// Prevent the event from reaching the widget. |
288 |
// Prevent the event from reaching the widget. |
| 414 |
event.doit = false; |
289 |
event.doit = false; |
|
Lines 416-460
Link Here
|
| 416 |
} |
291 |
} |
| 417 |
|
292 |
|
| 418 |
/** |
293 |
/** |
|
|
294 |
* A traversal listener that blocks all traversal except for tabs and arrow |
| 295 |
* keys. |
| 296 |
*/ |
| 297 |
private class TraversalFilter implements Listener { |
| 298 |
/** |
| 299 |
* Handles the traverse event on the text field wrapped by this class. |
| 300 |
* It swallows all traverse events example for tab and arrow key |
| 301 |
* navigation. The other forms of navigation can be reached by tabbing |
| 302 |
* off of the control. |
| 303 |
* |
| 304 |
* @param event The trigger event; must not be <code>null</code>. |
| 305 |
*/ |
| 306 |
public void handleEvent(Event event) { |
| 307 |
switch (event.detail) { |
| 308 |
case SWT.TRAVERSE_ESCAPE : |
| 309 |
case SWT.TRAVERSE_MNEMONIC : |
| 310 |
case SWT.TRAVERSE_NONE : |
| 311 |
case SWT.TRAVERSE_PAGE_NEXT : |
| 312 |
case SWT.TRAVERSE_PAGE_PREVIOUS : |
| 313 |
case SWT.TRAVERSE_RETURN : |
| 314 |
event.type = SWT.None; |
| 315 |
event.doit = false; |
| 316 |
break; |
| 317 |
|
| 318 |
case SWT.TRAVERSE_TAB_NEXT : |
| 319 |
case SWT.TRAVERSE_TAB_PREVIOUS : |
| 320 |
// Check if modifiers other than just 'Shift' were down. |
| 321 |
if ((event.stateMask & (SWT.MODIFIER_MASK ^ SWT.SHIFT)) != 0) { |
| 322 |
// Modifiers other than shift were down. |
| 323 |
event.type = SWT.None; |
| 324 |
event.doit = false; |
| 325 |
break; |
| 326 |
} |
| 327 |
// fall through -- either no modifiers, or just shift. |
| 328 |
|
| 329 |
case SWT.TRAVERSE_ARROW_NEXT : |
| 330 |
case SWT.TRAVERSE_ARROW_PREVIOUS : |
| 331 |
default : |
| 332 |
// Let the traversal happen, but clear the incomplete stroke |
| 333 |
if (hasIncompleteStroke()) { |
| 334 |
List keyStrokes = new ArrayList(getKeySequence().getKeyStrokes()); |
| 335 |
if (!keyStrokes.isEmpty()) { |
| 336 |
keyStrokes.remove(keyStrokes.size() - 1); |
| 337 |
} |
| 338 |
setKeySequence(KeySequence.getInstance(keyStrokes)); |
| 339 |
} |
| 340 |
} |
| 341 |
|
| 342 |
} |
| 343 |
} |
| 344 |
|
| 345 |
/** |
| 346 |
* The manager resposible for installing and removing the traversal filter |
| 347 |
* when the key sequence entry widget gains and loses focus. |
| 348 |
*/ |
| 349 |
private class TraversalFilterManager implements FocusListener { |
| 350 |
/** The managed filter. We only need one instance. */ |
| 351 |
private TraversalFilter filter = new TraversalFilter(); |
| 352 |
|
| 353 |
/** |
| 354 |
* Attaches the global traversal filter. |
| 355 |
* @param event Ignored. |
| 356 |
*/ |
| 357 |
public void focusGained(FocusEvent event) { |
| 358 |
Display.getCurrent().addFilter(SWT.Traverse, filter); |
| 359 |
} |
| 360 |
|
| 361 |
/** |
| 362 |
* Detaches the global traversal filter. |
| 363 |
* @param event Ignored. |
| 364 |
*/ |
| 365 |
public void focusLost(FocusEvent event) { |
| 366 |
Display.getCurrent().removeFilter(SWT.Traverse, filter); |
| 367 |
} |
| 368 |
} |
| 369 |
|
| 370 |
/** |
| 419 |
* A modification listener that makes sure that external events to this |
371 |
* A modification listener that makes sure that external events to this |
| 420 |
* class (i.e., direct modification of the underlying text) do not break |
372 |
* class (i.e., direct modification of the underlying text) do not break |
| 421 |
* this class' view of the world. |
373 |
* this class' view of the world. |
| 422 |
*/ |
374 |
*/ |
| 423 |
private final class UpdateSequenceListener implements ModifyListener { |
375 |
private class UpdateSequenceListener implements ModifyListener { |
| 424 |
/** |
376 |
/** |
| 425 |
* Handles the modify event on the underlying text widget. |
377 |
* Handles the modify event on the underlying text widget. |
| 426 |
* @param event The triggering event; ignored. |
378 |
* @param event The triggering event; ignored. |
| 427 |
*/ |
379 |
*/ |
| 428 |
public final void modifyText(final ModifyEvent event) { |
380 |
public void modifyText(ModifyEvent event) { |
| 429 |
try { |
381 |
try { |
| 430 |
// The original sequence. |
382 |
// The original sequence. |
| 431 |
final KeySequence originalSequence = getKeySequence(); |
383 |
KeySequence originalSequence = getKeySequence(); |
| 432 |
final List keyStrokes = new ArrayList(originalSequence.getKeyStrokes()); |
|
|
| 433 |
if (getTemporaryStroke() != null) { |
| 434 |
keyStrokes.add(getTemporaryStroke()); |
| 435 |
} |
| 436 |
final KeySequence sequenceFromStrokes = KeySequence.getInstance(keyStrokes); |
| 437 |
|
384 |
|
| 438 |
// The new sequence drawn from the text. |
385 |
// The new sequence drawn from the text. |
| 439 |
final String contents = getText().getText(); |
386 |
String contents = getText(); |
| 440 |
final KeySequence sequenceFromText = KeySequence.getInstance(contents); |
387 |
KeySequence newSequence = KeySequence.getInstance(contents); |
| 441 |
|
388 |
|
| 442 |
// Check to see if they're the same. |
389 |
// Check to see if they're the same. |
| 443 |
if (!sequenceFromStrokes.equals(sequenceFromText)) { |
390 |
if (!originalSequence.equals(newSequence)) { |
| 444 |
final List strokes = sequenceFromText.getKeyStrokes(); |
391 |
setKeySequence(newSequence); |
| 445 |
final Iterator strokeItr = strokes.iterator(); |
|
|
| 446 |
while (strokeItr.hasNext()) { |
| 447 |
// Make sure that it's a valid sequence. |
| 448 |
if (!isComplete((KeyStroke) strokeItr.next())) { |
| 449 |
setKeySequence(getKeySequence(), getTemporaryStroke()); |
| 450 |
return; |
| 451 |
} |
| 452 |
} |
| 453 |
setKeySequence(sequenceFromText, null); |
| 454 |
} |
392 |
} |
| 455 |
} catch (final ParseException e) { |
393 |
|
|
|
394 |
} catch (ParseException e) { |
| 456 |
// Abort any cut/paste-driven modifications |
395 |
// Abort any cut/paste-driven modifications |
| 457 |
setKeySequence(getKeySequence(), getTemporaryStroke()); |
396 |
setKeySequence(getKeySequence()); |
| 458 |
} |
397 |
} |
| 459 |
} |
398 |
} |
| 460 |
} |
399 |
} |