blob: 83469b551d037d3b9b623c3ed910639fb7e34afe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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.ui.keys;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.ui.internal.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>
*
* @deprecated Please use org.eclipse.jface.bindings.keys.KeySequence
* @since 3.0
*/
public final class KeySequence implements Comparable {
/**
* 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$
/**
* An empty key sequence instance for use by everyone.
*/
private final static KeySequence EMPTY_KEY_SEQUENCE = new KeySequence(
Collections.EMPTY_LIST);
/**
* An internal constant used only in this object's hash code algorithm.
*/
private final static int HASH_FACTOR = 89;
/**
* An internal constant used only in this object's hash code algorithm.
*/
private final static int HASH_INITIAL = KeySequence.class.getName()
.hashCode();
/**
* 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 KeySequence getInstance() {
return EMPTY_KEY_SEQUENCE;
}
/**
* Gets 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 KeySequence getInstance(KeySequence keySequence,
KeyStroke keyStroke) {
if (keySequence == null || keyStroke == null) {
throw new NullPointerException();
}
List keyStrokes = new ArrayList(keySequence.getKeyStrokes());
keyStrokes.add(keyStroke);
return new KeySequence(keyStrokes);
}
/**
* Gets 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 KeySequence getInstance(KeyStroke keyStroke) {
return new KeySequence(Collections.singletonList(keyStroke));
}
/**
* Gets 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 KeySequence getInstance(KeyStroke[] keyStrokes) {
return new KeySequence(Arrays.asList(keyStrokes));
}
/**
* Gets 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 KeySequence getInstance(List keyStrokes) {
return new KeySequence(keyStrokes);
}
/**
* Gets an instance of <code>KeySequence</code> given a new-style key
* sequence.
*
* @param newKeySequence
* The new-style key sequence to convert into a legacy key
* sequence; must not be <code>null</code>.
* @return a key sequence; never <code>null</code>.
*/
public static final KeySequence getInstance(
final org.eclipse.jface.bindings.keys.KeySequence newKeySequence) {
final org.eclipse.jface.bindings.keys.KeyStroke[] newKeyStrokes = newKeySequence
.getKeyStrokes();
final int newKeyStrokesCount = newKeyStrokes.length;
final List legacyKeyStrokes = new ArrayList(newKeyStrokesCount);
for (int i = 0; i < newKeyStrokesCount; i++) {
final org.eclipse.jface.bindings.keys.KeyStroke newKeyStroke = newKeyStrokes[i];
legacyKeyStrokes.add(SWTKeySupport
.convertAcceleratorToKeyStroke(newKeyStroke
.getModifierKeys()
| newKeyStroke.getNaturalKey()));
}
return new KeySequence(legacyKeyStrokes);
}
/**
* Gets an instance of <code>KeySequence</code> by parsing a given a
* 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 KeySequence getInstance(String string) throws ParseException {
if (string == null) {
throw new NullPointerException();
}
List keyStrokes = new ArrayList();
StringTokenizer stringTokenizer = new StringTokenizer(string,
KEY_STROKE_DELIMITERS);
while (stringTokenizer.hasMoreTokens()) {
keyStrokes.add(KeyStroke.getInstance(stringTokenizer.nextToken()));
}
try {
return new KeySequence(keyStrokes);
} catch (Throwable t) {
throw new ParseException(
"Could not construct key sequence with these key strokes: " //$NON-NLS-1$
+ keyStrokes);
}
}
/**
* The cached hash code for this object. Because <code>KeySequence</code>
* objects are immutable, their hash codes need only to be computed once.
* After the first call to <code>hashCode()</code>, the computed value
* is cached here for all subsequent calls.
*/
private transient int hashCode;
/**
* A flag to determine if the <code>hashCode</code> field has already
* been computed.
*/
private transient boolean hashCodeComputed;
/**
* The list of key strokes for this key sequence.
*/
private List 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>.
*/
private KeySequence(List keyStrokes) {
this.keyStrokes = Util.safeCopy(keyStrokes, KeyStroke.class);
for (int i = 0; i < this.keyStrokes.size() - 1; i++) {
KeyStroke keyStroke = (KeyStroke) this.keyStrokes.get(i);
if (!keyStroke.isComplete()) {
throw new IllegalArgumentException();
}
}
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public int compareTo(Object object) {
KeySequence castedObject = (KeySequence) object;
int compareTo = Util.compare(keyStrokes, castedObject.keyStrokes);
return compareTo;
}
/**
* Returns whether or not this key sequence ends with the given key
* sequence.
*
* @param keySequence
* a key sequence. Must not be <code>null</code>.
* @param equals
* whether or not an identical key sequence should be considered
* as a possible match.
* @return <code>true</code>, iff the given key sequence ends with this
* key sequence.
*/
public boolean endsWith(KeySequence keySequence, boolean equals) {
if (keySequence == null) {
throw new NullPointerException();
}
return Util.endsWith(keyStrokes, keySequence.keyStrokes, equals);
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object object) {
if (!(object instanceof KeySequence)) {
return false;
}
return keyStrokes.equals(((KeySequence) object).keyStrokes);
}
/**
* 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 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 List getKeyStrokes() {
return keyStrokes;
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
if (!hashCodeComputed) {
hashCode = HASH_INITIAL;
hashCode = hashCode * HASH_FACTOR + keyStrokes.hashCode();
hashCodeComputed = true;
}
return hashCode;
}
/**
* 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 boolean isComplete() {
return keyStrokes.isEmpty()
|| ((KeyStroke) keyStrokes.get(keyStrokes.size() - 1))
.isComplete();
}
/**
* Returns whether or not this key sequence is empty. Key sequences are
* complete iff they have no key strokes.
*
* @return <code>true</code>, iff the key sequence is empty.
*/
public boolean isEmpty() {
return keyStrokes.isEmpty();
}
/**
* Returns whether or not this key sequence starts with the given key
* sequence.
*
* @param keySequence
* a key sequence. Must not be <code>null</code>.
* @param equals
* whether or not an identical key sequence should be considered
* as a possible match.
* @return <code>true</code>, iff the given key sequence starts with
* this key sequence.
*/
public boolean startsWith(KeySequence keySequence, boolean equals) {
if (keySequence == null) {
throw new NullPointerException();
}
return Util.startsWith(keyStrokes, keySequence.keyStrokes, equals);
}
/**
* 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 String toString() {
return KeyFormatterFactory.getFormalKeyFormatter().format(this);
}
}