///******************************************************************************* // * Copyright (c) 2004, 2006 IBM Corporation and others. // * All rights reserved. This program and the accompanying materials // * are made available under the terms of the Eclipse Public License v1.0 // * which accompanies this distribution, and is available at // * http://www.eclipse.org/legal/epl-v10.html // * // * Contributors: // * IBM Corporation - initial API and implementation // *******************************************************************************/ // //package org.eclipse.jface.bindings.keys; // //import java.util.ArrayList; //import java.util.Collection; //import java.util.Iterator; // //import org.eclipse.jface.util.IPropertyChangeListener; //import org.eclipse.jface.util.PropertyChangeEvent; //import org.eclipse.swt.events.ModifyEvent; //import org.eclipse.swt.events.ModifyListener; //import org.eclipse.swt.widgets.Text; // ///** // * <p> // * A wrapper around the SWT text widget that traps literal key presses and // * converts them into key sequences for display. There are two types of key // * strokes that are displayed: complete and incomplete. A complete key stroke is // * one with a natural key, while an incomplete one has no natural key. // * Incomplete key strokes are only displayed until they are made complete or // * their component key presses are released. // * </p> // * // * @since 1.0 // */ //public final class KeySequenceText { // // /** // * A key listener that traps incoming events and displays them in the // * wrapped text field. It has no effect on traversal operations. // */ //// private class KeyTrapListener implements Listener { //// /** //// * The index at which insertion should occur. This is used if there is a //// * replacement occurring in the middle of the stroke, and the first key //// * stroke was incomplete. //// */ ////// private int insertionIndex = -1; //// //// /** //// * Resets the insertion index to point nowhere. In other words, it is //// * set to <code>-1</code>. //// */ //// void clearInsertionIndex() { //// insertionIndex = -1; //// } //// //// /** //// * Deletes the current selection. If there is no selection, then it //// * deletes the last key stroke. //// * //// * @param keyStrokes //// * The key strokes from which to delete. This list must not //// * be <code>null</code>, and must represent a valid key //// * sequence. //// */ ////// private final KeyStroke[] deleteKeyStroke(final KeyStroke[] keyStrokes) { ////// clearInsertionIndex(); ////// ////// if (hasSelection()) { ////// /* ////// * Delete the current selection -- disallowing incomplete ////// * strokes in the middle of the sequence. ////// */ ////// final KeyStroke[][] deletedKeyStrokes = new KeyStroke[1][]; ////// deleteSelection(keyStrokes, false, deletedKeyStrokes); ////// return deletedKeyStrokes[0]; ////// } ////// ////// // Remove the last key stroke. ////// if (keyStrokes.length > 0) { ////// final int newKeyStrokesLength = keyStrokes.length - 1; ////// final KeyStroke[] newKeyStrokes = new KeyStroke[newKeyStrokesLength]; ////// System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, ////// newKeyStrokesLength); ////// return newKeyStrokes; ////// } ////// ////// return keyStrokes; ////// } //// //// /** //// * Handles the key pressed and released events on the wrapped text //// * widget. This makes sure to either add the pressed key to the //// * temporary key stroke, or complete the current temporary key stroke //// * and prompt for the next. In the case of a key release, this makes //// * sure that the temporary stroke is correctly displayed -- //// * corresponding with modifier keys that may have been released. //// * //// * @param event //// * The triggering event; must not be <code>null</code>. //// */ //// public void handleEvent(Event event) { //// KeyStroke[] keyStrokes = getKeySequence().getKeyStrokes(); //// //// // Dispatch the event to the correct handler. ////// if (event.type == SWT.KeyDown) { ////// keyStrokes = handleKeyDown(event, keyStrokes); ////// } else if (event.type == SWT.KeyUp) { ////// keyStrokes = handleKeyUp(event, keyStrokes); ////// } //// //// // Update the underlying widget. //// setKeySequence(KeySequence.getInstance(keyStrokes)); //// //// // Prevent the event from reaching the widget. ////// event.doit = false; //// } //// //// /** //// * Handles the case where the key event is an <code>SWT.KeyDown</code> //// * event. This either causes a deletion (if it is an unmodified //// * backspace key stroke), or an insertion (if it is any other key). //// * //// * @param event //// * The trigger key down event; must not be <code>null</code>. //// * @param keyStrokes //// * The current list of key strokes. This valud must not be //// * <code>null</code>, and it must represent a valid key //// * sequence. //// */ ////// private KeyStroke[] handleKeyDown(Event event, KeyStroke[] keyStrokes) { //// // Is it an unmodified backspace character? ////// if ((event.character == SWT.BS) && (event.stateMask == 0)) { ////// return deleteKeyStroke(keyStrokes); ////// } //// ////// return insertKeyStroke(event, keyStrokes); ////// } //// //// /** //// * Handles the case where the key event is an <code>SWT.KeyUp</code> //// * event. This resets the insertion index. If there is an incomplete //// * stroke, then that incomplete stroke is modified to match the keys //// * that are still held. If no keys are held, then the incomplete stroke //// * is removed. //// * //// * @param event //// * The triggering event; must not be <code>null</code> //// * @param keyStrokes //// * The key strokes that are part of the current key sequence; //// * these key strokes are guaranteed to represent a valid key //// * sequence. This value must not be <code>null</code>. //// */ ////// private final KeyStroke[] handleKeyUp(final Event event, ////// final KeyStroke[] keyStrokes) { ////// if (hasIncompleteStroke()) { //// /* //// * Figure out the SWT integer representation of the remaining //// * values. //// */ ////// Event mockEvent = new Event(); ////// if ((event.keyCode & SWT.MODIFIER_MASK) != 0) { ////// // This key up is a modifier key being released. ////// mockEvent.stateMask = event.stateMask - event.keyCode; ////// } else { ////// /* ////// * This key up is the other end of a key down that was ////// * trapped by the operating system or window manager. ////// */ ////// mockEvent.stateMask = event.stateMask; ////// } //// //// /* //// * Get a reasonable facsimile of the stroke that is still //// * pressed. //// */ ////// int key = SWTKeySupport ////// .convertEventToUnmodifiedAccelerator(mockEvent); ////// KeyStroke remainingStroke = SWTKeySupport ////// .convertAcceleratorToKeyStroke(key); ////// final int keyStrokesLength = keyStrokes.length; ////// final KeyStroke[] newKeyStrokes; ////// if ((keyStrokesLength > 0) ////// && (remainingStroke.getModifierKeys() != 0)) { ////// newKeyStrokes = new KeyStroke[keyStrokesLength]; ////// System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, ////// keyStrokesLength - 1); ////// newKeyStrokes[keyStrokesLength - 1] = remainingStroke; ////// ////// } else if (keyStrokesLength > 0) { ////// newKeyStrokes = new KeyStroke[keyStrokesLength - 1]; ////// System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, ////// keyStrokesLength - 1); ////// ////// } else if (remainingStroke.getModifierKeys() != 0) { ////// newKeyStrokes = new KeyStroke[keyStrokesLength + 1]; ////// System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, ////// keyStrokesLength); ////// newKeyStrokes[keyStrokesLength] = remainingStroke; ////// ////// } else { ////// newKeyStrokes = keyStrokes; ////// ////// } ////// ////// return newKeyStrokes; ////// } //// ////// return keyStrokes; ////// } //// //// /** //// * <p> //// * Handles the case where a key down event is leading to a key stroke //// * being inserted. The current selection is deleted, and an invalid //// * remanents of the stroke are also removed. The insertion is carried //// * out at the cursor position. //// * </p> //// * <p> //// * If only a natural key is selected (as part of a larger key stroke), //// * then it is possible for the user to press a natural key to replace //// * the old natural key. In this situation, pressing any modifier keys //// * will replace the whole thing. //// * </p> //// * <p> //// * If the insertion point is not at the end of the sequence, then //// * incomplete strokes will not be immediately inserted. Only when the //// * sequence is completed is the stroke inserted. This is a requirement //// * as the widget must always represent a valid key sequence. The //// * insertion point is tracked using <code>insertionIndex</code>, //// * which is an index into the key stroke array. //// * </p> //// * //// * @param event //// * The triggering key down event; must not be //// * <code>null</code>. //// * @param keyStrokes //// * The key strokes into which the current stroke should be //// * inserted. This value must not be <code>null</code>, and //// * must represent a valid key sequence. //// */ ////// private final KeyStroke[] insertKeyStroke(final Event event, ////// KeyStroke[] keyStrokes) { ////// // Compute the key stroke to insert. ////// int key = SWTKeySupport.convertEventToUnmodifiedAccelerator(event); ////// KeyStroke stroke = SWTKeySupport.convertAcceleratorToKeyStroke(key); //// //// /* //// * Only insert the stroke if it is *not ScrollLock. Let's not get //// * silly //// */ ////// if ((SWT.NUM_LOCK == stroke.getNaturalKey()) ////// || (SWT.CAPS_LOCK == stroke.getNaturalKey()) ////// || (SWT.SCROLL_LOCK == stroke.getNaturalKey())) { ////// return keyStrokes; ////// } ////// ////// if (insertionIndex != -1) { ////// // There is a previous replacement still going on. ////// if (stroke.isComplete()) { ////// keyStrokes = insertStrokeAt(keyStrokes, stroke, ////// insertionIndex); ////// clearInsertionIndex(); ////// } ////// ////// } else if (hasSelection()) { ////// // There is a selection that needs to be replaced. ////// final KeyStroke[][] deletedKeyStrokes = new KeyStroke[1][]; ////// insertionIndex = deleteSelection(keyStrokes, stroke ////// .isComplete(), deletedKeyStrokes); ////// keyStrokes = deletedKeyStrokes[0]; ////// if ((stroke.isComplete()) ////// || (insertionIndex >= keyStrokes.length)) { ////// keyStrokes = insertStrokeAt(keyStrokes, stroke, ////// insertionIndex); ////// clearInsertionIndex(); ////// } ////// ////// } else { ////// // No selection, so remove the incomplete stroke, if any ////// if ((hasIncompleteStroke()) && (keyStrokes.length > 0)) { ////// final KeyStroke[] newKeyStrokes = new KeyStroke[keyStrokes.length - 1]; ////// System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, ////// keyStrokes.length - 1); ////// keyStrokes = newKeyStrokes; ////// } ////// ////// // And then add the new stroke. ////// if ((keyStrokes.length == 0) ////// || (insertionIndex >= keyStrokes.length) ////// || (isCursorInLastPosition())) { ////// keyStrokes = insertStrokeAt(keyStrokes, stroke, ////// keyStrokes.length); ////// clearInsertionIndex(); ////// } else { ////// /* ////// * I'm just getting the insertionIndex here. No actual ////// * deletion should occur. ////// */ ////// final KeyStroke[][] deletedKeyStrokes = new KeyStroke[1][]; ////// insertionIndex = deleteSelection(keyStrokes, stroke ////// .isComplete(), deletedKeyStrokes); ////// keyStrokes = deletedKeyStrokes[0]; ////// if (stroke.isComplete()) { ////// keyStrokes = insertStrokeAt(keyStrokes, stroke, ////// insertionIndex); ////// clearInsertionIndex(); ////// } ////// } ////// ////// } ////// ////// return keyStrokes; ////// } //// } // // /** // * A traversal listener that blocks all traversal except for tabs and arrow // * keys. // */ //// private class TraversalFilter implements Listener { // /** // * Handles the traverse event on the text field wrapped by this class. // * It swallows all traverse events example for tab and arrow key // * navigation. The other forms of navigation can be reached by tabbing // * off of the control. // * // * @param event // * The trigger event; must not be <code>null</code>. // */ //// public void handleEvent(Event event) { //// switch (event.detail) { //// case SWT.TRAVERSE_ESCAPE: //// case SWT.TRAVERSE_MNEMONIC: //// case SWT.TRAVERSE_NONE: //// case SWT.TRAVERSE_PAGE_NEXT: //// case SWT.TRAVERSE_PAGE_PREVIOUS: //// case SWT.TRAVERSE_RETURN: //// event.type = SWT.None; //// event.doit = false; //// break; //// //// case SWT.TRAVERSE_TAB_NEXT: //// case SWT.TRAVERSE_TAB_PREVIOUS: //// // Check if modifiers other than just 'Shift' were //// // down. //// if ((event.stateMask & (SWT.MODIFIER_MASK ^ SWT.SHIFT)) != 0) { //// // Modifiers other than shift were down. //// event.type = SWT.None; //// event.doit = false; //// break; //// } //// //// // fall through -- either no modifiers, or just shift. //// //// case SWT.TRAVERSE_ARROW_NEXT: //// case SWT.TRAVERSE_ARROW_PREVIOUS: //// default: //// // Let the traversal happen, but clear the incomplete //// // stroke //// if (hasIncompleteStroke()) { //// final KeyStroke[] oldKeyStrokes = getKeySequence() //// .getKeyStrokes(); //// final int newKeyStrokesLength = oldKeyStrokes.length - 1; //// if (newKeyStrokesLength >= 1) { //// final KeyStroke[] newKeyStrokes = new KeyStroke[newKeyStrokesLength]; //// System.arraycopy(oldKeyStrokes, 0, newKeyStrokes, 0, //// newKeyStrokesLength); //// setKeySequence(KeySequence.getInstance(newKeyStrokes)); //// } else { //// setKeySequence(KeySequence.getInstance()); //// } //// } //// } // //// } //// } // // /** // * The manager resposible for installing and removing the traversal filter // * when the key sequence entry widget gains and loses focus. // */ //// private class TraversalFilterManager implements FocusListener { //// /** The managed filter. We only need one instance. */ ////// private TraversalFilter filter = new TraversalFilter(); //// //// /** //// * Attaches the global traversal filter. //// * //// * @param event //// * Ignored. //// */ //// public void focusGained(FocusEvent event) { ////// Display.getCurrent().addFilter(SWT.Traverse, filter); //// } //// //// /** //// * Detaches the global traversal filter. //// * //// * @param event //// * Ignored. //// */ //// public void focusLost(FocusEvent event) { ////// Display.getCurrent().removeFilter(SWT.Traverse, filter); //// } //// } // // /** // * A modification listener that makes sure that external events to this // * class (i.e., direct modification of the underlying text) do not break // * this class' view of the world. // */ // private class UpdateSequenceListener implements ModifyListener { // /** // * Handles the modify event on the underlying text widget. // * // * @param event // * The triggering event; ignored. // */ // public void modifyText(ModifyEvent event) { // try { // // The original sequence. // KeySequence originalSequence = getKeySequence(); // // // The new sequence drawn from the text. // String contents = getText(); // KeySequence newSequence = KeySequence.getInstance(contents); // // // Check to see if they're the same. // if (!originalSequence.equals(newSequence)) { // setKeySequence(newSequence); // } // // } catch (ParseException e) { // // Abort any cut/paste-driven modifications // setKeySequence(getKeySequence()); // } // } // } // //// static { //// TreeSet trappedKeys = new TreeSet(); //// trappedKeys.add(SWTKeySupport.convertAcceleratorToKeyStroke(SWT.TAB)); //// trappedKeys.add(SWTKeySupport.convertAcceleratorToKeyStroke(SWT.TAB //// | SWT.SHIFT)); //// trappedKeys.add(SWTKeySupport.convertAcceleratorToKeyStroke(SWT.BS)); //// List trappedKeyList = new ArrayList(trappedKeys); //// TRAPPED_KEYS = Collections.unmodifiableList(trappedKeyList); //// } // // /** An empty string instance for use in clearing text values. */ // private static final String EMPTY_STRING = ""; //$NON-NLS-1$ // // /** // * The special integer value for the maximum number of strokes indicating // * that an infinite number should be allowed. // */ // public static final int INFINITE = -1; // // /** // * The name of the property representing the current key sequence in this // * key sequence widget. // * // * @since 1.0 // */ // public static final String P_KEY_SEQUENCE = "org.eclipse.jface.bindings.keys.KeySequenceText.KeySequence"; //$NON-NLS-1$ // // /** // * The keys trapped by this widget. This list is guaranteed to be roughly // * accurate. Perfection is not possible, as SWT does not export traversal // * keys as constants. // */ //// public static final List TRAPPED_KEYS; // // /** // * The key filter attached to the underlying widget that traps key events. // */ //// private final KeyTrapListener keyFilter = new KeyTrapListener(); // // /** // * The text of the key sequence -- containing only the complete key strokes. // */ // private KeySequence keySequence = KeySequence.getInstance(); // // /** // * Those listening to changes to the key sequence in this widget. This value // * may be <code>null</code> if there are no listeners. // */ // private Collection listeners = null; // // /** The maximum number of key strokes permitted in the sequence. */ // private int maxStrokes = INFINITE; // // /** The text widget that is wrapped for this class. */ // private final Text text; // // /** // * The listener that makes sure that the text widget remains up-to-date with // * regards to external modification of the text (e.g., cut & pasting). // */ // private final UpdateSequenceListener updateSequenceListener = new UpdateSequenceListener(); // // /** // * Constructs an instance of <code>KeySequenceTextField</code> with the // * text field to use. If the platform is carbon (MacOS X), then the font is // * set to be the same font used to display accelerators in the menus. // * // * @param wrappedText // * The text widget to wrap; must not be <code>null</code>. // */ // public KeySequenceText(Text wrappedText) { // text = wrappedText; // // // Set the font if the platform is carbon. //// if ("carbon".equals(SWT.getPlatform())) { //$NON-NLS-1$ //// // Don't worry about this font name here; it is the official menu //// // font and point size on the Mac. //// final Font font = new Font(text.getDisplay(), //// "Lucida Grande", 13, SWT.NORMAL); //$NON-NLS-1$ //// text.setFont(font); //// text.addDisposeListener(new DisposeListener() { //// public void widgetDisposed(DisposeEvent e) { //// font.dispose(); //// } //// }); //// } // //// // Add the key listener. //// text.addListener(SWT.KeyUp, keyFilter); //// text.addListener(SWT.KeyDown, keyFilter); // // // Add the focus listener that attaches the global traversal filter. //// text.addFocusListener(new TraversalFilterManager()); // // // Add an internal modify listener. //// text.addModifyListener(updateSequenceListener); // } // // /** // * Adds a property change listener to this key sequence widget. It will be // * notified when the key sequence changes. // * // * @param listener // * The listener to be notified when changes occur; must not be // * <code>null</code>. // * @since 1.0 // */ // public final void addPropertyChangeListener( // final IPropertyChangeListener listener) { // if (listener == null) { // return; // } // // if (listeners == null) { // listeners = new ArrayList(1); // } // // listeners.add(listener); // } // // /** // * Clears the text field and resets all the internal values. // */ // public void clear() { // final KeySequence oldKeySequence = keySequence; // keySequence = KeySequence.getInstance(); // text.setText(EMPTY_STRING); // firePropertyChangeEvent(oldKeySequence); // } // // /** // * Removes the key strokes from the list corresponding the selection. If // * <code>allowIncomplete</code>, then invalid key sequences will be // * allowed (i.e., those with incomplete strokes in the non-terminal // * position). Otherwise, incomplete strokes will be removed. This modifies // * <code>keyStrokes</code> in place, and has no effect on the text widget // * this class wraps. // * // * @param keyStrokes // * The list of key strokes from which the selection should be // * removed; must not be <code>null</code>. // * @param allowIncomplete // * Whether incomplete strokes should be allowed to exist in the // * list after the deletion. // * @return The index at which a subsequent insert should occur. This index // * only has meaning to the <code>insertStrokeAt</code> method. // */ //// private final int deleteSelection(final KeyStroke[] keyStrokes, //// final boolean allowIncomplete, final KeyStroke[][] deletedKeyStrokes) { //// // Get the current selection. //// Point selection = text.getSelection(); //// int start = selection.x; //// int end = selection.y; //// //// /* //// * Using the key sequence format method, discover the point at which //// * adding key strokes passes or equals the start of the selection. In //// * other words, find the first stroke that is part of the selection. //// * Keep track of the text range under which the stroke appears (i.e., //// * startTextIndex->string.length() is the first selected stroke). //// */ //// String string = new String(); //// List currentStrokes = new ArrayList(); //// int startTextIndex = 0; // keeps track of the start of the stroke //// final int keyStrokesLength = keyStrokes.length; //// int i; //// for (i = 0; (i < keyStrokesLength) && (string.length() < start); i++) { //// startTextIndex = string.length(); //// currentStrokes.add(keyStrokes[i]); //// string = KeySequence.getInstance(currentStrokes).format(); //// } //// //// /* //// * If string.length() == start, then the cursor is positioned between //// * strokes (i.e., selection is outside of a stroke). //// */ //// int startStrokeIndex; //// if (string.length() == start) { //// startStrokeIndex = currentStrokes.size(); //// } else { //// startStrokeIndex = currentStrokes.size() - 1; //// } //// //// /* //// * Check to see if the cursor is only positioned, rather than actually //// * selecting something. We only need to compute the end if there is a //// * selection. //// */ //// int endStrokeIndex; //// if (start == end) { //// return startStrokeIndex; //// } //// //// for (; (i < keyStrokesLength) && (string.length() < end); i++) { //// currentStrokes.add(keyStrokes[i]); //// string = KeySequence.getInstance(currentStrokes).format(); //// } //// endStrokeIndex = currentStrokes.size() - 1; //// if (endStrokeIndex < 0) { //// endStrokeIndex = 0; //// } //// //// /* //// * Remove the strokes that are touched by the selection. Keep track of //// * the first stroke removed. //// */ //// final int newLength = endStrokeIndex - startStrokeIndex + 1; //// deletedKeyStrokes[0] = new KeyStroke[newLength]; //// final KeyStroke startStroke = keyStrokes[startStrokeIndex]; //// System.arraycopy(keyStrokes, 0, keyStrokes, 0, newLength); //// //// /* //// * Allow the first stroke removed to be replaced by an incomplete //// * stroke. //// */ //// if (allowIncomplete) { //// final int modifierKeys = startStroke.getModifierKeys(); //// KeyStroke incompleteStroke = KeyStroke.getInstance(modifierKeys, //// KeyStroke.NO_KEY); //// int incompleteStrokeLength = incompleteStroke.format().length(); //// if ((startTextIndex + incompleteStrokeLength) <= start) { //// final KeyStroke[] added = new KeyStroke[newLength + 1]; //// System.arraycopy(deletedKeyStrokes[0], 0, added, 0, //// startStrokeIndex); //// added[startStrokeIndex] = incompleteStroke; //// System.arraycopy(deletedKeyStrokes[0], startStrokeIndex, added, //// startStrokeIndex + 1, newLength); //// deletedKeyStrokes[0] = added; //// } //// } //// //// return startStrokeIndex; //// } // // /** // * Fires a property change event to all of the listeners. // * // * @param oldKeySequence // * The old key sequence; must not be <code>null</code>. // * @since 1.0 // */ // protected final void firePropertyChangeEvent( // final KeySequence oldKeySequence) { // if (listeners != null) { // final Iterator listenerItr = listeners.iterator(); // final PropertyChangeEvent event = new PropertyChangeEvent(this, // P_KEY_SEQUENCE, oldKeySequence, getKeySequence()); // while (listenerItr.hasNext()) { // final IPropertyChangeListener listener = (IPropertyChangeListener) listenerItr // .next(); // listener.propertyChange(event); // } // } // } // // /** // * An accessor for the <code>KeySequence</code> that corresponds to the // * current state of the text field. This includes incomplete strokes. // * // * @return The key sequence representation; never <code>null</code>. // */ // public KeySequence getKeySequence() { // return keySequence; // } // // /** // * An accessor for the underlying text widget's contents. // * // * @return The text contents of this entry; never <code>null</code>. // */ // private String getText() { // return text.getText(); // } // // /** // * Tests whether the current key sequence has a stroke with no natural key. // * // * @return <code>true</code> is there is an incomplete stroke; // * <code>false</code> otherwise. // */ //// private boolean hasIncompleteStroke() { //// return !keySequence.isComplete(); //// } // // /** // * Tests whether the current text widget has some text selection. // * // * @return <code>true</code> if the number of selected characters it // * greater than zero; <code>false</code> otherwise. // */ //// private boolean hasSelection() { //// return (text.getSelectionCount() > 0); //// } // // /** // * Inserts the key stroke at the current insertion point. This does a // * regular delete and insert, as if the key had been pressed. // * // * @param stroke // * The key stroke to insert; must not be <code>null</code>. // */ // public void insert(KeyStroke stroke) { //// if (!stroke.isComplete()) { //// return; //// } //// //// // Copy the key strokes in the current key sequence. //// final KeySequence keySequence = getKeySequence(); //// final KeyStroke[] oldKeyStrokes = keySequence.getKeyStrokes(); //// final KeyStroke[] newKeyStrokes; //// if ((hasIncompleteStroke()) && (!keySequence.isEmpty())) { //// final int newKeyStrokesLength = oldKeyStrokes.length - 1; //// newKeyStrokes = new KeyStroke[newKeyStrokesLength]; //// System.arraycopy(oldKeyStrokes, 0, newKeyStrokes, 0, //// newKeyStrokesLength); //// } else { //// newKeyStrokes = oldKeyStrokes; //// } //// //// KeyStroke[][] deletedKeyStrokes = new KeyStroke[1][]; //// int index = deleteSelection(newKeyStrokes, false, deletedKeyStrokes); //// if (index == -1) { //// index = 0; //// } //// //// final KeyStroke[] keyStrokes = insertStrokeAt(newKeyStrokes, stroke, index); //// keyFilter.clearInsertionIndex(); //// setKeySequence(KeySequence.getInstance(keyStrokes)); // } // // /** // * Inserts the stroke at the given index in the list of strokes. If the // * stroke currently at that index is incomplete, then it tries to merge the // * two strokes. If merging is a complete failure (unlikely), then it will // * simply overwrite the incomplete stroke. If the stroke at the index is // * complete, then it simply inserts the stroke independently. // * // * @param keyStrokes // * The list of key strokes in which the key stroke should be // * appended; must not be <code>null</code>. // * @param stroke // * The stroke to insert; should not be <code>null</code>. // * @param index // * The index at which to insert; must be a valid index into the // * list of key strokes. // */ //// private final KeyStroke[] insertStrokeAt(final KeyStroke[] keyStrokes, //// KeyStroke stroke, int index) { //// final int keyStrokesLength = keyStrokes.length; //// final KeyStroke currentStroke = (index >= keyStrokesLength) ? null //// : keyStrokes[index]; //// if ((currentStroke != null) && (!currentStroke.isComplete())) { //// int modifierKeys = currentStroke.getModifierKeys(); //// final int naturalKey = stroke.getNaturalKey(); //// modifierKeys |= stroke.getModifierKeys(); //// keyStrokes[index] = KeyStroke.getInstance(modifierKeys, naturalKey); //// return keyStrokes; //// } //// //// final KeyStroke[] newKeyStrokes = new KeyStroke[keyStrokesLength + 1]; //// System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, index); //// newKeyStrokes[index] = stroke; //// if (index < keyStrokesLength) { //// System.arraycopy(keyStrokes, index, newKeyStrokes, index + 1, //// keyStrokesLength-index); //// } //// return newKeyStrokes; //// } // // /** // * Tests whether the cursor is in the last position. This means that the // * selection extends to the last position. // * // * @return <code>true</code> if the selection extends to the last // * position; <code>false</code> otherwise. // */ //// private boolean isCursorInLastPosition() { //// return (text.getSelection().y >= getText().length()); //// } // // /** // * Removes the given listener from this key sequence widget. // * // * @param listener // * The listener to be removed; must not be <code>null</code>. // * @since 1.0 // */ // public final void removePropertyChangeListener( // final IPropertyChangeListener listener) { // if ((listener == null) || (listeners == null)) { // return; // } // // listeners.remove(listener); // } // // /** // * <p> // * A mutator for the key sequence stored within this widget. The text and // * caret position are updated. // * </p> // * <p> // * All sequences are limited to maxStrokes number of strokes in length. If // * there are already that number of strokes, then it does not show // * incomplete strokes, and does not keep track of them. // * </p> // * // * @param newKeySequence // * The new key sequence for this widget; may be <code>null</code> // * if none. // */ // public void setKeySequence(KeySequence newKeySequence) { // final KeySequence oldKeySequence = keySequence; // keySequence = newKeySequence; // // // Trim any extra strokes. // if (maxStrokes != INFINITE) { // final KeyStroke[] oldKeyStrokes = keySequence.getKeyStrokes(); // if (maxStrokes < oldKeyStrokes.length) { // final KeyStroke[] newKeyStrokes = new KeyStroke[maxStrokes]; // System // .arraycopy(oldKeyStrokes, 0, newKeyStrokes, 0, // maxStrokes); // keySequence = KeySequence.getInstance(newKeyStrokes); // } // } // // // Check to see if the text has changed. // String currentString = getText(); // String newString = keySequence.format(); // if (!currentString.equals(newString)) { // // We need to update the text // text.removeModifyListener(updateSequenceListener); // text.setText(keySequence.format()); // text.addModifyListener(updateSequenceListener); // text.setSelection(getText().length()); // } // // firePropertyChangeEvent(oldKeySequence); // } // // /** // * Returns the maximum number of strokes that are permitted in this widget // * at one time. // * // * @return The maximum number of strokes; will be a positive integer or // * <code>INFINITE</code>. // */ // public int getKeyStrokeLimit() { // return maxStrokes; // } // // /** // * A mutator for the maximum number of strokes that are permitted in this // * widget at one time. // * // * @param keyStrokeLimit // * The maximum number of strokes; must be a positive integer or // * <code>INFINITE</code>. // */ // public void setKeyStrokeLimit(int keyStrokeLimit) { // if (keyStrokeLimit > 0 || keyStrokeLimit == INFINITE) { // this.maxStrokes = keyStrokeLimit; // } else { // throw new IllegalArgumentException(); // } // // // Make sure we are obeying the new limit. // setKeySequence(getKeySequence()); // } //}