///*******************************************************************************
// * 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());
// }
//}