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

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

Auto-correct widget names with invalid capitalisation and/or missing widget package prefix

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