blob: c64def34e6d3217e9d7eb064a9517cf0f5d6b270 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2005 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.List;
import java.util.StringTokenizer;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.formatting.KeyFormatterFactory;
import org.eclipse.jface.util.Util;
/**
* <p>
* A <code>KeySequence</code> is defined as a list of zero or more
* <code>KeyStrokes</code>, with the stipulation that all
* <code>KeyStroke</code> objects must be complete, save for the last one,
* whose completeness is optional. A <code>KeySequence</code> is said to be
* complete if all of its <code>KeyStroke</code> objects are complete.
* </p>
* <p>
* All <code>KeySequence</code> objects have a formal string representation
* available via the <code>toString()</code> method. There are a number of
* methods to get instances of <code>KeySequence</code> objects, including one
* which can parse this formal string representation.
* </p>
* <p>
* All <code>KeySequence</code> objects, via the <code>format()</code>
* method, provide a version of their formal string representation translated by
* platform and locale, suitable for display to a user.
* </p>
* <p>
* <code>KeySequence</code> objects are immutable. Clients are not permitted
* to extend this class.
* </p>
*
* @since 3.1
*/
public final class KeySequence extends TriggerSequence implements Comparable {
/**
* An empty key sequence instance for use by everyone.
*/
private final static KeySequence EMPTY_KEY_SEQUENCE = new KeySequence(
new KeyStroke[0]);
/**
* The delimiter between multiple key strokes in a single key sequence --
* expressed in the formal key stroke grammar. This is not to be displayed
* to the user. It is only intended as an internal representation.
*/
public final static String KEY_STROKE_DELIMITER = "\u0020"; //$NON-NLS-1$
/**
* The set of delimiters for <code>KeyStroke</code> objects allowed during
* parsing of the formal string representation.
*/
public final static String KEY_STROKE_DELIMITERS = KEY_STROKE_DELIMITER
+ "\b\r\u007F\u001B\f\n\0\t\u000B"; //$NON-NLS-1$
/**
* Gets an instance of <code>KeySequence</code>.
*
* @return a key sequence. This key sequence will have no key strokes.
* Guaranteed not to be <code>null</code>.
*/
public static final KeySequence getInstance() {
return EMPTY_KEY_SEQUENCE;
}
/**
* Creates an instance of <code>KeySequence</code> given a key sequence
* and a key stroke.
*
* @param keySequence
* a key sequence. Must not be <code>null</code>.
* @param keyStroke
* a key stroke. Must not be <code>null</code>.
* @return a key sequence that is equal to the given key sequence with the
* given key stroke appended to the end. Guaranteed not to be
* <code>null</code>.
*/
public static final KeySequence getInstance(final KeySequence keySequence,
final KeyStroke keyStroke) {
if (keySequence == null || keyStroke == null)
throw new NullPointerException();
final KeyStroke[] oldKeyStrokes = keySequence.getKeyStrokes();
final int oldKeyStrokeLength = oldKeyStrokes.length;
final KeyStroke[] newKeyStrokes = new KeyStroke[oldKeyStrokeLength + 1];
System
.arraycopy(oldKeyStrokes, 0, newKeyStrokes, 0,
oldKeyStrokeLength);
newKeyStrokes[oldKeyStrokeLength] = keyStroke;
return new KeySequence(newKeyStrokes);
}
/**
* Creates an instance of <code>KeySequence</code> given a single key
* stroke.
*
* @param keyStroke
* a single key stroke. Must not be <code>null</code>.
* @return a key sequence. Guaranteed not to be <code>null</code>.
*/
public static final KeySequence getInstance(final KeyStroke keyStroke) {
return new KeySequence(new KeyStroke[] { keyStroke });
}
/**
* Creates an instance of <code>KeySequence</code> given an array of key
* strokes.
*
* @param keyStrokes
* the array of key strokes. This array may be empty, but it must
* not be <code>null</code>. This array must not contain
* <code>null</code> elements.
* @return a key sequence. Guaranteed not to be <code>null</code>.
*/
public static final KeySequence getInstance(final KeyStroke[] keyStrokes) {
return new KeySequence(keyStrokes);
}
/**
* Creates an instance of <code>KeySequence</code> given a list of key
* strokes.
*
* @param keyStrokes
* the list of key strokes. This list may be empty, but it must
* not be <code>null</code>. If this list is not empty, it
* must only contain instances of <code>KeyStroke</code>.
* @return a key sequence. Guaranteed not to be <code>null</code>.
*/
public static final KeySequence getInstance(final List keyStrokes) {
return new KeySequence((KeyStroke[]) keyStrokes
.toArray(new KeyStroke[keyStrokes.size()]));
}
/**
* Creates an instance of <code>KeySequence</code> by parsing a given
* formal string representation.
*
* @param string
* the formal string representation to parse.
* @return a key sequence. Guaranteed not to be <code>null</code>.
* @throws ParseException
* if the given formal string representation could not be parsed
* to a valid key sequence.
*/
public static final KeySequence getInstance(final String string)
throws ParseException {
if (string == null)
throw new NullPointerException();
final List keyStrokes = new ArrayList();
final StringTokenizer stringTokenizer = new StringTokenizer(string,
KEY_STROKE_DELIMITERS);
try {
while (stringTokenizer.hasMoreTokens())
keyStrokes.add(KeyStroke.getInstance(stringTokenizer
.nextToken()));
final KeyStroke[] keyStrokeArray = (KeyStroke[]) keyStrokes
.toArray(new KeyStroke[keyStrokes.size()]);
return new KeySequence(keyStrokeArray);
} catch (final IllegalArgumentException e) {
throw new ParseException(
"Could not construct key sequence with these key strokes: " //$NON-NLS-1$
+ keyStrokes);
} catch (final NullPointerException e) {
throw new ParseException(
"Could not construct key sequence with these key strokes: " //$NON-NLS-1$
+ keyStrokes);
}
}
/**
* Constructs an instance of <code>KeySequence</code> given a list of key
* strokes.
*
* @param keyStrokes
* the list of key strokes. This list may be empty, but it must
* not be <code>null</code>. If this list is not empty, it
* must only contain instances of <code>KeyStroke</code>.
*/
protected KeySequence(final KeyStroke[] keyStrokes) {
super(keyStrokes);
for (int i = 0; i < triggers.length - 1; i++) {
KeyStroke keyStroke = (KeyStroke) triggers[i];
if (!keyStroke.isComplete())
throw new IllegalArgumentException();
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#compareTo(java.lang.Object)
*/
public final int compareTo(final Object object) {
final KeySequence castedObject = (KeySequence) object;
return Util.compare(triggers, castedObject.triggers);
}
/**
* Formats this key sequence into the current default look.
*
* @return A string representation for this key sequence using the default
* look; never <code>null</code>.
*/
public final String format() {
return KeyFormatterFactory.getDefault().format(this);
}
/**
* Returns the list of key strokes for this key sequence.
*
* @return the list of key strokes keys. This list may be empty, but is
* guaranteed not to be <code>null</code>. If this list is not
* empty, it is guaranteed to only contain instances of
* <code>KeyStroke</code>.
*/
public final KeyStroke[] getKeyStrokes() {
final int triggerLength = triggers.length;
final KeyStroke[] keyStrokes = new KeyStroke[triggerLength];
System.arraycopy(triggers, 0, keyStrokes, 0, triggerLength);
return keyStrokes;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.bindings.TriggerSequence#getPrefixes()
*/
public final TriggerSequence[] getPrefixes() {
final int numberOfPrefixes = triggers.length;
final TriggerSequence[] prefixes = new TriggerSequence[numberOfPrefixes];
prefixes[0] = KeySequence.getInstance();
for (int i = 0; i < numberOfPrefixes - 1; i++) {
final KeyStroke[] prefixKeyStrokes = new KeyStroke[i + 1];
System.arraycopy(triggers, 0, prefixKeyStrokes, 0, i + 1);
prefixes[i + 1] = KeySequence.getInstance(prefixKeyStrokes);
}
return prefixes;
}
/**
* Returns whether or not this key sequence is complete. Key sequences are
* complete iff all of their key strokes are complete.
*
* @return <code>true</code>, iff the key sequence is complete.
*/
public final boolean isComplete() {
final int triggersLength = triggers.length;
for (int i = 0; i < triggersLength; i++) {
if (!((KeyStroke) triggers[i]).isComplete()) {
return false;
}
}
return true;
}
/**
* Returns the formal string representation for this key sequence.
*
* @return The formal string representation for this key sequence.
* Guaranteed not to be <code>null</code>.
* @see java.lang.Object#toString()
*/
public final String toString() {
return KeyFormatterFactory.getFormalKeyFormatter().format(this);
}
}