1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 
15 
16 package org.eclipse.ui.texteditor;
17 
18 
19 import java.util.ResourceBundle;
20 
21 import org.eclipse.swt.events.HelpListener;
22 
23 import org.eclipse.jface.action.IAction;
24 import org.eclipse.jface.util.IPropertyChangeListener;
25 import org.eclipse.jface.util.PropertyChangeEvent;
26 
27 
28 /**
29  * Action used by an editor action bar contributor to establish placeholders in
30  * menus or action bars which can be retargeted to dynamically changing actions,
31  * for example, those which come from the active editor. This action assumes that
32  * the "wrapped" action sends out property change events in response to state
33  * changes. It uses these change notifications to adapt its enabling state and
34  * its visual presentation.
35  */
36 public final class RetargetTextEditorAction extends ResourceAction {
37 
38 	/** The target action. */
39 	private IAction fAction;
40 	/** The default label if there is no target action. */
41 	private String fDefaultText;
42 	/**
43 	 * The local help listener
44 	 * @since 2.1
45 	 */
46 	private HelpListener fLocalHelpListener;
47 	/** The listener to pick up changes of the target action. */
48 	private IPropertyChangeListener fListener= this::update;
49 
50 	/**
51 	 * Creates a new action. The action configures its initial visual
52 	 * representation from the given resource bundle. If this action's
53 	 * wrapped action is set to <code>null</code> it also uses the
54 	 * information in the resource bundle.
55 	 *
56 	 * @param bundle the resource bundle
57 	 * @param prefix a prefix to be prepended to the various resource keys
58 	 *   (described in <code>ResourceAction</code> constructor), or
59 	 *   <code>null</code> if none
60 	 * @param	style one of <code>IAction.AS_PUSH_BUTTON</code>, <code>IAction.AS_CHECK_BOX</code>,
61 	 *			and <code>IAction.AS_RADIO_BUTTON</code>.
62 	 *
63 	 * @see ResourceAction#ResourceAction(ResourceBundle, String, int)
64 	 * @see IAction#AS_CHECK_BOX
65 	 * @see IAction#AS_DROP_DOWN_MENU
66 	 * @see IAction#AS_PUSH_BUTTON
67 	 * @see IAction#AS_RADIO_BUTTON
68 	 * @since 2.1
69 	 */
RetargetTextEditorAction(ResourceBundle bundle, String prefix, int style)70 	public RetargetTextEditorAction(ResourceBundle bundle, String prefix, int style) {
71 		super(bundle, prefix, style);
72 		fDefaultText= getText();
73 		installHelpListener();
74 	}
75 
76 	/**
77 	 * Creates a new action. The action configures its initial visual
78 	 * representation from the given resource bundle. If this action's
79 	 * wrapped action is set to <code>null</code> it also uses the
80 	 * information in the resource bundle.
81 	 *
82 	 * @param bundle the resource bundle
83 	 * @param prefix a prefix to be prepended to the various resource keys
84 	 *   (described in <code>ResourceAction</code> constructor), or
85 	 *   <code>null</code> if none
86 	 * @see ResourceAction#ResourceAction(ResourceBundle, String)
87 	 */
RetargetTextEditorAction(ResourceBundle bundle, String prefix)88 	public RetargetTextEditorAction(ResourceBundle bundle, String prefix) {
89 		super(bundle, prefix);
90 		fDefaultText= getText();
91 		installHelpListener();
92 	}
93 
94 	/**
95 	 * Creates a new action. The action configures its initial visual
96 	 * representation from the given resource bundle. If this action's
97 	 * wrapped action is set to <code>null</code> it also uses the
98 	 * information in the resource bundle. The action gets the given
99 	 * action id.
100 	 *
101 	 * @param bundle the resource bundle
102 	 * @param prefix a prefix to be prepended to the various resource keys
103 	 *   (described in <code>ResourceAction</code> constructor), or <code>null</code> if none
104 	 * @param actionId the action id
105 	 * @param	style one of <code>IAction.AS_PUSH_BUTTON</code>, <code>IAction.AS_CHECK_BOX</code>,
106 	 *			and <code>IAction.AS_RADIO_BUTTON</code>.
107 	 *
108 	 * @see ResourceAction#ResourceAction(ResourceBundle, String, int)
109 	 * @see IAction#AS_CHECK_BOX
110 	 * @see IAction#AS_DROP_DOWN_MENU
111 	 * @see IAction#AS_PUSH_BUTTON
112 	 * @see IAction#AS_RADIO_BUTTON
113 	 * @since 2.1
114 	 */
RetargetTextEditorAction(ResourceBundle bundle, String prefix, String actionId, int style)115 	public RetargetTextEditorAction(ResourceBundle bundle, String prefix, String actionId, int style) {
116 		super(bundle, prefix, style);
117 		fDefaultText= getText();
118 		setId(actionId);
119 		installHelpListener();
120 	}
121 
122 	/**
123 	 * Creates a new action. The action configures its initial visual
124 	 * representation from the given resource bundle. If this action's
125 	 * wrapped action is set to <code>null</code> it also uses the
126 	 * information in the resource bundle. The action gets the given
127 	 * action id.
128 	 *
129 	 * @param bundle the resource bundle
130 	 * @param prefix a prefix to be prepended to the various resource keys
131 	 *   (described in <code>ResourceAction</code> constructor), or <code>null</code> if none
132 	 * @param actionId the action id
133 	 * @see ResourceAction#ResourceAction(ResourceBundle, String)
134 	 * @since 2.0
135 	 */
RetargetTextEditorAction(ResourceBundle bundle, String prefix, String actionId)136 	public RetargetTextEditorAction(ResourceBundle bundle, String prefix, String actionId) {
137 		super(bundle, prefix);
138 		fDefaultText= getText();
139 		setId(actionId);
140 		installHelpListener();
141 	}
142 
143 	/**
144 	 * Updates to the changes of the underlying action.
145 	 *
146 	 * @param event the change event describing the state change
147 	 */
update(PropertyChangeEvent event)148 	private void update(PropertyChangeEvent event) {
149 		if (ENABLED.equals(event.getProperty())) {
150 			Boolean bool= (Boolean) event.getNewValue();
151 			setEnabled(bool.booleanValue());
152 		} else if (TEXT.equals(event.getProperty()))
153 			setText((String) event.getNewValue());
154 		else if (TOOL_TIP_TEXT.equals(event.getProperty()))
155 			setToolTipText((String) event.getNewValue());
156 		else if (CHECKED.equals(event.getProperty())) {
157 			Boolean bool= (Boolean) event.getNewValue();
158 			setChecked(bool.booleanValue());
159 		}
160 	}
161 
162 	/**
163 	 * Sets the underlying action.
164 	 *
165 	 * @param action the underlying action
166 	 */
setAction(IAction action)167 	public void setAction(IAction action) {
168 
169 		if (fAction != null) {
170 			fAction.removePropertyChangeListener(fListener);
171 			fAction= null;
172 		}
173 
174 		fAction= action;
175 
176 		if (fAction == null) {
177 
178 			setEnabled(false);
179 			if (getStyle() == AS_CHECK_BOX || getStyle() == AS_RADIO_BUTTON)
180 				setChecked(false);
181 			setText(fDefaultText);
182 			setToolTipText(""); //$NON-NLS-1$
183 
184 		} else {
185 
186 			setEnabled(fAction.isEnabled());
187 			if (fAction.getStyle() == AS_CHECK_BOX || fAction.getStyle() ==  AS_RADIO_BUTTON)
188 				super.setChecked(fAction.isChecked());
189 			setText(fAction.getText());
190 			setToolTipText(fAction.getToolTipText());
191 			fAction.addPropertyChangeListener(fListener);
192 		}
193 	}
194 
195 	/**
196 	 * Installs the help listener.
197 	 *
198 	 * @since 2.1
199 	 */
installHelpListener()200 	private void installHelpListener() {
201 		super.setHelpListener(e -> {
202 			HelpListener listener= null;
203 			if (fAction != null) {
204 				// if we have a handler, see if it has a help listener
205 				listener= fAction.getHelpListener();
206 				if (listener == null)
207 					// use our own help listener
208 					listener= fLocalHelpListener;
209 			}
210 			if (listener != null)
211 				// pass on the event
212 				listener.helpRequested(e);
213 		});
214 	}
215 
216 	/**
217 	 * The <code>RetargetTextEditorAction</code> implementation of this method declared on
218 	 * <code>IAction</code> stores the help listener in a local field. The
219 	 * supplied listener is only used if there is no handler.
220 	 *
221 	 * @param listener the help listener
222 	 * @since 2.1
223 	 */
224 	@Override
setHelpListener(HelpListener listener)225 	public void setHelpListener(HelpListener listener) {
226 		fLocalHelpListener= listener;
227 	}
228 
229 	@Override
run()230 	public void run() {
231 		if (fAction != null)
232 			fAction.run();
233 	}
234 }
235