001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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.commands;
011:
012: import org.eclipse.core.commands.IStateListener;
013: import org.eclipse.core.commands.State;
014: import org.eclipse.core.runtime.CoreException;
015: import org.eclipse.core.runtime.IConfigurationElement;
016: import org.eclipse.core.runtime.IStatus;
017: import org.eclipse.core.runtime.Status;
018: import org.eclipse.jface.commands.PersistentState;
019: import org.eclipse.jface.preference.IPreferenceStore;
020: import org.eclipse.ui.internal.WorkbenchPlugin;
021:
022: /**
023: * <p>
024: * A proxy for handler state that has been defined in XML. This delays the class
025: * loading until the state is really asked for information. Asking a proxy for
026: * anything (except disposing, and adding and removing listeners) will cause the
027: * proxy to instantiate the proxied handler.
028: * </p>
029: * <p>
030: * Loading the proxied state will automatically cause it to load its value from
031: * the preference store. Disposing of the state will cause it to persist its
032: * value.
033: * </p>
034: * <p>
035: * This class is not intended for use outside of the
036: * <code>org.eclipse.ui.workbench</code> plug-in.
037: * </p>
038: *
039: * @since 3.2
040: */
041: public final class CommandStateProxy extends PersistentState {
042:
043: /**
044: * The configuration element from which the state can be created. This value
045: * will exist until the element is converted into a real class -- at which
046: * point this value will be set to <code>null</code>.
047: */
048: private IConfigurationElement configurationElement;
049:
050: /**
051: * The key in the preference store to locate the persisted state.
052: */
053: private String preferenceKey;
054:
055: /**
056: * The preference store containing the persisted state, if any.
057: */
058: private IPreferenceStore preferenceStore;
059:
060: /**
061: * The real state. This value is <code>null</code> until the proxy is
062: * forced to load the real state. At this point, the configuration element
063: * is converted, nulled out, and this state gains a reference.
064: */
065: private State state = null;
066:
067: /**
068: * The name of the configuration element attribute which contains the
069: * information necessary to instantiate the real state.
070: */
071: private final String stateAttributeName;
072:
073: /**
074: * Constructs a new instance of <code>HandlerState</code> with all the
075: * information it needs to create the real state later.
076: *
077: * @param configurationElement
078: * The configuration element from which the real class can be
079: * loaded at run-time; must not be <code>null</code>.
080: * @param stateAttributeName
081: * The name of the attribute or element containing the state
082: * executable extension; must not be <code>null</code>.
083: * @param preferenceStore
084: * The preference store to which any persistent data should be
085: * written, and from which it should be loaded; may be
086: * <code>null</code>.
087: * @param preferenceKey
088: * The key at which the persistent data is located within the
089: * preference store.
090: */
091: public CommandStateProxy(
092: final IConfigurationElement configurationElement,
093: final String stateAttributeName,
094: final IPreferenceStore preferenceStore,
095: final String preferenceKey) {
096:
097: if (configurationElement == null) {
098: throw new NullPointerException(
099: "The configuration element backing a state proxy cannot be null"); //$NON-NLS-1$
100: }
101:
102: if (stateAttributeName == null) {
103: throw new NullPointerException(
104: "The attribute containing the state class must be known"); //$NON-NLS-1$
105: }
106:
107: this .configurationElement = configurationElement;
108: this .stateAttributeName = stateAttributeName;
109: this .preferenceKey = preferenceKey;
110: this .preferenceStore = preferenceStore;
111: }
112:
113: public final void addListener(final IStateListener listener) {
114: if (state == null) {
115: addListenerObject(listener);
116: } else {
117: state.addListener(listener);
118: }
119: }
120:
121: public final void dispose() {
122: if (state != null) {
123: state.dispose();
124: if (state instanceof PersistentState) {
125: final PersistentState persistableState = (PersistentState) state;
126: if (persistableState.shouldPersist()
127: && preferenceStore != null
128: && preferenceKey != null) {
129: persistableState.save(preferenceStore,
130: preferenceKey);
131: }
132: }
133: }
134: }
135:
136: public final Object getValue() {
137: if (loadState()) {
138: return state.getValue();
139: }
140:
141: return null;
142: }
143:
144: public final void load(final IPreferenceStore store,
145: final String preferenceKey) {
146: if (loadState() && state instanceof PersistentState) {
147: final PersistentState persistableState = (PersistentState) state;
148: if (persistableState.shouldPersist()
149: && preferenceStore != null && preferenceKey != null) {
150: persistableState.load(preferenceStore, preferenceKey);
151: }
152: }
153: }
154:
155: /**
156: * Loads the state, if possible. If the state is loaded, then the member
157: * variables are updated accordingly and the state is told to load its value
158: * from the preference store.
159: *
160: * @return <code>true</code> if the state is now non-null;
161: * <code>false</code> otherwise.
162: */
163: private final boolean loadState() {
164: return loadState(false);
165: }
166:
167: /**
168: * Loads the state, if possible. If the state is loaded, then the member
169: * variables are updated accordingly and the state is told to load its value
170: * from the preference store.
171: *
172: * @param readPersistence
173: * Whether the persistent state for this object should be read.
174: * @return <code>true</code> if the state is now non-null;
175: * <code>false</code> otherwise.
176: */
177: private final boolean loadState(final boolean readPersistence) {
178: if (state == null) {
179: try {
180: state = (State) configurationElement
181: .createExecutableExtension(stateAttributeName);
182: state.setId(getId());
183: configurationElement = null;
184:
185: // Try to load the persistent state, if possible.
186: if (readPersistence && state instanceof PersistentState) {
187: final PersistentState persistentState = (PersistentState) state;
188: persistentState.setShouldPersist(true);
189: }
190: load(preferenceStore, preferenceKey);
191:
192: // Transfer the local listeners to the real state.
193: final Object[] listenerArray = getListeners();
194: for (int i = 0; i < listenerArray.length; i++) {
195: state
196: .addListener((IStateListener) listenerArray[i]);
197: }
198: clearListeners();
199:
200: return true;
201:
202: } catch (final ClassCastException e) {
203: final String message = "The proxied state was the wrong class"; //$NON-NLS-1$
204: final IStatus status = new Status(IStatus.ERROR,
205: WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
206: WorkbenchPlugin.log(message, status);
207: return false;
208:
209: } catch (final CoreException e) {
210: final String message = "The proxied state for '" + configurationElement.getAttribute(stateAttributeName) //$NON-NLS-1$
211: + "' could not be loaded"; //$NON-NLS-1$
212: IStatus status = new Status(IStatus.ERROR,
213: WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
214: WorkbenchPlugin.log(message, status);
215: return false;
216: }
217: }
218:
219: return true;
220: }
221:
222: public final void removeListener(final IStateListener listener) {
223: if (state == null) {
224: removeListenerObject(listener);
225: } else {
226: state.removeListener(listener);
227: }
228: }
229:
230: public final void save(final IPreferenceStore store,
231: final String preferenceKey) {
232: if (loadState() && state instanceof PersistentState) {
233: ((PersistentState) state).save(store, preferenceKey);
234: }
235: }
236:
237: public final void setId(final String id) {
238: super .setId(id);
239: if (state != null) {
240: state.setId(id);
241: }
242: }
243:
244: public final void setShouldPersist(final boolean persisted) {
245: if (loadState(persisted) && state instanceof PersistentState) {
246: ((PersistentState) state).setShouldPersist(persisted);
247: }
248: }
249:
250: public final void setValue(final Object value) {
251: if (loadState()) {
252: state.setValue(value);
253: }
254: }
255:
256: public final boolean shouldPersist() {
257: if (loadState() && state instanceof PersistentState) {
258: return ((PersistentState) state).shouldPersist();
259: }
260:
261: return false;
262: }
263:
264: public final String toString() {
265: if (state == null) {
266: return configurationElement
267: .getAttribute(stateAttributeName);
268: }
269:
270: return state.toString();
271: }
272: }
|