source: trunk/src/org/expeditee/gui/AttributeUtils.java@ 50

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

A whole day of big changes.
Adding the ability to have Text at the end of Lines.
Also a lot of refactoring to improve the quality of code relating to constraints and lines

File size: 21.0 KB
Line 
1package org.expeditee.gui;
2
3import java.awt.Color;
4import java.awt.Font;
5import java.lang.reflect.InvocationTargetException;
6import java.lang.reflect.Method;
7import java.util.HashMap;
8import java.util.LinkedList;
9import java.util.List;
10
11import org.expeditee.io.Conversion;
12import org.expeditee.items.Item;
13import org.expeditee.items.Text;
14
15/**
16 * This class provides the methods to extract and set attributes of Items and
17 * Frames. These methods are called when a user merges a text item with
18 * <code>Attribute: Value</code> pairs.
19 *
20 * @author jdm18
21 *
22 */
23public class AttributeUtils {
24
25 private static final char SEPARATOR_CHAR = ':';
26
27 private static final String SEPARATOR_STRING = SEPARATOR_CHAR + " ";
28
29 // List of method names to ignore when searching for a match
30 private static List<Method> _GetMethods = null;
31
32 private static HashMap<String, Method> _SetMethods = null;
33
34 // List of attributes which are ignored when copying.
35 private static List<String> _Ignore = null;
36
37 // List of method names to show in extraced lists even when they return
38 // null
39 // (Null is often used to indicate the default value is used)
40 private static List<Method> _AllowNull = null;
41
42 // private static HashMap<String, String> _Abbreviations = null;
43
44 /**
45 * Initialises the _Ignore and _AllowNull lists.
46 */
47 private static void initLists() {
48
49 Class[] param = {};
50
51 try {
52 _Ignore = new LinkedList<String>();
53 _Ignore.add("date");
54 _Ignore.add("datecreated");
55 _Ignore.add("d");
56 _Ignore.add("link");
57 _Ignore.add("l");
58
59 _AllowNull = new LinkedList<Method>();
60 _AllowNull.add(Item.class.getMethod("getColor", param));
61 _AllowNull.add(Item.class.getMethod("getBackgroundColor", param));
62
63 _AllowNull.add(Frame.class.getMethod("getBackgroundColor", param));
64 _AllowNull.add(Frame.class.getMethod("getForegroundColor", param));
65
66 _GetMethods = new LinkedList<Method>();
67 _GetMethods.add(Item.class.getMethod("getDateCreated", param));
68
69 _GetMethods.add(Item.class.getMethod("getColor", param));
70 _GetMethods.add(Item.class.getMethod("getBackgroundColor", param));
71 _GetMethods.add(Item.class.getMethod("getAction", param));
72 _GetMethods.add(Item.class.getMethod("getLink", param));
73 _GetMethods.add(Item.class.getMethod("getFillColor", param));
74 _GetMethods.add(Item.class.getMethod("getFillPattern", param));
75 _GetMethods.add(Item.class.getMethod("getThickness", param));
76
77 _GetMethods.add(Item.class.getMethod("getOwner", param));
78 _GetMethods.add(Item.class.getMethod("getLinkMark", param));
79 _GetMethods.add(Item.class.getMethod("getActionMark", param));
80
81 _GetMethods
82 .add(Item.class.getMethod("getActionCursorEnter", param));
83 _GetMethods
84 .add(Item.class.getMethod("getActionCursorLeave", param));
85 _GetMethods.add(Item.class.getMethod("getActionEnterFrame", param));
86 _GetMethods.add(Item.class.getMethod("getActionLeaveFrame", param));
87
88 _GetMethods.add(Item.class.getMethod("getTopShadowColor", param));
89 _GetMethods
90 .add(Item.class.getMethod("getBottomShadowColor", param));
91 _GetMethods.add(Item.class.getMethod("getArrow", param));
92
93 _GetMethods.add(Item.class.getMethod("getLinePattern", param));
94 _GetMethods.add(Item.class.getMethod("getLinkFrameset", param));
95 _GetMethods.add(Item.class.getMethod("getLinkTemplate", param));
96
97 _GetMethods.add(Text.class.getMethod("getFamily", param));
98 _GetMethods.add(Text.class.getMethod("getFontStyle", param));
99 _GetMethods.add(Text.class.getMethod("getJustification", param));
100 _GetMethods.add(Text.class.getMethod("getWidth", param));
101 _GetMethods.add(Item.class.getMethod("getSize", param));
102
103 _GetMethods.add(Frame.class.getMethod("getOwner", param));
104 _GetMethods.add(Frame.class.getMethod("getProtection", param));
105 _GetMethods.add(Frame.class.getMethod("getDateCreated", param));
106 _GetMethods.add(Frame.class.getMethod("getLastModifyUser", param));
107 _GetMethods.add(Frame.class.getMethod("getLastModifyDate", param));
108 _GetMethods.add(Frame.class.getMethod("getForegroundColor", param));
109 _GetMethods.add(Frame.class.getMethod("getBackgroundColor", param));
110
111 Class[] pString = { String.class };
112 Class[] pInt = { int.class };
113 Class[] pFloat = { float.class };
114 Class[] pColor = { Color.class };
115 Class[] pBool = { boolean.class };
116 Class[] pArrow = { int.class, double.class };
117 Class[] pList = { List.class };
118 Class[] pIntArray = { int[].class };
119
120 _SetMethods = new HashMap<String, Method>();
121
122 _SetMethods.put("thickness", Item.class.getMethod("setThickness",
123 pFloat));
124 _SetMethods.put("t", Item.class.getMethod("setThickness", pFloat));
125
126 _SetMethods.put("color", Item.class.getMethod("setColor", pColor));
127 _SetMethods.put("c", Item.class.getMethod("setColor", pColor));
128
129 _SetMethods.put("backgroundcolor", Item.class.getMethod(
130 "setBackgroundColor", pColor));
131 _SetMethods.put("bgc", Item.class.getMethod("setBackgroundColor",
132 pColor));
133
134 _SetMethods.put("action", Item.class.getMethod("setAction", pList));
135 _SetMethods.put("a", Item.class.getMethod("setAction", pList));
136
137 _SetMethods.put("link", Item.class.getMethod("setLink", pString));
138 _SetMethods.put("l", Item.class.getMethod("setLink", pString));
139
140 _SetMethods.put("fillcolor", Item.class.getMethod("setFillColor",
141 pColor));
142 _SetMethods.put("fc", Item.class.getMethod("setFillColor", pColor));
143
144 _SetMethods.put("fillpattern", Item.class.getMethod(
145 "setFillPattern", pString));
146
147 _SetMethods.put("owner", Item.class.getMethod("setOwner", pString));
148 _SetMethods.put("linkmark", Item.class.getMethod("setLinkMark",
149 pBool));
150 _SetMethods.put("actionmark", Item.class.getMethod("setActionMark",
151 pBool));
152
153 _SetMethods.put("actioncursorenter", Item.class.getMethod(
154 "setActionCursorEnter", pList));
155 _SetMethods.put("actioncursorleave", Item.class.getMethod(
156 "setActionCursorLeave", pList));
157 _SetMethods.put("actionenterframe", Item.class.getMethod(
158 "setActionEnterFrame", pList));
159 _SetMethods.put("actionleaveframe", Item.class.getMethod(
160 "setActionLeaveFrame", pList));
161
162 _SetMethods.put("topshadow", Item.class.getMethod(
163 "setTopShadowColor", pColor));
164 _SetMethods.put("bottomshadow", Item.class.getMethod(
165 "setBottomShadowColor", pColor));
166 _SetMethods.put("arrow", Item.class.getMethod("setArrow", pArrow));
167
168 _SetMethods.put("linepattern", Item.class.getMethod(
169 "setLinePattern", pIntArray));
170 _SetMethods.put("linkframeset", Item.class.getMethod(
171 "setLinkFrameset", pString));
172 _SetMethods.put("linktemplate", Item.class.getMethod(
173 "setLinkTemplate", pString));
174
175 _SetMethods.put("family", Text.class
176 .getMethod("setFamily", pString));
177 _SetMethods.put("face", Text.class.getMethod("setFontStyle",
178 pString));
179 _SetMethods.put("fontstyle", Text.class.getMethod("setFontStyle",
180 pString));
181 _SetMethods.put("justification", Text.class.getMethod(
182 "setJustification", pInt));
183 _SetMethods.put("width", Text.class.getMethod("setWidth", pInt));
184 _SetMethods.put("size", Item.class.getMethod("setSize", pInt));
185 _SetMethods.put("s", Item.class.getMethod("setSize", pInt));
186
187 _SetMethods.put("foregroundcolor", Frame.class.getMethod(
188 "setForegroundColor", pColor));
189 _SetMethods.put("fgc", Frame.class.getMethod("setForegroundColor",
190 pColor));
191 _SetMethods.put("backgroundcolor0", Frame.class.getMethod(
192 "setBackgroundColor", pColor));
193 _SetMethods.put("bgc0", Frame.class.getMethod("setBackgroundColor",
194 pColor));
195
196 /*
197 * _Abbreviations = new HashMap<String, String>();
198 * _Abbreviations.put("a", "Action"); _Abbreviations.put("l",
199 * "Link"); _Abbreviations.put("c", "Color");
200 * _Abbreviations.put("bgc", "BackgroundColor");
201 * _Abbreviations.put("fgc", "ForegroundColor");
202 * _Abbreviations.put("fc", "FillColor"); _Abbreviations.put("s",
203 * "Size");
204 */
205
206 } catch (SecurityException e) {
207 // TODO Auto-generated catch block
208 e.printStackTrace();
209 } catch (NoSuchMethodException e) {
210 // TODO Auto-generated catch block
211 e.printStackTrace();
212 }
213 }
214
215 /**
216 * Extracts a list of attributes from the given Object. Any method that
217 * starts with <code>get</code>, takes no arguments and is not found in
218 * the Ignore list will be run, All the attributes are then put into a Text
219 * Item of the form <Name>:<Value> If the value returned by the get method
220 * is null, then the attribute will not be included, unless the name of the
221 * method is found in the AllowNull list.
222 *
223 * @param toExtract
224 * The Object from which to extract the attributes
225 * @return A Text Item containing the extracted Attributes.
226 */
227 public static Text ExtractAttributes(Object toExtract) {
228 if (toExtract == null)
229 return null;
230
231 // ensure the lists are populated
232 if (_Ignore == null)
233 initLists();
234
235 // StringBuffer to store all the extracted Attribute:Value pairs
236 StringBuffer attributes = new StringBuffer();
237
238 // iterate through the list of methods
239 for (Method m : _GetMethods) {
240 // skip methods that are in the ignore list, do not start with
241 // 'get', or take parameters
242 if (m.getDeclaringClass() == toExtract.getClass()
243 || m.getDeclaringClass() == toExtract.getClass()
244 .getSuperclass()) {
245 try {
246 Object o = m.invoke(toExtract, (Object[]) null);
247 if (o != null) {
248 if (o instanceof Integer) {
249 if (m.getName().endsWith("Justification")
250 && convertJustificationToString((Integer) o) != null)
251 attributes
252 .append(m.getName().substring(3))
253 .append(SEPARATOR_STRING)
254 .append(
255 convertJustificationToString((Integer) o))
256 .append("\n");
257 // -1 indicates default value
258 else if (((Integer) o) > -1)
259 attributes.append(m.getName().substring(3))
260 .append(SEPARATOR_STRING).append(o)
261 .append("\n");
262 } else if (o instanceof Float) {
263 // -1 indicates default value
264 if (((Float) o) > 0.0001)
265 attributes.append(m.getName().substring(3))
266 .append(SEPARATOR_STRING).append(o)
267 .append("\n");
268 } else if (o instanceof Double) {
269 // -1 indicates default value
270 if (((Double) o) > 0.0001)
271 attributes.append(m.getName().substring(3))
272 .append(SEPARATOR_STRING).append(o)
273 .append("\n");
274 } else if (o instanceof Color) {
275 // converts the color to the KMS code
276 String s = Conversion.getKMSColorCode((Color) o);
277 if (s != null)
278 attributes.append(m.getName().substring(3))
279 .append(SEPARATOR_STRING).append(s)
280 .append("\n");
281 } else if (o instanceof Font) {
282 Font f = (Font) o;
283
284 String s = f.getName() + "-";
285 if (f.isPlain())
286 s += "Plain";
287
288 if (f.isBold())
289 s += "Bold";
290
291 if (f.isItalic())
292 s += "Italic";
293
294 s += "-" + f.getSize();
295
296 attributes.append(m.getName().substring(3)).append(
297 SEPARATOR_STRING).append(s).append("\n");
298 } else if (o instanceof Text) {
299 attributes.append(m.getName().substring(3)).append(
300 SEPARATOR_STRING).append(
301 ((Text) o).getFirstLine()).append("\n");
302 } else if (o instanceof List) {
303 List list = (List) o;
304 for (Object ob : list)
305 attributes.append(m.getName().substring(3))
306 .append(SEPARATOR_STRING).append(ob)
307 .append("\n");
308 } else if (o instanceof Boolean) {
309 // true is the default for boolean values
310 if (!((Boolean) o).booleanValue())
311 attributes.append(m.getName().substring(3))
312 .append(SEPARATOR_STRING).append(o)
313 .append("\n");
314 } else
315 attributes.append(m.getName().substring(3)).append(
316 SEPARATOR_STRING).append(o).append("\n");
317
318 /*
319 * } catch (SecurityException e) { e.printStackTrace(); }
320 * /*catch (NoSuchMethodException e) {
321 * e.printStackTrace(); }
322 */
323
324 // methods that return null are only included if they
325 // are in the AllowNull list
326 } else if (_AllowNull.contains(m))
327 attributes.append(m.getName().substring(3)).append(
328 SEPARATOR_CHAR + "\n");
329 } catch (IllegalArgumentException e) {
330 // TODO Auto-generated catch block
331 e.printStackTrace();
332 } catch (IllegalAccessException e) {
333 // TODO Auto-generated catch block
334 e.printStackTrace();
335 } catch (InvocationTargetException e) {
336 // TODO Auto-generated catch block
337 e.printStackTrace();
338 }
339 }
340 }
341
342 // if no attributes were extracted
343 if (attributes.length() <= 0)
344 return null;
345
346 while (attributes.charAt(attributes.length() - 1) == '\n')
347 attributes.delete(attributes.length() - 1, attributes.length());
348
349 // create the text Item
350 Text attribs = DisplayIO.getCurrentFrame().createNewText();
351 attribs.setText(attributes.toString());
352 attribs.setColor(null);
353 return attribs;
354 }
355
356 /**
357 * Returns the String name of the justification value given. just should
358 * correspond to one of the Item.JUSTIFICATION constants, if it does not
359 * then null is returned.
360 *
361 * @param just
362 * The justification level as defined by the Item.JUSTIFICATION
363 * constants.
364 * @return The String name (i.e. "Center") of the justification given, or
365 * null if no match is found.
366 */
367 private static String convertJustificationToString(int just) {
368 switch (just) {
369 case Item.JUSTIFICATION_CENTER:
370 return "Center";
371 case Item.JUSTIFICATION_FULL:
372 return "Full";
373 case Item.JUSTIFICATION_LEFT:
374 return "Left";
375 case Item.JUSTIFICATION_RIGHT:
376 return "Right";
377 default:
378 return null;
379 }
380 }
381
382 /**
383 * Attempts to set the attribute in the given attribute: value pair. The
384 * value string should be formatted as follows:
385 * <code> Attribute: Value </code> Multiple values can be used if they are
386 * separated by spaces
387 *
388 * @param toSet
389 * The Item to set the attribute of
390 * @param attribs
391 * The Text item that contains the list of attributes to set
392 * @return True if the attribute(s) were sucessfully set, false otherwise
393 */
394 public static boolean SetAttribute(Object toSet, Text attribs) {
395 // error checking
396 if (toSet == null || attribs == null)
397 return false;
398
399 if (_Ignore == null)
400 initLists();
401
402 // get the list of attribute: value pairs
403 List<String> values = attribs.getText();
404 // if no paris exist, we are done
405 if (values.size() == 0
406 || (values.size() == 1 && values.get(0).length() == 0))
407 return false;
408
409 // loop through all attribute: value pairs
410 for (int i = 0; i < values.size(); i++) {
411 StringBuffer v = new StringBuffer(values.get(i));
412
413 // remove the annotation mark (if applicable)
414 if (v.indexOf("@") == 0)
415 v = v.deleteCharAt(0);
416
417 // check if the next string is another attribute to merge or a
418 // continuation
419 while (i < values.size() - 1) {
420 StringBuffer next = new StringBuffer(values.get(i + 1));
421
422 // if the next String has a colon, then it may be another
423 // attribute
424 if (next.indexOf("" + SEPARATOR_CHAR) >= 0) {
425 // if the attribute is the same as v, then it is a
426 // continuation
427 if (v.indexOf(stripAttribute(next.toString())) == 0) {
428 // strip the attribute from next
429 next = new StringBuffer(stripValue(next.toString()));
430 // if the attribute is not the same, then it may be a
431 // new method
432 } else {
433 // if this is indeed a method, then leave the while loop
434 // if(_SetMethods.containsKey(StripFromColon(next.toString()).toLowerCase())){
435 break;
436 // }
437 }
438 }
439
440 v.append("\n").append(next);
441 i++;
442 }
443
444 if (v.length() > 0
445 && !SetAttribute(toSet, v.toString(), values.size() > 1)) {
446 // if no other attributes have been set
447 if (i == 0)
448 return false;
449 // otherwise, this is a list of attributes, so continue
450 else {
451 String stripped = stripAttribute(v.toString());
452 if (stripped == null) {
453 // This happens when there is an attribute at the start
454 // Then a bunch of plain text
455 return false;
456 } else if (_Ignore.contains(stripped)) {
457 return false;
458 } else if (!(_SetMethods.containsKey(stripped))) {
459 // Display an error message if its not in our list of
460 // attributes to ignore when copying
461 FrameGraphics.WarningMessage("Attribute: '"
462 + stripAttribute(v.toString())
463 + "' does not exist.");
464 } else {
465 String types = "";
466 for (Class c : _SetMethods.get(stripped)
467 .getParameterTypes())
468 types += c.getSimpleName() + " ";
469 FrameGraphics.WarningMessage("Wrong arguments for: '"
470 + stripAttribute(v.toString()) + "' expecting "
471 + types.trim() + " found '"
472 + stripValue(v.toString()) + "'");
473 }
474 }
475 } else if (v.length() == 0)
476 return false;
477 }
478
479 return true;
480 }
481
482 private static boolean SetAttribute(Object toSet, String value,
483 boolean isAttributeList) {
484 // separate attribute and value from string
485 String attribute = stripAttribute(value);
486 value = stripValue(value);
487
488 // if there was no colon
489 if (value == null || attribute == null)
490 return false;
491
492 if (value.length() == 0)
493 value = "";
494
495 attribute = attribute.toLowerCase();
496
497 // Some properties are ignored when multiple attributes are being set on
498 // an item at the same time
499 if (isAttributeList && _Ignore.contains(attribute)) {
500 // System.out.println("Attribute ignored: " + attribute);
501 return true;
502 }
503
504 // separate multiple values if required
505 Method toRun = _SetMethods.get(attribute);
506
507 // if this is not the name of a method, it may be the name of an agent
508 if (toRun == null) {
509 // System.out.println("Attrib not found for: " + attribute);
510 return false;
511 }
512
513 // if there are duplicate methods with the same name
514 List<Method> possibles = new LinkedList<Method>();
515 if (toRun.getDeclaringClass() == toSet.getClass()
516 || toRun.getDeclaringClass() == toSet.getClass()
517 .getSuperclass())
518 possibles.add(toRun);
519 int i = 0;
520 while (_SetMethods.containsKey(attribute + i)) {
521 if (_SetMethods.get(attribute + i).getDeclaringClass() == toSet
522 .getClass()
523 || _SetMethods.get(attribute + i).getDeclaringClass() == toSet
524 .getClass().getSuperclass())
525 possibles.add(_SetMethods.get(attribute + i));
526 i++;
527 }
528
529 for (Method possible : possibles) {
530 Object current = null;
531 Object[] param = {};
532
533 // find the corresponding get method for this set method
534 for (Method m : _GetMethods) {
535 if (m.getDeclaringClass() == toSet.getClass()
536 && m.getName()
537 .endsWith(possible.getName().substring(3))) {
538 try {
539 current = m.invoke(toSet, param);
540 } catch (IllegalArgumentException e) {
541 // TODO Auto-generated catch block
542 e.printStackTrace();
543 } catch (IllegalAccessException e) {
544 // TODO Auto-generated catch block
545 e.printStackTrace();
546 } catch (InvocationTargetException e) {
547 // TODO Auto-generated catch block
548 e.printStackTrace();
549 }
550 break;
551 }
552
553 }
554
555 try {
556 Object[] params = Conversion.Convert(possible, value, current);
557
558 try {
559 possible.invoke(toSet, params);
560 return true;
561 } catch (IllegalArgumentException e) {
562 // TODO Auto-generated catch block
563 e.printStackTrace();
564 } catch (IllegalAccessException e) {
565 // TODO Auto-generated catch block
566 e.printStackTrace();
567 } catch (InvocationTargetException e) {
568 FrameGraphics.DisplayMessage(toSet.getClass()
569 .getSimpleName()
570 + " type does not support that attribute.");
571 // e.printStackTrace();
572 }
573 } catch (NumberFormatException e) {
574
575 }
576 }
577
578 return false;
579
580 }
581
582 /**
583 * Returns the part of the given string that is after a colon, or null if
584 * the given String has no colon
585 *
586 * @param toStrip
587 * The String to strip
588 * @return The part of the String that is after a colon if there is one, or
589 * null if there is no colon
590 */
591 public static String stripValue(String toStrip) {
592 int ind = toStrip.lastIndexOf(SEPARATOR_CHAR);
593 if (ind < 0)
594 return null;
595
596 toStrip = toStrip.substring(ind + 1);
597 // This line must be separate from above
598 // It removes spaces from the string returned by the above statement
599 toStrip = toStrip.trim();
600
601 return toStrip;
602 }
603
604 /**
605 * Returns the part of the given string that is before a colon, or null if
606 * the given String has no colon
607 *
608 * @param toStrip
609 * The String to strip
610 * @return The part of the String that is before a colon if there is one, or
611 * null if there is no colon
612 */
613 public static String stripAttribute(String toStrip) {
614 int ind = toStrip.indexOf(SEPARATOR_CHAR);
615 if (ind < 0)
616 return null;
617
618 toStrip = toStrip.substring(0, ind);
619 toStrip = toStrip.trim();
620
621 if (toStrip.length() == 0)
622 return null;
623
624 return toStrip;
625 }
626
627 public static void setSingleValue(Text text, String value) {
628 assert (value != null);
629
630 String oldText = text.getTextNoList();
631 String attribute = stripAttribute(oldText);
632
633 if (attribute == null)
634 attribute = text.getTextNoList().trim();
635
636 text.setText(attribute + SEPARATOR_STRING + value);
637 }
638
639 public static Double getDoubleValue(String attributeValuePair) {
640 String value = stripValue(attributeValuePair);
641
642 if (value == null)
643 return null;
644
645 try {
646 return Double.parseDouble(value);
647 } catch (Exception e) {
648 }
649 return null;
650 }
651}
Note: See TracBrowser for help on using the repository browser.