Source code: org/eclipse/ui/actions/BaseSelectionListenerAction.java
1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11
12 package org.eclipse.ui.actions;
13
14 import org.eclipse.jface.action.Action;
15 import org.eclipse.jface.viewers.ISelection;
16 import org.eclipse.jface.viewers.ISelectionChangedListener;
17 import org.eclipse.jface.viewers.IStructuredSelection;
18 import org.eclipse.jface.viewers.SelectionChangedEvent;
19 import org.eclipse.jface.viewers.StructuredSelection;
20 import org.eclipse.swt.widgets.Event;
21
22 /**
23 * The abstract superclass for actions that listen to selection change events.
24 * This implementation tracks the current selection (see
25 * <code>getStructuredSelection</code>) and provides a convenient place to
26 * monitor selection changes that could affect the availability of the action.
27 * <p>
28 * Subclasses must implement the following <code>IAction</code> method:
29 * <ul>
30 * <li><code>run</code> - to do the action's work</li>
31 * </ul>
32 * </p>
33 * <p>
34 * Subclasses may extend the <code>updateSelection</code> method to update
35 * the action determine its availability based on the current selection.
36 * </p>
37 * <p>
38 * The object instantiating the subclass is responsible for registering
39 * the instance with a selection provider. Alternatively, the object can
40 * notify the subclass instance directly of a selection change using the
41 * methods:
42 * <ul>
43 * <li><code>selectionChanged(IStructuredSelection)</code> - passing the selection</li>
44 * <li><code>selectionChanged(ISelectionChangedEvent)</code> - passing the selection change event</li>
45 * </ul>
46 * </p>
47 * @since 3.0
48 */
49 public abstract class BaseSelectionListenerAction extends Action implements ISelectionChangedListener {
50 /**
51 * The current selection.
52 */
53 private IStructuredSelection selection = new StructuredSelection();
54
55 /**
56 * Running flag: <code>true</code> iff the action is running.
57 */
58 private boolean running = false;
59
60 /**
61 * The deferred selection. Any selection change that occurs
62 * while the action is running is held here until the run is complete.
63 */
64 private IStructuredSelection deferredSelection = null;
65
66 /**
67 * Creates a new action with the given text.
68 *
69 * @param text the string used as the text for the action,
70 * or <code>null</code> if there is no text
71 */
72 protected BaseSelectionListenerAction(String text) {
73 super(text);
74 }
75
76 /**
77 * Clears any cached state associated with the selection.
78 * Called when the selection changes.
79 * <p>
80 * The <code>BaseSelectionListenerAction</code> implementation of this method
81 * does nothing. Subclasses may override.
82 * </p>
83 */
84 protected void clearCache() {
85 // do nothing
86 }
87
88 /**
89 * Returns the current structured selection in the workbench, or an empty
90 * selection if nothing is selected or if selection does not include
91 * objects (for example, raw text).
92 *
93 * @return the current structured selection in the workbench
94 */
95 public IStructuredSelection getStructuredSelection() {
96 return selection;
97 }
98
99 /**
100 * Notifies this action that the given structured selection has changed.
101 * <p>
102 * The <code>BaseSelectionListenerAction</code> implementation of this method
103 * records the given selection for future reference and calls
104 * <code>updateSelection</code>, updating the enable state of this action
105 * based on the outcome. Subclasses should override <code>updateSelection</code>
106 * to react to selection changes.
107 * </p>
108 *
109 * @param selection the new selection
110 */
111 public final void selectionChanged(IStructuredSelection selection) {
112 // Ignore any incoming selection change while the action is running,
113 // otherwise the action can have unpredictable results, including lost
114 // data, if it operates on a different selection than what it initially
115 // validated.
116 // See Bug 60606 [Navigator] (data loss) Navigator deletes/moves the wrong file
117 if (running) {
118 deferredSelection = selection;
119 return;
120 }
121 this.selection = selection;
122 clearCache();
123 setEnabled(updateSelection(selection));
124 }
125
126 /**
127 * The <code>BaseSelectionListenerAction</code> implementation of this
128 * <code>ISelectionChangedListener</code> method calls
129 * <code>selectionChanged(IStructuredSelection)</code> assuming the selection is
130 * a structured one. Subclasses should override the <code>updateSelection</code>
131 * method to react to selection changes.
132 */
133 public final void selectionChanged(SelectionChangedEvent event) {
134 ISelection selection = event.getSelection();
135 if (selection instanceof IStructuredSelection)
136 selectionChanged((IStructuredSelection) selection);
137 else
138 selectionChanged(StructuredSelection.EMPTY);
139 }
140
141 /**
142 * Updates this action in response to the given selection.
143 * <p>
144 * The <code>BaseSelectionListenerAction</code> implementation of this method
145 * returns <code>true</code>. Subclasses may extend to react to selection
146 * changes; however, if the super method returns <code>false</code>, the
147 * overriding method must also return <code>false</code>.
148 * </p>
149 *
150 * @param selection the new selection
151 * @return <code>true</code> if the action should be enabled for this selection,
152 * and <code>false</code> otherwise
153 */
154 protected boolean updateSelection(IStructuredSelection selection) {
155 return true;
156 }
157
158 /* (non-Javadoc)
159 * @see org.eclipse.jface.action.Action#runWithEvent(org.eclipse.swt.widgets.Event)
160 */
161 public void runWithEvent(Event event) {
162 // Set the running flag during the run so that selection changes are deferred.
163 // See selectionChanged(IStructuredSelection) for more details.
164 running = true;
165 try {
166 run();
167 }
168 finally {
169 running = false;
170 IStructuredSelection s = deferredSelection;
171 deferredSelection = null;
172 if (s != null) {
173 selectionChanged(s);
174 }
175 }
176 }
177 }