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

Last change on this file since 437 was 437, checked in by davidb, 12 years ago

Fixed a couple of typos in comments.

File size: 27.1 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 parametres 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 * If there are extra parametres the last param must be a
519 * String
520 */
521 int lastParam = paramTypes.length - 1;
522
523 if (paramCount < paramStrings.length
524 && !paramTypes[lastParam].equals(String.class))
525 continue;
526 try {
527 for (int i = 0; i < paramCount; i++) {
528 SString nextParam = new SString(paramStrings[i]);
529 params[i] = null;
530 if (paramTypes[i].equals(int.class)
531 || paramTypes[i].equals(Integer.class)) {
532 params[i] = nextParam.integerValue().intValue();
533 } else if (paramTypes[i].equals(long.class)
534 || paramTypes[i].equals(Long.class)) {
535 params[i] = nextParam.integerValue();
536 } else if (paramTypes[i].equals(double.class)
537 || paramTypes[i].equals(Double.class)) {
538 params[i] = nextParam.doubleValue();
539 } else if (paramTypes[i].equals(float.class)
540 || paramTypes[i].equals(Float.class)) {
541 params[i] = nextParam.doubleValue()
542 .floatValue();
543 } else if (paramTypes[i].equals(boolean.class)
544 || paramTypes[i].equals(Boolean.class)) {
545 params[i] = nextParam.booleanValue();
546 } else if (paramTypes[i].equals(String.class)) {
547 params[i] = nextParam.stringValue();
548 } else {
549 throw new UnexpectedException(
550 "Unexpected type "
551 + paramTypes[i].getClass()
552 .toString());
553 }
554 }
555 } catch (Exception e) {
556 continue;
557 }
558 /** Append extra params on the end of the last string param */
559 String s = params[lastParam].toString();
560 for (int i = paramCount; i < paramStrings.length; i++) {
561 s += ' ' + paramStrings[i];
562 }
563 params[lastParam] = s;
564
565 con = c;
566 break;
567 } else if (c.getParameterTypes().length == 0 && con == null) {
568 con = c;
569 params = null;
570 }
571 }
572
573 // if there is no constructor, return
574 if (con == null) {
575 throw new RuntimeException(INVALID_PARAMETERS_ERROR
576 + nameWithCorrectCase);
577 }
578
579 // create the JAG
580 Agent toLaunch = (Agent) con.newInstance(params);
581
582 LaunchAgent(toLaunch, source, clicked);
583
584 } catch (ClassNotFoundException cnf) {
585 _Agent = null;
586 throw new RuntimeException(nameWithCorrectCase
587 + "' is not an action or agent.");
588 }
589 }
590
591 /**
592 * Launches an agent from an already instantiated object.
593 *
594 * @param agent
595 * The agent to launch. Must not be null.
596 *
597 * @param source
598 * The calling frame that launched it. Must not be null.
599 *
600 * @param itemParam
601 * The item parameter for the agent.
602 *
603 * @throws NullPointerException
604 * if any of the arguments are null.
605 */
606 public static void LaunchAgent(Agent agent, Frame source, Item itemParam) {
607
608 if (agent == null)
609 throw new NullPointerException("agent");
610 if (source == null)
611 throw new NullPointerException("source");
612 // if (itemParam == null) throw new NullPointerException("itemParam");
613
614 String nameWithCorrectCase = agent.getClass().getSimpleName();
615
616 try {
617
618 // create the JAG
619 _Agent = agent;
620
621 Thread t = new Thread(_Agent);
622 t.setPriority(Thread.MIN_PRIORITY);
623
624 if (FreeItems.textOnlyAttachedToCursor()) {
625 itemParam = FreeItems.getItemAttachedToCursor();
626 }
627
628 // check for errors during initialisation
629 if (!_Agent.initialise(source, itemParam)) {
630 _Agent = null;
631 throw new RuntimeException("Error initialising agent: "
632 + nameWithCorrectCase);
633 }
634
635 // save the current frame (if necesssary)
636 // TODO make this nicer... ie. make Format an action rather than an
637 // agent and save frames only before running agents
638 if (!nameWithCorrectCase.equalsIgnoreCase("format")
639 && !nameWithCorrectCase.equalsIgnoreCase("sort")) {
640 FrameUtils.LeavingFrame(source);
641 }
642
643 if (_Agent.hasResultString()) {
644 // Just run the agent on this thread... dont run it in the
645 // background
646 t.run();
647 String result = _Agent.toString();
648 // Attach the result to the cursor
649 if (FreeItems.textOnlyAttachedToCursor()) {
650 Item resultItem = FreeItems.getItemAttachedToCursor();
651 resultItem.setText(result);
652 }
653 // if there is a completion frame, then display it to the user
654 } else {
655 t.start();
656 if (_Agent.hasResultFrame()) {
657 // TODO We want to be able to navigate through the frames as
658 // the results are loading
659 Frame next = _Agent.getResultFrame();
660 FrameUtils.DisplayFrame(next, true, true);
661 }
662 }
663 } catch (Exception e) {
664 _Agent = null;
665 e.printStackTrace();
666 throw new RuntimeException("Error creating Agent: '"
667 + nameWithCorrectCase + "'");
668 }
669 FrameGraphics.refresh(false);
670 }
671
672 /**
673 * Used to determine if the previously launched agent is still executing.
674 *
675 * @return True if the last Agent is still executing, False otherwise.
676 */
677 public static boolean isAgentRunning() {
678 if (_Agent != null)
679 return _Agent.isRunning();
680
681 return false;
682 }
683
684 /**
685 * Stops the currently running Agent (If there is one) by calling
686 * Agent.stop(). Note: This may not stop the Agent immediately, but the
687 * Agent should terminate as soon as it is safe to do so.
688 */
689 public static void stopAgent() {
690 if (_Agent != null && _Agent.isRunning()) {
691 MessageBay.errorMessage("Stopping Agent...");
692 _Agent.stop();
693 }
694 }
695
696 public static void interruptAgent() {
697 if (_Agent != null) {
698 _Agent.interrupt();
699 }
700 }
701
702 /**
703 * Converts the given String of values into an array of Objects
704 *
705 * @param launcher
706 * The Item used to launch the action, it may be required as a
707 * parameter
708 * @param values
709 * A list of space separated String values to convert to objects
710 * @return The created array of Objects
711 */
712 public static Object[] CreateObjects(Method method, Frame source,
713 Item launcher, String values) {
714 // The parameter types that should be created from the given String
715 Class[] paramTypes = method.getParameterTypes();
716
717 int paramCount = paramTypes.length;
718 // if the method has no parameters
719 if (paramCount == 0)
720 return new Object[0];
721
722 Object[] objects = new Object[paramCount];
723 int ind = 0;
724
725 /*
726 * if the first class in the list is a frame or item, it is the source
727 * or launcher length must be at least one if we are still running
728 */
729 if (paramTypes[ind] == Frame.class) {
730 objects[ind] = source;
731 ind++;
732 }
733
734 // Check if the second item is an item
735 if (paramCount > ind && Item.class.isAssignableFrom(paramTypes[ind])) {
736 objects[ind] = launcher;
737 ind++;
738 }// If there is stuff on the cursor use it for the rest of the params
739 else if (launcher != null && launcher.isFloating()) {
740 values = launcher.getText();
741 }
742
743 String param = values;
744 // convert the rest of the objects
745 for (; ind < objects.length; ind++) {
746 // check if its the last param and combine
747 if (values.length() > 0 && ind == objects.length - 1) {
748 param = values.trim();
749 // check if its a string
750 if (param.length() > 0 && param.charAt(0) == '"') {
751 int endOfString = param.indexOf('"', 1);
752 if (endOfString > 0) {
753 param = param.substring(1, endOfString);
754 }
755 }
756 } else {// strip off the next value
757 param = ParseValue(values);
758 values = RemainingParams(values);
759 }
760 // convert the value to an object
761 try {
762 Object o = Conversion.Convert(paramTypes[ind], param);
763 if (o == null)
764 return null;
765 objects[ind] = o;
766 } catch (Exception e) {
767 return null;
768 }
769 }
770
771 return objects;
772 }
773
774 /**
775 * Returns a string containing the remaining params after ignoring the first
776 * one.
777 *
778 * @param params
779 * a space sparated list of N parameters
780 * @return the remaining N - 1 parameters
781 */
782 public static String RemainingParams(String params) {
783 if (params.length() == 0)
784 return null;
785
786 // remove leading and trailing spaces
787 params = params.trim();
788
789 // if there are no more parameters, we are done
790 if (params.indexOf(" ") < 0) {
791 return "";
792 }
793
794 // Check if we have a string parameter
795 if (params.charAt(0) == '"') {
796 int endOfString = params.indexOf('"', 1);
797 if (endOfString > 0) {
798 if (endOfString > params.length())
799 return "";
800 return params.substring(endOfString + 1).trim();
801 }
802 }
803
804 return params.substring(params.indexOf(" ")).trim();
805 }
806
807 /**
808 * Returns the first value in the space separated String of parameters
809 * passed in. Strings are enclosed in double quotes.
810 *
811 * @param params
812 * The String of space separated values
813 * @return The first value in the String
814 */
815 public static String ParseValue(String params) {
816 if (params.length() == 0)
817 return null;
818
819 // remove leading and trailing spaces
820 String param = params.trim();
821
822 // Check if we have a string parameter
823 if (param.charAt(0) == '"') {
824 int endOfString = param.indexOf('"', 1);
825 if (endOfString > 0)
826 return param.substring(1, endOfString);
827 }
828
829 // if there are no more parameters, we are done
830 if (param.indexOf(" ") < 0) {
831 return param;
832 }
833
834 return param.substring(0, param.indexOf(" "));
835 }
836
837 /**
838 * Separates the name of the given command from any parameters and returns
839 * them
840 *
841 * @param command
842 * The String to separate out the Action or Agent name from
843 * @return The name of the Action of Agent with parameters stripped off
844 */
845 private static String getName(String command) {
846 if (command.indexOf(" ") < 0)
847 return command;
848
849 return command.substring(0, command.indexOf(" "));
850 }
851
852 /**
853 * Gets an uncapitalized font name and returns the capitalized font name.
854 * The capitalized form can be used with the Font.decoded method to get a
855 * corresponding Font object.
856 *
857 * @param fontName
858 * a font name in mixed case
859 * @return the correct capitalized form of the font name
860 */
861 public static String getCapitalizedFontName(String fontName) {
862 // Initialize the fonts if they have not already been loaded
863 initFonts();
864 return _Fonts.get(fontName.toLowerCase());
865 }
866
867 /**
868 * Initialise the fontsList if it has not been done already
869 */
870 private static void initFonts() {
871 if (_Fonts.size() == 0) {
872 String[] availableFonts = GraphicsEnvironment
873 .getLocalGraphicsEnvironment()
874 .getAvailableFontFamilyNames();
875 for (String s : availableFonts) {
876 _Fonts.put(s.toLowerCase(), s);
877 }
878 }
879 }
880
881 public static HashMap<String, String> getFonts() {
882 initFonts();
883 return _Fonts;
884 }
885
886 public static Object PerformActionCatchErrors(Frame current, Item launcher,
887 String command) {
888 try {
889 return PerformAction(current, launcher, command);
890 } catch (RuntimeException e) {
891 e.printStackTrace();
892 MessageBay.errorMessage("Action failed: " + e.getMessage());
893 } catch (Exception e) {
894 e.printStackTrace();
895 MessageBay.errorMessage("Action failed: "
896 + e.getClass().getSimpleName());
897 }
898 return null;
899 }
900
901 /**
902 * Gets the full class path for a widget with a given case insensitive name.
903 *
904 * @param widgetName
905 * @return
906 */
907 public static String getClassName(String widgetName) {
908 return _IWs.get(widgetName.toLowerCase());
909 }
910
911 static List<String> getActions() {
912 List<String> actionNames = new LinkedList<String>();
913 for (Method m : _Actions.values()) {
914 StringBuilder sb = new StringBuilder();
915 sb.append(m.getName());
916 for (Class c : m.getParameterTypes()) {
917 sb.append(" ").append(c.getSimpleName());
918 }
919 actionNames.add(sb.toString());
920 }
921
922 return actionNames;
923 }
924
925 static List<String> getAgents() {
926 List<String> agentNames = new LinkedList<String>();
927
928 for (String s : _JAGs.values()) {
929 agentNames.add(s.substring(s.lastIndexOf('.') + 1));
930 }
931
932 return agentNames;
933 }
934}
Note: See TracBrowser for help on using the repository browser.