1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.gui.action;
21
22 import java.awt.event.ActionEvent;
23 import java.io.File;
24 import java.io.IOException;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Hashtable;
28 import java.util.Iterator;
29 import java.util.LinkedList;
30
31 import javax.swing.Action;
32 import javax.swing.JComponent;
33 import javax.swing.JPopupMenu;
34 import javax.swing.text.DefaultEditorKit;
35
36 import org.xnap.XNap;
37 import org.xnap.action.ToggleAction;
38 import org.xnap.gui.StatusBar;
39 import org.xnap.gui.component.XNapCheckBoxMenuItem;
40 import org.xnap.gui.component.XNapMenuItem;
41 import org.xnap.gui.menu.AbstractDynamicMenu;
42 import org.xnap.gui.util.IconHelper;
43 import org.xnap.util.launcher.Player;
44 import org.xnap.util.launcher.PlayerManager;
45
46 /***
47 * This class provides a set of static actions.
48 */
49 public class ActionHelper
50 {
51
52
53
54 /***
55 * Default clipboard copy action that operates on any
56 * <code>JTextComponent</code>.
57 */
58 public static Action copyAction;
59 static {
60 copyAction = new DefaultEditorKit.CopyAction();
61 copyAction.putValue(Action.NAME, XNap.tr("Copy"));
62 copyAction.putValue(Action.SHORT_DESCRIPTION,
63 XNap.tr("Copies selected text to clipboard."));
64 copyAction.putValue(IconHelper.XNAP_ICON, "editcopy.png");
65 }
66
67 /***
68 * Default clipboard cut action that operates on any
69 * <code>JTextComponent</code>.
70 */
71 public static Action cutAction;
72 static {
73 cutAction = new DefaultEditorKit.CutAction();
74 cutAction.putValue(Action.NAME, XNap.tr("Cut"));
75 cutAction.putValue(Action.SHORT_DESCRIPTION,
76 XNap.tr("Moves selected text to clipboard."));
77 cutAction.putValue(IconHelper.XNAP_ICON, "editcut.png");
78 }
79
80 /***
81 * Default clipboard paste action that operates on any
82 * <code>JTextComponent</code>.
83 */
84 public static Action pasteAction;
85 static {
86 pasteAction = new DefaultEditorKit.PasteAction();
87 pasteAction.putValue(Action.NAME, XNap.tr("Paste"));
88 pasteAction.putValue(Action.SHORT_DESCRIPTION,
89 XNap.tr("Pastes clipboard contents."));
90 pasteAction.putValue(IconHelper.XNAP_ICON, "editpaste.png");
91 }
92
93 public static Action pluginPreferencesDialogAction;
94 static {
95 pluginPreferencesDialogAction = new PluginPreferencesDialogAction();
96 pluginPreferencesDialogAction.setEnabled(false);
97 }
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 /***
117 * Uses the ActionExtractor to extract the common actions from all objects
118 * in the array and adds them to the AbstractDynamicMenu as temporaries.
119 *
120 * @return -1, if nothing was added; the number of actions that were added
121 * to <code>jm</code>, otherwise
122 */
123 public static int addCommonActions(AbstractDynamicMenu jm,
124 Object[] object, ActionExtractor ae,
125 int startIndex)
126 {
127 Collection actions = getCommonActions(object, ae);
128 if (actions != null) {
129 int index = startIndex;
130 for (Iterator i = actions.iterator(); i.hasNext();) {
131 Action action = (Action)i.next();
132 jm.addTemporary(createMenuItem(action), index);
133 index++;
134 }
135 return index - startIndex;
136 }
137 return -1;
138 }
139
140 public static int addCommonActions(AbstractDynamicMenu jm,
141 Object[] object, ActionExtractor ae)
142 {
143 return addCommonActions(jm, object, ae, 0);
144 }
145
146 /***
147 * Returns a collection of common actions in <code>objects</code>.
148 */
149 public static Collection getCommonActions(Object[] items,
150 ActionExtractor ae)
151 {
152 if (items != null) {
153 if (items.length == 1) {
154 Action[] actions = ae.getActions(items[0]);
155 if (actions != null) {
156 return Arrays.asList(actions);
157 }
158 }
159 else {
160
161 Hashtable containerByAction = new Hashtable();
162
163
164 Action[] refActions = ae.getActions(items[0]);
165 if (refActions != null) {
166 for (int i = 0; i < refActions.length; i++) {
167 if (refActions[i] != null) {
168 containerByAction.put
169 (refActions[i],
170 new ActionContainer(refActions[i]));
171 }
172 }
173 }
174
175 for (int i = 1; (i < items.length
176 && containerByAction.size() > 0); i++) {
177 Action[] actions = ae.getActions(items[i]);
178 if (actions != null && actions.length > 0) {
179 retainAll(containerByAction, actions);
180 }
181 else {
182 containerByAction.clear();
183 }
184 }
185
186 if (containerByAction.size() > 0) {
187
188 LinkedList sorted = new LinkedList();
189 for (int i = 0; i < refActions.length; i++) {
190 if (refActions[i] != null
191 && containerByAction.containsKey(refActions[i])) {
192
193 sorted.add(containerByAction.get(refActions[i]));
194 }
195 }
196 return sorted;
197 }
198 }
199 }
200
201 return null;
202 }
203
204 /***
205 * MenuItem factory.
206 */
207 public static JComponent createMenuItem(Action action)
208 {
209 if (action == null) {
210 return new JPopupMenu.Separator();
211 }
212 else if (action instanceof ToggleAction) {
213 return new XNapCheckBoxMenuItem((ToggleAction)action);
214 }
215 else if (action instanceof SubmenuAction) {
216 return ((SubmenuAction)action).createMenu();
217 }
218 else {
219 return new XNapMenuItem(action);
220 }
221 }
222
223 /***
224 * This is O(n^2);
225 */
226 private static void retainAll(Hashtable containerByAction,
227 Action[] actions)
228 {
229 for (Iterator it = containerByAction.keySet().iterator();
230 it.hasNext();) {
231 Object key = it.next();
232 boolean contained = false;
233
234 for (int i = 0; i < actions.length && !contained; i++) {
235 if (actions[i] != null
236 && key.equals(actions[i])
237 && actions[i].equals(key)) {
238
239 ActionContainer ac
240 = (ActionContainer)containerByAction.get(key);
241 ac.add(actions[i]);
242 contained = true;
243 }
244 }
245 if (!contained) {
246
247 it.remove();
248 }
249 }
250 }
251
252 public interface ActionExtractor {
253
254 Action[] getActions(Object o);
255
256 }
257
258 /***
259 * Used by the Play...Actions for enqueueing files.
260 *
261 * A thread is used if when array size surpasses 5 elements.
262 *
263 * @param files array of files to be enqueued
264 * @param playFirst play first file
265 */
266 public static void enqueueFiles(final File[] files,
267 final boolean playFirst)
268 {
269 if (files.length < 5) {
270 enqueue(files, playFirst);
271 }
272 else {
273 Thread t = new Thread("EnqueueThread")
274 {
275 public void run()
276 {
277 enqueue(files, playFirst);
278 }
279 };
280 t.start();
281 }
282 }
283
284 private static void enqueue(File[] files, boolean playFirst)
285 {
286 Player player = PlayerManager.getInstance().getDefaultPlayer();
287
288 if (player == null) {
289 StatusBar.setText(XNap.tr("Could not launch player"));
290 return;
291 }
292
293 for (int i = 0; i < files.length; i++) {
294 try {
295 if (files[i] != null && files[i].length() > 0
296 && player.canPlay(files[i])) {
297 if (playFirst) {
298 player.open(files[i]);
299 playFirst = false;
300 }
301 else {
302 player.enqueue(files[i]);
303 }
304 }
305 }
306 catch (IOException e) {
307 }
308 }
309 }
310
311 public static boolean perform(Action[] actions, ActionEvent event, Class requiredInterface)
312 {
313 if (actions != null) {
314 for (int i = 0; i < actions.length; i++) {
315 if (actions[i] != null
316 && actions[i].isEnabled()
317 && requiredInterface.isInstance(actions[i])) {
318
319 actions[i].actionPerformed(event);
320 return true;
321 }
322 }
323 }
324 return false;
325 }
326
327 }
328