001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.keys;
011:
012: import org.eclipse.jface.action.IContributionItem;
013: import org.eclipse.jface.action.IStatusLineManager;
014: import org.eclipse.jface.bindings.keys.KeySequence;
015: import org.eclipse.ui.IWorkbench;
016: import org.eclipse.ui.IWorkbenchWindow;
017: import org.eclipse.ui.internal.WorkbenchWindow;
018: import org.eclipse.ui.internal.util.StatusLineContributionItem;
019:
020: /**
021: * <p>
022: * The mutable state of the key binding architecture. This is the only piece of
023: * the key binding architecture that changes (internally). It keeps track of
024: * what partial key strokes the user has entered. In the case of functional
025: * groups of key bindings, it allows the user to keep part of the key sequence
026: * even after a match has been made. Only after releasing all of the modifier
027: * keys would the sequence reset itself.
028: * </p>
029: * <p>
030: * In the current implementation, a partial reset results in only one key
031: * stroke being left in the sequence. However, this may change in the future.
032: * </p>
033: *
034: * @since 3.0
035: */
036: class KeyBindingState {
037:
038: /**
039: * The workbench window associated with this state. The state can only
040: * exist for one window. When the focus leaves this window then the mode
041: * must automatically be reset.
042: */
043: private IWorkbenchWindow associatedWindow;
044:
045: /**
046: * This is the current extent of the sequence entered by the user. In an
047: * application with only single-stroke key bindings, this will also be
048: * empty. However, in applications with multi-stroke key bindings, this is
049: * the sequence entered by the user that partially matches another one of
050: * the application's active key bindings.
051: */
052: private KeySequence currentSequence;
053:
054: /**
055: * The workbench that should be notified of changes to the key binding
056: * state. This is done by updating one of the contribution items on the
057: * status line.
058: */
059: private final IWorkbench workbench;
060:
061: /**
062: * Constructs a new instance of <code>KeyBindingState</code> with an
063: * empty key sequence, set to reset fully.
064: *
065: * @param workbenchToNotify
066: * The workbench that this state should keep advised of changes
067: * to the key binding state; must not be <code>null</code>.
068: */
069: KeyBindingState(IWorkbench workbenchToNotify) {
070: currentSequence = KeySequence.getInstance();
071: workbench = workbenchToNotify;
072: associatedWindow = workbench.getActiveWorkbenchWindow();
073: }
074:
075: /**
076: * An accessor for the workbench window associated with this state. This
077: * should never be <code>null</code>, as the setting follows the last
078: * workbench window to have focus.
079: *
080: * @return The workbench window to which the key binding architecture is
081: * currently attached; should never be <code>null</code>.
082: */
083: IWorkbenchWindow getAssociatedWindow() {
084: return associatedWindow;
085: }
086:
087: /**
088: * An accessor for the current key sequence waiting for completion.
089: *
090: * @return The current incomplete key sequence; never <code>null</code>,
091: * but may be empty.
092: */
093: KeySequence getCurrentSequence() {
094: return currentSequence;
095: }
096:
097: /**
098: * Gets the status line contribution item which the key binding
099: * architecture uses to keep the user up-to-date as to the current state.
100: *
101: * @return The status line contribution item, if any; <code>null</code>,
102: * if none.
103: */
104: StatusLineContributionItem getStatusLine() {
105: if (associatedWindow instanceof WorkbenchWindow) {
106: WorkbenchWindow window = (WorkbenchWindow) associatedWindow;
107: IStatusLineManager statusLine = window
108: .getStatusLineManager();
109: // TODO implicit dependency on IDE's action builder
110: // @issue implicit dependency on IDE's action builder
111: if (statusLine != null) { // this can be null if we're exiting
112: IContributionItem item = statusLine
113: .find("ModeContributionItem"); //$NON-NLS-1$
114: if (item instanceof StatusLineContributionItem) {
115: return ((StatusLineContributionItem) item);
116: }
117: }
118: }
119:
120: return null;
121: }
122:
123: /**
124: * <p>
125: * Resets the state based on the current properties. If the state is to
126: * collapse fully or if there are no key strokes, then it sets the state to
127: * have an empty key sequence. Otherwise, it leaves the first key stroke in
128: * the sequence.
129: * </p>
130: * <p>
131: * The workbench's status lines are updated, if appropriate.
132: * </p>
133: */
134: void reset() {
135: currentSequence = KeySequence.getInstance();
136: updateStatusLines();
137: }
138:
139: /**
140: * A mutator for the workbench window to which this state is associated.
141: *
142: * @param window
143: * The workbench window to associated; should never be <code>null</code>.
144: */
145: void setAssociatedWindow(IWorkbenchWindow window) {
146: associatedWindow = window;
147: }
148:
149: /**
150: * A mutator for the partial sequence entered by the user.
151: *
152: * @param sequence
153: * The current key sequence; should not be <code>null</code>,
154: * but may be empty.
155: */
156: void setCurrentSequence(KeySequence sequence) {
157: currentSequence = sequence;
158: updateStatusLines();
159: }
160:
161: /**
162: * Updates the text of the status line of the associated shell with the
163: * current sequence.
164: */
165: private void updateStatusLines() {
166: StatusLineContributionItem statusLine = getStatusLine();
167: if (statusLine != null) {
168: statusLine.setText(getCurrentSequence().format());
169: }
170: }
171: }
|