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

Last change on this file since 408 was 408, checked in by ra33, 16 years ago

Made changes so that clicking back still counts as accessing a frame for statistics purposes...

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