source: trunk/src/org/expeditee/actions/Actions.java@ 919

Last change on this file since 919 was 919, checked in by jts21, 10 years ago

Added license headers to all files, added full GPL3 license file, moved license header generator script to dev/bin/scripts

File size: 28.8 KB
Line 
1/**
2 * Actions.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.actions;
20
21import java.awt.GraphicsEnvironment;
22import java.io.File;
23import java.io.IOException;
24import java.lang.reflect.Constructor;
25import java.lang.reflect.Method;
26import java.lang.reflect.Modifier;
27import java.net.URL;
28import java.net.URI;
29import java.net.URLDecoder;
30import java.net.JarURLConnection;
31import java.rmi.UnexpectedException;
32import java.util.ArrayList;
33import java.util.Collection;
34import java.util.Enumeration;
35import java.util.HashMap;
36import java.util.LinkedList;
37import java.util.List;
38import java.util.Set;
39import java.util.jar.JarEntry;
40import java.util.jar.JarFile;
41import java.util.zip.ZipEntry;
42
43import org.expeditee.agents.Agent;
44import org.expeditee.gui.DisplayIO;
45import org.expeditee.gui.Frame;
46import org.expeditee.gui.FrameGraphics;
47import org.expeditee.gui.FrameIO;
48import org.expeditee.gui.FrameUtils;
49import org.expeditee.gui.FreeItems;
50import org.expeditee.gui.MessageBay;
51import org.expeditee.io.Conversion;
52import org.expeditee.items.Item;
53import org.expeditee.items.ItemUtils;
54import org.expeditee.items.Text;
55import org.expeditee.reflection.PackageLoader;
56import org.expeditee.settings.UserSettings;
57import org.expeditee.simple.SString;
58import org.expeditee.stats.Logger;
59
60/**
61 * The Action class is used to launch Actions and Agents.
62 *
63 * This class checks all class files in the same directory, and reads in and adds all the methods from them. The methods
64 * are stored in a Hashtable so that the lowercase method names can be mapped to the correctly capatilized method names
65 * (to provide case-insensitivity)
66 *
67 * When adding an action to a class in the actions folder the following must be considered: <li>If the first parameter
68 * is of type Frame, the current frame will be passed as a parameter. <li>If the next param is of type Item the item on
69 * the end of the cursor will be passed or the item that was clicked to execute the action if nothing is on the end of
70 * the cursor. current frame or item.</li> <li>If there are multiple overloads for the same method they should be
71 * declared in order of the methods with the most parameteres to least parameters.</li>
72 */
73public class Actions {
74
75 private static final String INVALID_PARAMETERS_ERROR = "Invalid parameters for agent: "; //$NON-NLS-1$
76
77 // the currently running agent (if there is one)
78 private static Agent _Agent = null;
79
80 // maps lower case method names to the method
81 private static HashMap<String, Method> _Actions = new HashMap<String, Method>();
82
83 // map lower case fonts to capitalized fonts
84 private static HashMap<String, String> _Fonts = new HashMap<String, String>();
85
86 // maps lower case JAG class names to capitalized JAG full class names
87 private static HashMap<String, String> _JAGs = new HashMap<String, String>();
88
89 // maps lower case IW class names to capitalized IW names
90 private static HashMap<String, String> _IWs = new HashMap<String, String>();
91
92 public static final String ROOT_PACKAGE = "org.expeditee.";
93
94 // Package and class file locations
95 public static final String ACTIONS_PACKAGE = ROOT_PACKAGE + "actions.";
96
97 public static final String AGENTS_PACKAGE = ROOT_PACKAGE + "agents.";
98
99 public static final String WIDGET_PACKAGE = ROOT_PACKAGE + "items.widgets.";
100
101 public static final String CHARTS_PACKAGE = ROOT_PACKAGE + "items.widgets.charts.";
102
103 public static final String NAVIGATIONS_CLASS = ROOT_PACKAGE + "actions.NavigationActions";
104
105 // public static Class[] getClasses(String pckgname)
106 // throws ClassNotFoundException {
107 // ArrayList<Class> classes = new ArrayList<Class>();
108 // // Get a File object for the package
109 // File directory = null;
110 // // Must be a forward slash for loading resources
111 // String path = pckgname.replace('.', '/');
112 // System.err.println("Get classes: " + path);
113 // try {
114 // ClassLoader cld = Thread.currentThread().getContextClassLoader();
115 // if (cld == null) {
116 // throw new ClassNotFoundException("Can't get class loader.");
117 // }
118 // URL resource = null;
119 // try {
120 // Enumeration<URL> resources = cld.getResources(path);
121 // System.err.println(resources);
122 // while (resources.hasMoreElements()) {
123 // URL url = resources.nextElement();
124 // // Ingore the classes in the test folder when we are running
125 // // the program from Eclipse
126 // // This doesnt apply when running directly from the jar
127 // // because the test classes are not compiled into the jar.
128 // // TODO change this so it is only done when running from
129 // // Eclipse... if it causes problems again!!
130 // // if (!url.toString().toLowerCase().contains("/tests/")) {
131 // resource = url;
132 // // break;
133 // // }
134 // }
135 // } catch (Exception e) {
136 // e.printStackTrace();
137 // }
138 // if (resource == null) {
139 // throw new ClassNotFoundException("No resource for " + path);
140 // }
141 // directory = new File(resource.getFile());
142 // } catch (NullPointerException x) {
143 // x.printStackTrace();
144 // throw new ClassNotFoundException(pckgname + " (" + directory
145 // + ") does not appear to be a valid package");
146 // }
147 // // System.out.println("Path:" + directory.getPath());
148 // int splitPoint = directory.getPath().indexOf('!');
149 // if (splitPoint > 0) {
150 // try {
151 // String jarName = directory.getPath().substring(
152 // "file:".length(), splitPoint);
153 // // Windows HACK
154 // if (jarName.indexOf(":") >= 0)
155 // jarName = jarName.substring(1);
156 //
157 // if (jarName.indexOf("%20") > 0) {
158 // jarName = jarName.replace("%20", " ");
159 // }
160 // // System.out.println("JarName:" + jarName);
161 // JarFile jarFile = new JarFile(jarName);
162 //
163 // Enumeration entries = jarFile.entries();
164 // int classCount = 0;
165 // while (entries.hasMoreElements()) {
166 // ZipEntry entry = (ZipEntry) entries.nextElement();
167 // String className = entry.getName();
168 // if (className.startsWith(path)) {
169 // if (className.endsWith(".class")
170 // && !className.contains("$")) {
171 // classCount++;
172 // // The forward slash below is a forwards slash for
173 // // both windows and linux
174 // classes.add(Class.forName(className.substring(0,
175 // className.length() - 6).replace('/', '.')));
176 // }
177 // }
178 // }
179 // jarFile.close();
180 // // System.out.println("Loaded " + classCount + " classes from "
181 // // + pckgname);
182 //
183 // } catch (Exception e) {
184 // e.printStackTrace();
185 // }
186 //
187 // } else {
188 //
189 // if (directory.exists()) {
190 // // Get the list of the files contained in the package
191 // String[] files = directory.list();
192 // for (int i = 0; i < files.length; i++) {
193 // // we are only interested in .class files
194 // if (files[i].endsWith(".class") && !files[i].contains("$")
195 // && !files[i].equals("Actions.class")) {
196 // // removes the .class extension
197 // classes
198 // .add(Class.forName(pckgname
199 // + files[i].substring(0, files[i]
200 // .length() - 6)));
201 // }
202 // }
203 // } else {
204 // throw new ClassNotFoundException("The package '" + pckgname +
205 // "' in the directory '" + directory
206 // + "' does not appear to be a valid package");
207 // }
208 // }
209 // Class[] classesA = new Class[classes.size()];
210 // classes.toArray(classesA);
211 // return classesA;
212 // }
213
214 /**
215 * Clears out the Action and JAG Hashtables and refills them. Normally this is only called once when the system
216 * starts.
217 *
218 * @return a warning message if there were any problems loading agents or actions.
219 */
220 public static Collection<String> Init() {
221
222 Collection<String> warnings = new LinkedList<String>();
223 List<Class<?>> classes;
224
225 try {
226 classes = PackageLoader.getClassesNew(AGENTS_PACKAGE);
227
228 for (Class clazz : classes) {
229 String name = clazz.getSimpleName();
230 // maps lower case name to correct capitalised name
231 _JAGs.put(name.toLowerCase(), clazz.getName());
232 }
233
234
235 classes = PackageLoader.getClassesNew(WIDGET_PACKAGE);
236
237 for (Class clazz : classes) {
238 String name = clazz.getSimpleName();
239 // maps lower case name to correct capitalised name
240 _IWs.put(name.toLowerCase(), WIDGET_PACKAGE + name);
241 }
242
243
244 classes = PackageLoader.getClassesNew(CHARTS_PACKAGE);
245
246 for (Class clazz : classes) {
247 String name = clazz.getSimpleName();
248 // maps lower case name to correct capitalised name
249 _IWs.put("charts." + name.toLowerCase(), CHARTS_PACKAGE + name);
250 }
251 } catch (ClassNotFoundException e) {
252 System.err.println("ClassNotFoundException");
253 e.printStackTrace();
254 } catch (Exception e) {
255 warnings.add("You must have Java 1.5 or higher to run Expeditee");
256 warnings.add(e.getMessage());
257 e.printStackTrace();
258 }
259
260 try {
261 classes = PackageLoader.getClassesNew(ACTIONS_PACKAGE);
262
263 for (Class clazz : classes) {
264 String name = clazz.getSimpleName();
265 // Ignore the test classes
266 if (name.toLowerCase().contains("test"))
267 continue;
268 // read in all the methods from the class
269 try {
270 // System.out.println(name)
271 LoadMethods(Class.forName(ACTIONS_PACKAGE + name));
272 } catch (ClassNotFoundException e) {
273 Logger.Log(e);
274 e.printStackTrace();
275 }
276 }
277 } catch (Exception e) {
278 warnings.add(e.getMessage());
279 }
280 return warnings;
281 }
282
283 /**
284 * Temporary, if a plugin system is devised then this would porbably become redundant. For now this allows external
285 * agents to be included.
286 *
287 * @param fullClassNames
288 * A set of full class names, that is, the class package and name. For
289 * example" "org.myplugin.agents.SerializedSearch"
290 *
291 * @return A collection of classes their were omitted because either there was a name clash with existing agents or
292 * did not exist. i.e. is completely successful this will be empty. Never null.
293 *
294 * @throws NullPointerException
295 * If fullClassNames is null.
296 *
297 */
298 public static Collection<String> addAgents(Set<String> fullClassNames) {
299 if (fullClassNames == null)
300 throw new NullPointerException("fullClassNames");
301
302 List<String> omittedAgents = new LinkedList<String>();
303
304 for (String fullName : fullClassNames) {
305
306 if (fullName == null || fullName.length() == 0)
307 continue;
308
309 boolean didAdd = false;
310
311 try {
312 // Does the class even exist?
313 Class<?> c = Class.forName(fullName);
314
315 String name = c.getSimpleName().toLowerCase();
316
317 if (!_JAGs.containsKey(name)) {
318
319 _JAGs.put(name, fullName);
320 didAdd = true;
321
322 }
323
324 } catch (ClassNotFoundException e) { // Nope it does not exist
325 e.printStackTrace();
326 }
327
328 if (!didAdd)
329 omittedAgents.add(fullName);
330
331 }
332
333 return omittedAgents;
334 }
335
336 /**
337 * Loads all the Methods that meet the requirements checked by MethodCheck into the hashtable.
338 *
339 * @param c
340 * The Class to load the Methods from.
341 */
342 public static void LoadMethods(Class<?> c) {
343 assert (c != null);
344
345 // list of methods to test
346 Method[] toLoad = c.getMethods();
347
348 for (Method m : toLoad) {
349 // only allow methods with the right modifiers
350 if (MethodCheck(m)) {
351 String lowercaseName = m.getName().toLowerCase();
352 if (!(_Actions.containsKey(lowercaseName)))
353 _Actions.put(lowercaseName, m);
354 else {
355 int i = 0;
356 while (_Actions.containsKey(lowercaseName + i))
357 i++;
358
359 _Actions.put(lowercaseName + i, m);
360 }
361
362 }
363 }
364 }
365
366 /**
367 * Checks if the given Method corresponds to the restrictions of Action commands, namely: Declared (not inherited),
368 * Public, and Static, with a void return type.
369 *
370 * @param m
371 * The Method to check
372 * @return True if the Method meets the above conditions, false otherwise.
373 */
374 private static boolean MethodCheck(Method m) {
375 int mods = m.getModifiers();
376
377 // check the method is declared (not inherited)
378 if ((mods & Method.DECLARED) != Method.DECLARED)
379 return false;
380
381 // check the method is public
382 if ((mods & Modifier.PUBLIC) != Modifier.PUBLIC)
383 return false;
384
385 // check the method is static
386 if ((mods & Modifier.STATIC) != Modifier.STATIC)
387 return false;
388
389 // if we have not returned yet, then the tests have all passed
390 return true;
391 }
392
393 /**
394 * Performs the given action command. The source Frame and Item are given because they are required by some actions.
395 * Note that the source frame does not have to be the Item's parent Frame.
396 *
397 * @param source
398 * The Frame that the action should apply to
399 * @param launcher
400 * The Item that has the action assigned to it
401 * @param command
402 * The action to perform
403 */
404 public static Object PerformAction(Frame source, Item launcher, String command) throws Exception {
405 // if (!command.equalsIgnoreCase("Restore"))
406 // FrameIO.SaveFrame(source, false);
407 // TODO make restore UNDO the changes made by the last action
408
409 // separate method name and parameter names
410 String mname = getName(command);
411 command = command.substring(mname.length()).trim();
412 // If no params are provided get them from a text item on the cursor
413 if (command.length() == 0 && launcher instanceof Text && launcher.isFloating()) {
414 command = launcher.getText();
415 }
416
417 // Strip off the @ from annotation items
418 if (mname.startsWith("@"))
419 mname = mname.substring(1);
420
421 mname = mname.trim();
422 String lowercaseName = mname.toLowerCase();
423 // check for protection on frame
424 if (ItemUtils.ContainsTag(source.getItems(), "@No" + mname)) {
425 throw new RuntimeException("Frame is protected by @No" + mname + " tag.");
426 }
427
428 // retrieve methods that match the name
429 Method toRun = _Actions.get(lowercaseName);
430
431 // if this is not the name of a method, it may be the name of an agent
432 if (toRun == null) {
433 LaunchAgent(mname, command, source, launcher);
434 return null;
435 }
436
437 // Need to save the frame if we are navigating away from it so we dont
438 // loose changes
439 if (toRun.getDeclaringClass().getName().equals(NAVIGATIONS_CLASS)) {
440 FrameIO.SaveFrame(DisplayIO.getCurrentFrame());
441 }
442
443 // if there are duplicate methods with the same name
444 List<Method> possibles = new LinkedList<Method>();
445 possibles.add(toRun);
446 int i = 0;
447 while (_Actions.containsKey(lowercaseName + i)) {
448 possibles.add(_Actions.get(lowercaseName + i));
449 i++;
450 }
451
452 for (Method possible : possibles) {
453 // try first with the launching item as a parameter
454
455 // run method
456 try {
457 // convert parameters to objects and get the method to invoke
458 Object[] parameters = CreateObjects(possible, source, launcher, command);
459 // Check that there are the same amount of params
460 if (parameters == null) {
461 continue;
462 }
463
464 return possible.invoke(null, parameters);
465 } catch (Exception e) {
466 Logger.Log(e);
467 e.printStackTrace();
468 }
469 }
470 // If the actions was not found... then it is run as an agent
471 assert (possibles.size() > 0);
472 throw new RuntimeException("Incorrect parameters for " + mname);
473 }
474
475 /**
476 * Launches an agent with the given name, and passes in the given parameters
477 *
478 * @param name
479 * The name of the JAG to load
480 * @param parameters
481 * The parameters to pass to the JAG
482 * @param source
483 * The starting Frame that the JAG is being launched on
484 */
485 private static void LaunchAgent(String name, String parameters, Frame source, Item clicked) throws Exception {
486 // Use the correct case version for printing error messages
487 String nameWithCorrectCase = name;
488 name = name.toLowerCase();
489
490 String fullClassName = AGENTS_PACKAGE + name;
491
492 try {
493 // check for stored capitalisation
494 if (_JAGs.containsKey(name)) {
495 fullClassName = _JAGs.get(name);
496 } else if (name.endsWith("tree")) {
497 parameters = name.substring(0, name.length() - "tree".length()) + " " + parameters;
498 fullClassName = AGENTS_PACKAGE + "writetree";
499
500 } else if (name.endsWith("frame")) {
501 parameters = name.substring(0, name.length() - "frame".length()) + " " + parameters;
502 fullClassName = AGENTS_PACKAGE + "writeframe";
503 }
504
505 // load the JAG class
506 Class<?> agentClass = Class.forName(fullClassName);
507
508 // get the constructor for the JAG class
509 Constructor<?> con = null;
510 Constructor<?>[] constructors = agentClass.getConstructors();
511 Object[] params = null;
512
513 parameters = parameters.trim();
514 // determine correct parameters for constructor
515 for (Constructor<?> c : constructors) {
516 Class<?>[] paramTypes = c.getParameterTypes();
517 int paramCount = paramTypes.length;
518 if (paramCount > 0 && parameters.length() > 0) {
519 params = new Object[paramCount];
520 String[] paramStrings = parameters.split("\\s+");
521 /**
522 * Any extra parameters will be treated as the rest of the string if the last param is a string
523 */
524 if (paramCount > paramStrings.length) {
525 continue;
526 }
527
528 /**
529 * If there are extra parameters the last param must be a String
530 */
531 int lastParam = paramTypes.length - 1;
532
533 if (paramCount < paramStrings.length && !paramTypes[lastParam].equals(String.class)) {
534 continue;
535 }
536
537 try {
538 for (int i = 0; i < paramCount; i++) {
539 SString nextParam = new SString(paramStrings[i]);
540 params[i] = null;
541 if (paramTypes[i].equals(int.class) || paramTypes[i].equals(Integer.class)) {
542 params[i] = nextParam.integerValue().intValue();
543 } else if (paramTypes[i].equals(long.class) || paramTypes[i].equals(Long.class)) {
544 params[i] = nextParam.integerValue();
545 } else if (paramTypes[i].equals(double.class) || paramTypes[i].equals(Double.class)) {
546 params[i] = nextParam.doubleValue();
547 } else if (paramTypes[i].equals(float.class) || paramTypes[i].equals(Float.class)) {
548 params[i] = nextParam.doubleValue().floatValue();
549 } else if (paramTypes[i].equals(boolean.class) || paramTypes[i].equals(Boolean.class)) {
550 params[i] = nextParam.booleanValue();
551 } else if (paramTypes[i].equals(String.class)) {
552 params[i] = nextParam.stringValue();
553 } else {
554 throw new UnexpectedException("Unexpected type " + paramTypes[i].getClass().toString());
555 }
556 }
557 } catch (Exception e) {
558 continue;
559 }
560
561 if (paramCount < paramStrings.length) {
562
563 /**
564 * Append extra params on the end of the last string param
565 */
566 String s = params[lastParam].toString();
567 for (int i = paramCount; i < paramStrings.length; i++) {
568 s += ' ' + paramStrings[i];
569 }
570 params[lastParam] = s;
571 }
572
573 con = c;
574 break;
575 } else if (c.getParameterTypes().length == 0 && con == null) {
576 con = c;
577 params = null;
578 }
579 }
580
581 // if there is no constructor, return
582 if (con == null) {
583 throw new RuntimeException(INVALID_PARAMETERS_ERROR + nameWithCorrectCase);
584 }
585
586 // create the JAG
587 Agent toLaunch = (Agent) con.newInstance(params);
588
589 LaunchAgent(toLaunch, source, clicked);
590
591 } catch (ClassNotFoundException cnf) {
592 _Agent = null;
593 throw new RuntimeException("'" + nameWithCorrectCase + "' is not an action or agent.");
594 }
595 }
596
597 public static void LaunchAgent(String name, String parameters, Frame source) throws Exception {
598 LaunchAgent(name, parameters, source, null);
599 }
600
601 /**
602 * Launches an agent from an already instantiated object.
603 *
604 * @param agent
605 * The agent to launch. Must not be null.
606 *
607 * @param source
608 * The calling frame that launched it. Must not be null.
609 *
610 * @param itemParam
611 * The item parameter for the agent.
612 *
613 * @throws NullPointerException
614 * if any of the arguments are null.
615 */
616 public static void LaunchAgent(Agent agent, Frame source, Item itemParam) {
617
618 if (agent == null)
619 throw new NullPointerException("agent");
620 if (source == null)
621 throw new NullPointerException("source");
622 // if (itemParam == null) throw new NullPointerException("itemParam");
623
624 String nameWithCorrectCase = agent.getClass().getSimpleName();
625
626 try {
627
628 // create the JAG
629 _Agent = agent;
630
631 Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
632 public void uncaughtException(Thread th, Throwable ex) {
633
634 MessageBay.errorMessage("Error occurred in Action: " + th.getName());
635 ex.printStackTrace();
636
637 stopAgent();
638 _Agent = null;
639 }
640 };
641
642 Thread t = new Thread(_Agent,nameWithCorrectCase);
643
644 t.setPriority(Thread.MIN_PRIORITY);
645 t.setUncaughtExceptionHandler(h);
646
647 if (FreeItems.textOnlyAttachedToCursor()) {
648 itemParam = FreeItems.getItemAttachedToCursor();
649 }
650
651 // check for errors during initialisation
652 if (!_Agent.initialise(source, itemParam)) {
653 _Agent = null;
654 throw new RuntimeException("Error initialising agent: " + nameWithCorrectCase);
655 }
656
657 // save the current frame (if necesssary)
658 // TODO make this nicer... ie. make Format an action rather than an
659 // agent and save frames only before running agents
660 if (!nameWithCorrectCase.equalsIgnoreCase("format") && !nameWithCorrectCase.equalsIgnoreCase("sort")) {
661 FrameUtils.LeavingFrame(source);
662 }
663
664 if (_Agent.hasResultString()) {
665 // Just run the agent on this thread... dont run it in the
666 // background
667 t.run();
668 if (_Agent != null) {
669 String result = _Agent.toString();
670 // Attach the result to the cursor
671 if (FreeItems.textOnlyAttachedToCursor()) {
672 Item resultItem = FreeItems.getItemAttachedToCursor();
673 resultItem.setText(result);
674 }
675 // if there is a completion frame, then display it to the user
676 }
677 } else {
678 t.start();
679 if (_Agent != null && _Agent.hasResultFrame()) {
680 // TODO We want to be able to navigate through the frames as
681 // the results are loading
682 Frame next = _Agent.getResultFrame();
683 FrameUtils.DisplayFrame(next, true, true);
684 }
685 }
686 } catch (Exception e) {
687 _Agent = null;
688 e.printStackTrace();
689 throw new RuntimeException("Error creating Agent: '" + nameWithCorrectCase + "'");
690 }
691 FrameGraphics.refresh(false);
692 }
693
694 /**
695 * Used to determine if the previously launched agent is still executing.
696 *
697 * @return True if the last Agent is still executing, False otherwise.
698 */
699 public static boolean isAgentRunning() {
700 if (_Agent != null)
701 return _Agent.isRunning();
702
703 return false;
704 }
705
706 /**
707 * Stops the currently running Agent (If there is one) by calling Agent.stop(). Note: This may not stop the Agent
708 * immediately, but the Agent should terminate as soon as it is safe to do so.
709 */
710 public static void stopAgent() {
711 if (_Agent != null && _Agent.isRunning()) {
712 MessageBay.errorMessage("Stopping Agent...");
713 _Agent.stop();
714 }
715 }
716
717 public static void interruptAgent() {
718 if (_Agent != null) {
719 _Agent.interrupt();
720 }
721 }
722
723 /**
724 * Converts the given String of values into an array of Objects
725 *
726 * @param launcher
727 * The Item used to launch the action, it may be required as a parameter
728 * @param values
729 * A list of space separated String values to convert to objects
730 * @return The created array of Objects
731 */
732 public static Object[] CreateObjects(Method method, Frame source, Item launcher, String values) {
733 // The parameter types that should be created from the given String
734 Class<?>[] paramTypes = method.getParameterTypes();
735
736 int paramCount = paramTypes.length;
737 // if the method has no parameters
738 if (paramCount == 0)
739 return new Object[0];
740
741 Object[] objects = new Object[paramCount];
742 int ind = 0;
743
744 /*
745 * if the first class in the list is a frame or item, it is the source or launcher length must be at least one
746 * if we are still running
747 */
748 if (paramTypes[ind] == Frame.class) {
749 objects[ind] = source;
750 ind++;
751 }
752
753 // Check if the second item is an item
754 if (paramCount > ind && Item.class.isAssignableFrom(paramTypes[ind])) {
755 objects[ind] = launcher;
756 ind++;
757 }// If there is stuff on the cursor use it for the rest of the params
758 else if (launcher != null && launcher.isFloating()) {
759 values = launcher.getText();
760 }
761
762 String param = values;
763 // convert the rest of the objects
764 for (; ind < objects.length; ind++) {
765 // check if its the last param and combine
766 if (values.length() > 0 && ind == objects.length - 1) {
767 param = values.trim();
768 // check if its a string
769 if (param.length() > 0 && param.charAt(0) == '"') {
770 int endOfString = param.indexOf('"', 1);
771 if (endOfString > 0) {
772 param = param.substring(1, endOfString);
773 }
774 }
775 } else {// strip off the next value
776 param = ParseValue(values);
777 values = RemainingParams(values);
778 }
779 // convert the value to an object
780 try {
781 Object o = Conversion.Convert(paramTypes[ind], param);
782 if (o == null)
783 return null;
784 objects[ind] = o;
785 } catch (Exception e) {
786 return null;
787 }
788 }
789
790 return objects;
791 }
792
793 /**
794 * Returns a string containing the remaining params after ignoring the first one.
795 *
796 * @param params
797 * a space sparated list of N parameters
798 * @return the remaining N - 1 parameters
799 */
800 public static String RemainingParams(String params) {
801 if (params.length() == 0)
802 return null;
803
804 // remove leading and trailing spaces
805 params = params.trim();
806
807 // if there are no more parameters, we are done
808 if (params.indexOf(" ") < 0) {
809 return "";
810 }
811
812 // Check if we have a string parameter
813 if (params.charAt(0) == '"') {
814 int endOfString = params.indexOf('"', 1);
815 if (endOfString > 0) {
816 if (endOfString > params.length())
817 return "";
818 return params.substring(endOfString + 1).trim();
819 }
820 }
821
822 return params.substring(params.indexOf(" ")).trim();
823 }
824
825 /**
826 * Returns the first value in the space separated String of parameters passed in. Strings are enclosed in double
827 * quotes.
828 *
829 * @param params
830 * The String of space separated values
831 * @return The first value in the String
832 */
833 public static String ParseValue(String params) {
834 if (params.length() == 0)
835 return null;
836
837 // remove leading and trailing spaces
838 String param = params.trim();
839
840 // Check if we have a string parameter
841 if (param.charAt(0) == '"') {
842 int endOfString = param.indexOf('"', 1);
843 if (endOfString > 0)
844 return param.substring(1, endOfString);
845 }
846
847 // if there are no more parameters, we are done
848 if (param.indexOf(" ") < 0) {
849 return param;
850 }
851
852 return param.substring(0, param.indexOf(" "));
853 }
854
855 /**
856 * Separates the name of the given command from any parameters and returns them
857 *
858 * @param command
859 * The String to separate out the Action or Agent name from
860 * @return The name of the Action of Agent with parameters stripped off
861 */
862 private static String getName(String command) {
863 if (command.indexOf(" ") < 0)
864 return command;
865
866 return command.substring(0, command.indexOf(" "));
867 }
868
869 /**
870 * Gets an uncapitalized font name and returns the capitalized font name. The capitalized form can be used with the
871 * Font.decoded method to get a corresponding Font object.
872 *
873 * @param fontName
874 * a font name in mixed case
875 * @return the correct capitalized form of the font name
876 */
877 public static String getCapitalizedFontName(String fontName) {
878 // Initialize the fonts if they have not already been loaded
879 initFonts();
880 return _Fonts.get(fontName.toLowerCase());
881 }
882
883 /**
884 * Initialise the fontsList if it has not been done already
885 */
886 private static void initFonts() {
887 if (_Fonts.size() == 0) {
888 String[] availableFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
889 for (String s : availableFonts) {
890 _Fonts.put(s.toLowerCase(), s);
891 }
892 }
893 }
894
895 public static HashMap<String, String> getFonts() {
896 initFonts();
897 return _Fonts;
898 }
899
900 public static Object PerformActionCatchErrors(Frame current, Item launcher, String command) {
901 try {
902 return PerformAction(current, launcher, command);
903 } catch (RuntimeException e) {
904 e.printStackTrace();
905 MessageBay.errorMessage("Action failed: " + e.getMessage());
906 } catch (Exception e) {
907 e.printStackTrace();
908 MessageBay.errorMessage("Action failed: " + e.getClass().getSimpleName());
909 }
910 return null;
911 }
912
913 /**
914 * Gets the full class path for a widget with a given case insensitive name.
915 *
916 * @param widgetName
917 * @return
918 */
919 public static String getClassName(String widgetName) {
920 return _IWs.get(widgetName.toLowerCase());
921 }
922
923 static List<String> getActions() {
924 List<String> actionNames = new LinkedList<String>();
925 for (Method m : _Actions.values()) {
926 StringBuilder sb = new StringBuilder();
927 sb.append(m.getName());
928 for (Class<?> c : m.getParameterTypes()) {
929 sb.append(" ").append(c.getSimpleName());
930 }
931 actionNames.add(sb.toString());
932 }
933
934 return actionNames;
935 }
936
937 static List<String> getAgents() {
938 List<String> agentNames = new LinkedList<String>();
939
940 for (String s : _JAGs.values()) {
941 agentNames.add(s.substring(s.lastIndexOf('.') + 1));
942 }
943
944 return agentNames;
945 }
946}
Note: See TracBrowser for help on using the repository browser.