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

Last change on this file since 479 was 479, checked in by davidb, 11 years ago

When adding in support for a third attribute for an arrow head (nibb thickness) the 'extra parameter' mechnanism was found to be faulty. The 3rd param for arrow head was not seen as it's strongly type value, but treated as an extra param of type string. This code change is to more carefully test for when there is evidence of extra parameters supplied to an action/agent

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