Changeset 866
- Timestamp:
- 02/08/14 15:08:51 (10 years ago)
- Location:
- trunk/src/org/expeditee/items/widgets
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/expeditee/items/widgets/InteractiveWidget.java
r805 r866 13 13 import java.awt.event.KeyListener; 14 14 import java.awt.event.MouseEvent; 15 import java.io.PrintWriter; 16 import java.io.StringWriter; 15 17 import java.lang.reflect.Constructor; 16 18 import java.util.ArrayList; … … 20 22 import java.util.LinkedList; 21 23 import java.util.List; 24 import java.util.StringTokenizer; 22 25 23 26 import javax.swing.JComponent; 24 27 import javax.swing.SwingUtilities; 25 28 29 import org.apache.commons.cli.CommandLine; 30 import org.apache.commons.cli.CommandLineParser; 31 import org.apache.commons.cli.GnuParser; 32 import org.apache.commons.cli.HelpFormatter; 33 import org.apache.commons.cli.Option; 34 import org.apache.commons.cli.OptionBuilder; 35 import org.apache.commons.cli.Options; 36 import org.apache.commons.cli.ParseException; 26 37 import org.expeditee.actions.Actions; 27 38 import org.expeditee.gui.Browser; … … 72 83 protected Text _textRepresentation; 73 84 85 protected Float _anchorLeft; 86 protected Float _anchorRight; 87 protected Float _anchorTop; 88 protected Float _anchorBottom; 89 74 90 protected final static Color FREESPACE_BACKCOLOR = new Color(100, 100, 100); 75 91 … … 135 151 136 152 String text = source.getText(); 137 if (text == null) 153 if (text == null) { 138 154 throw new IllegalArgumentException("source does not have any text"); 155 } 139 156 140 157 text = text.trim(); 141 158 142 // Check starts with the widget tag and sep orator159 // Check starts with the widget tag and separator 143 160 if (!text.startsWith(TAG + ":")) 144 throw new IllegalArgumentException("Source text must begin with \"" 145 + TAG + ":\""); 146 161 throw new IllegalArgumentException("Source text must begin with \"" + TAG + ":\""); 162 163 // skip over the '@iw:' preamble 147 164 text = text.substring(TAG.length() + 1).trim(); 148 165 149 166 int index = 0; 150 167 if (text.length() > 0) { 151 index = text.indexOf(':'); // used for 152 // signifying start 153 // of arguments 154 } 155 156 if (index == 0) 157 throw new IllegalArgumentException("Source text must begin with \"" 158 + TAG + "\""); 159 160 String[] tokens = (index == -1) ? text.split("\\s+") : text.substring( 161 0, index).split(" "); 162 168 // Having removed @iw:, then next ':' is used for signifying start of arguments 169 index = text.indexOf(':'); 170 } 171 172 if (index == 0) { 173 throw new IllegalArgumentException("Source text must begin with \"" + TAG + "\""); 174 } 175 176 // 177 // Step 1: 178 // For an X-rayable text item in the form: 179 // @iw: <class name> [options] width height : <rest...> 180 // 181 // Parse the 'core' part of the X-rayable text item 182 // i.e, the text between the first ':' and the second ':' 183 // 184 // 185 186 String tokens_str = (index == -1) ? text : text.substring(0, index); 187 188 String[] tokens = parseArgsApache(tokens_str); 189 190 // make anything starting with a '-' lowercase 191 for (int i=0; i<tokens.length; i++) { 192 if (tokens[i].startsWith("-")) { 193 tokens[i] = tokens[i].toLowerCase(); 194 } 195 } 196 197 // create the command line parser 198 CommandLineParser parser = new GnuParser(); 199 200 // create the Options 201 Options options = new Options(); 202 options.addOption( "al", "anchorleft", true, "Anchor the vertical left-hand edge of the interactive widget to the value provided " ); 203 options.addOption( "ar", "anchorright", true, "Anchor the vertical right-hand edge of the interactive widget to the value provided " ); 204 options.addOption( "at", "anchortop", true, "Anchor the vertical top edge of the interactive widget to the value provided " ); 205 options.addOption( "ab", "anchorbottom", true, "Anchor the vertical bottom edge of the interactive widget to the value provided " ); 206 207 /* 208 * Alternative way to do the above, but with more control over how the values are set up and can be used 209 * 210 @SuppressWarnings("static-access") 211 Option anchor_left_opt = OptionBuilder.withLongOpt( "anchorleft" ) 212 .withDescription( "use <x-pos> as left anchor for the vertical lefthand edge of the interactive widget" ) 213 .hasArg() 214 .withArgName("<x-pos>") 215 .create("al"); 216 217 @SuppressWarnings("static-access") 218 Option anchor_right_opt = OptionBuilder.withLongOpt( "anchorright" ) 219 .withDescription( "use <x-pos> as right anchor for the vertical righthand edge of the interactive widget" ) 220 .hasArg() 221 .withArgName("<x-pos>") 222 .create("ar"); 223 224 225 @SuppressWarnings("static-access") 226 Option anchor_top_opt = OptionBuilder.withLongOpt( "anchortop" ) 227 .withDescription( "use <y-pos> as top anchor for the horizontal top end of the interactive widget" ) 228 .hasArg() 229 .withArgName("<x-pos>") 230 .create("at"); 231 232 @SuppressWarnings("static-access") 233 Option anchor_bottom_opt = OptionBuilder.withLongOpt( "anchorbottom" ) 234 .withDescription( "use <y-pos> as bottom anchor for the horizontal bottom edge of the interactive widget" ) 235 .hasArg() 236 .withArgName("<x-pos>") 237 .create("ab"); 238 239 options.addOption(anchor_left_opt); 240 options.addOption(anchor_right_opt); 241 options.addOption(anchor_top_opt); 242 options.addOption(anchor_bottom_opt); 243 */ 244 245 CommandLine core_line; 246 try { 247 // parse the command line arguments 248 core_line = parser.parse( options, tokens ); 249 250 // Update tokens to be version with the options removed 251 tokens = core_line.getArgs(); 252 253 } 254 catch( ParseException exp ) { 255 System.err.println( "Unexpected exception:" + exp.getMessage() ); 256 core_line = null; 257 258 } 259 260 HelpFormatter formatter = new HelpFormatter(); 261 StringWriter usage_str_writer = new StringWriter(); 262 PrintWriter printWriter = new PrintWriter(usage_str_writer); 263 264 String widget_name = tokens[0]; 265 final String widget_prefix = "org.expeditee.items.widgets"; 266 if (widget_name.startsWith(widget_prefix)) { 267 widget_name = widget_name.substring(widget_prefix.length()); 268 } 269 270 formatter.printHelp(printWriter, 80, TAG + ":" + widget_name + " [options] width height", null, options, 4, 0, null); 271 System.out.println(usage_str_writer.toString()); 272 163 273 float width = -1, height = -1; 164 274 165 if (tokens.length < 1) 166 throw new IllegalArgumentException( 167 "Missing widget class name in source text");275 if (tokens.length < 1) { 276 throw new IllegalArgumentException("Missing widget class name in source text"); 277 } 168 278 169 279 try { … … 200 310 + " does not exist or is not an InteractiveWidget"); 201 311 312 313 // 314 // Step 2: 315 // For an X-rayable text item in the form: 316 // @iw: <class name> [options] width height : <rest...> 317 // 318 // Parse the <rest ...> part 319 202 320 // Extract out the parameters - if any 203 321 String[] args = null; 204 322 if (index > 0) { // index of the first ":" 205 args = (text.length() == (index + 1)) ? null : parseArgs(text 206 .substring(index + 1)); 323 if (text.length()>(index+1)) { 324 String args_str = text.substring(index + 1); 325 326 args = parseArgsApache(args_str); 327 328 } 207 329 } 208 330 … … 222 344 } 223 345 224 // Use default dimensions if not provided (or provided as negitive 346 // Step 3: 347 // Set up the size and position of the widget 348 349 // Use default dimensions if not provided (or provided as negative 225 350 // values) 226 if (width <= 0) 351 if (width <= 0) { 227 352 width = inst.getWidth(); 228 if (height <= 0) 353 } 354 if (height <= 0) { 229 355 height = inst.getHeight(); 356 } 230 357 231 358 inst.setSize(width, height); 232 359 360 // Apply any anchor values supplied in the core part of the @iw item 361 Float anchor_left = null; 362 Float anchor_right = null; 363 Float anchor_top = null; 364 Float anchor_bottom = null; 365 366 if(core_line.hasOption( "anchorleft" ) ) { 367 String al_str = core_line.getOptionValue( "anchorleft" ); 368 369 anchor_left = Float.parseFloat(al_str); 370 } 371 372 if(core_line.hasOption( "anchorright" ) ) { 373 String ar_str = core_line.getOptionValue( "anchorright" ); 374 375 anchor_right = Float.parseFloat(ar_str); 376 } 377 378 if(core_line.hasOption( "anchortop" ) ) { 379 String at_str = core_line.getOptionValue( "anchortop" ); 380 381 anchor_top = Float.parseFloat(at_str); 382 } 383 384 if(core_line.hasOption( "anchorbottom" ) ) { 385 String ab_str = core_line.getOptionValue( "anchorbottom" ); 386 387 anchor_bottom = Float.parseFloat(ab_str); 388 } 389 390 inst.setAnchorCorners(anchor_left,anchor_right,anchor_top,anchor_bottom); 391 392 393 233 394 return inst; 234 395 } … … 319 480 320 481 } else if (c == '\"') { 321 // If double q outed482 // If double quoted 322 483 if (args.length() >= (i + 2) && args.charAt(i + 1) == '\"') { 323 484 … … 376 537 return sb.length() > 0 ? sb.toString() : null; 377 538 } 539 540 541 542 543 /** 544 * Similar to parseArgs() above. 545 * Code based on routine used in Apache Ant: 546 * org.apache.tools.ant.types.Commandline::translateCommandline() 547 * @param toProcess the command line to process. 548 * @return the command line broken into strings. 549 * An empty or null toProcess parameter results in a zero sized array. 550 */ 551 public static String[] parseArgsApache(String toProcess) { 552 if (toProcess == null || toProcess.length() == 0) { 553 //no command? no string 554 return new String[0]; 555 } 556 // parse with a simple finite state machine 557 558 final int normal = 0; 559 final int inQuote = 1; 560 final int inDoubleQuote = 2; 561 int state = normal; 562 final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true); 563 final ArrayList<String> result = new ArrayList<String>(); 564 final StringBuilder current = new StringBuilder(); 565 boolean lastTokenHasBeenQuoted = false; 566 567 while (tok.hasMoreTokens()) { 568 String nextTok = tok.nextToken(); 569 switch (state) { 570 case inQuote: 571 if ("\'".equals(nextTok)) { 572 lastTokenHasBeenQuoted = true; 573 state = normal; 574 } else { 575 current.append(nextTok); 576 } 577 break; 578 case inDoubleQuote: 579 if ("\"".equals(nextTok)) { 580 lastTokenHasBeenQuoted = true; 581 state = normal; 582 } else { 583 current.append(nextTok); 584 } 585 break; 586 default: 587 if ("\'".equals(nextTok)) { 588 state = inQuote; 589 } else if ("\"".equals(nextTok)) { 590 state = inDoubleQuote; 591 } else if (" ".equals(nextTok)) { 592 if (lastTokenHasBeenQuoted || current.length() != 0) { 593 result.add(current.toString()); 594 current.setLength(0); 595 } 596 } else { 597 current.append(nextTok); 598 } 599 lastTokenHasBeenQuoted = false; 600 break; 601 } 602 } 603 if (lastTokenHasBeenQuoted || current.length() != 0) { 604 result.add(current.toString()); 605 } 606 if (state == inQuote || state == inDoubleQuote) { 607 System.err.println("Error: Unbalanced quotes -- failed to parse '" + toProcess + "'"); 608 return null; 609 } 610 611 return result.toArray(new String[result.size()]); 612 } 613 614 615 378 616 379 617 /** … … 456 694 _textRepresentation = source; 457 695 458 setSizeRestrictions(minWidth, maxWidth, minHeight, maxHeight); // throws 459 // IllegalArgumentException's 696 setSizeRestrictions(minWidth, maxWidth, minHeight, maxHeight); // throws IllegalArgumentException's 460 697 461 698 int x = source.getX(); … … 608 845 /** 609 846 * @return The current representation for this widget. The representation 610 * stores link info mation, data etc... It is used for saving and847 * stores link information, data etc... It is used for saving and 611 848 * loading of the widget. Never null. 612 849 * … … 617 854 618 855 /** 619 * @return The expeditee anotation string.856 * @return The Expeditee annotation string. 620 857 */ 621 858 protected String getAnnotationString() { … … 628 865 sb.append(getClass().getName()); 629 866 630 // Append size information if needed (not an attibute of text items) 867 if (_anchorLeft != null) { 868 sb.append(" -anchorLeft " + Math.round(_anchorLeft)); 869 } 870 if (_anchorRight != null) { 871 sb.append(" -anchorRight " + Math.round(_anchorRight)); 872 } 873 874 if (_anchorTop != null) { 875 sb.append(" -anchorTop " + Math.round(_anchorTop)); 876 } 877 878 if (_anchorBottom != null) { 879 sb.append(" -anchorBottom " + Math.round(_anchorBottom)); 880 } 881 882 // Append size information if needed (not an attribute of text items) 631 883 if (!isFixedSize()) { 632 884 sb.append(' '); … … 647 899 648 900 /** 649 * Sets both the new size as well as the new min/max wid det/height650 * restric itons.901 * Sets both the new size as well as the new min/max widget/height 902 * restrictions. 651 903 * 652 904 * @param minWidth … … 700 952 public void setSize(float width, float height) { 701 953 702 // Clamp 703 if (width < _minWidth && _minWidth >= 0) 954 // If 'width' and 'height' exceed the min/max values for width/height 955 // => clamp to the relevant min/max value 956 if (width < _minWidth && _minWidth >= 0) { 704 957 width = _minWidth; 705 else if (width > _maxWidth && _maxWidth >= 0) 958 } 959 else if (width > _maxWidth && _maxWidth >= 0) { 706 960 width = _maxWidth; 707 708 if (height < _minHeight && _minHeight >= 0) 961 } 962 963 if (height < _minHeight && _minHeight >= 0) { 709 964 height = _minHeight; 710 else if (height > _maxHeight && _maxHeight >= 0) 965 } 966 else if (height > _maxHeight && _maxHeight >= 0) { 711 967 height = _maxHeight; 712 968 } 969 970 // Remember current isFloating() values 713 971 boolean vfloating[] = new boolean[] { _d1.isFloating(), 714 972 _d2.isFloating(), _d3.isFloating(), _d4.isFloating() }; … … 719 977 _d4.setFloating(true); 720 978 721 float x = _d1.getX() + width; 722 float y = _d1.getY() + height; 723 724 _d2.setX(x); 725 _d3.setX(x); 726 _d3.setY(y); 727 _d4.setY(y); 728 979 float xr = _d1.getX() + width; 980 float yb = _d1.getY() + height; 981 982 _d2.setX(xr); 983 _d3.setX(xr); 984 _d3.setY(yb); 985 _d4.setY(yb); 986 987 // Restore isFloating() values 729 988 _d1.setFloating(vfloating[0]); 730 989 _d2.setFloating(vfloating[1]); … … 735 994 } 736 995 996 public void setAnchorCorners(Float left, Float right, Float top, Float bottom) 997 { 998 setAnchorLeft(left); 999 setAnchorRight(right); 1000 setAnchorTop(top); 1001 setAnchorBottom(bottom); 1002 } 1003 1004 737 1005 public void setPosition(int x, int y) { 738 1006 if (x == getX() && y == getY()) 739 1007 return; 740 1008 1009 // Remember current isFloating() values 741 1010 boolean vfloating[] = new boolean[] { _d1.isFloating(), 742 1011 _d2.isFloating(), _d3.isFloating(), _d4.isFloating() }; … … 757 1026 _d4.setPosition(x, y + height); 758 1027 1028 // Restore isFloating() values 759 1029 _d1.setFloating(vfloating[0]); 760 1030 _d2.setFloating(vfloating[1]); … … 771 1041 772 1042 /** 773 * to be called from corners only 1043 * Updates position of given WidgetCorner to the given (x,y), 1044 * and updates related values (connected corners, width and height) 774 1045 * 775 1046 * @param src … … 1719 1990 } 1720 1991 1992 public void setAnchorLeft(Float anchor) { 1993 _anchorLeft = anchor; 1994 // Anchor left-edge corners (dots) as well 1995 _d1.setAnchorCornerX(anchor,null); 1996 _d4.setAnchorCornerX(anchor,null); 1997 1998 if (anchor != null) { 1999 setPositions(_d1, anchor, _d1.getY()); 2000 onResized(); 2001 } 2002 2003 // Move X-rayable items as well 2004 getSource().setAnchorLeft(anchor); 2005 } 2006 2007 public void setAnchorRight(Float anchor) { 2008 _anchorRight = anchor; 2009 // Anchor right-edge corners (dots) as well 2010 _d2.setAnchorCornerX(null,anchor); // right 2011 _d3.setAnchorCornerX(null,anchor); // right 2012 2013 if (anchor != null) { 2014 setPositions(_d2, FrameGraphics.getMaxFrameSize().width - anchor, _d2.getY()); 2015 onResized(); 2016 } 2017 2018 if (_anchorLeft == null) { 2019 // Prefer having the X-rayable item at anchorLeft position (if defined) over moving to anchorRight 2020 getSource().setAnchorRight(anchor); 2021 } 2022 } 2023 1721 2024 public void setAnchorTop(Float anchor) { 1722 setPosition(getX(),Math.round(anchor)); 2025 _anchorTop = anchor; 2026 // Anchor top-edge corners (dots) as well 2027 _d1.setAnchorCornerY(anchor,null); 2028 _d2.setAnchorCornerY(anchor,null); 2029 2030 if (anchor != null) { 2031 setPositions(_d2, _d2.getX(), anchor); 2032 onResized(); 2033 } 2034 2035 // Move X-rayable items as well 1723 2036 getSource().setAnchorTop(anchor); 1724 2037 } 1725 2038 1726 2039 public void setAnchorBottom(Float anchor) { 1727 setPosition(getX(),1728 Math.round(FrameGraphics.getMaxFrameSize().height - anchor - getHeight()));1729 getSource().setAnchorBottom(anchor);1730 }1731 1732 public void setAnchorLeft(Float anchor) {1733 setPosition(Math.round(anchor),1734 getY());1735 getSource().setAnchorLeft(anchor);1736 }1737 1738 public void setAnchorRight(Float anchor) {1739 setPosition(Math.round(FrameGraphics.getMaxFrameSize().width - anchor - getWidth()),1740 getY());1741 getSource().setAnchorRight(anchor);1742 } 2040 _anchorBottom = anchor; 2041 // Anchor bottom-edge corners (dots) as well 2042 _d3.setAnchorCornerY(null,anchor); 2043 _d4.setAnchorCornerY(null,anchor); 2044 2045 if (anchor != null) { 2046 setPositions(_d3, _d3.getX(), FrameGraphics.getMaxFrameSize().height - anchor); 2047 onResized(); 2048 } 2049 2050 if (_anchorTop == null) { 2051 // Prefer having the X-rayable item at anchorTop position (if defined) over moving to anchorBottom 2052 getSource().setAnchorBottom(anchor); 2053 } 2054 } 2055 1743 2056 1744 2057 public boolean isAnchored() { 1745 return getSource().isAnchored(); 2058 return (isAnchoredX()) || (isAnchoredY()); 2059 2060 //return getSource().isAnchored(); 1746 2061 } 1747 2062 1748 2063 public boolean isAnchoredX() { 1749 return getSource().isAnchoredX(); 2064 return (_anchorLeft != null) || (_anchorRight != null); 2065 //return getSource().isAnchoredX(); 1750 2066 } 1751 2067 1752 2068 public boolean isAnchoredY() { 1753 return getSource().isAnchoredY(); 2069 return (_anchorTop != null) || (_anchorBottom != null); 2070 //return getSource().isAnchoredY(); 1754 2071 } 1755 2072 -
trunk/src/org/expeditee/items/widgets/WidgetCorner.java
r805 r866 36 36 super.setPosition(x, y); 37 37 } 38 } else 38 } 39 else { 39 40 super.setPosition(x, y); 41 } 40 42 invalidateFill(); 41 43 } … … 48 50 super.setXY(x, y); 49 51 } 50 } else 52 } 53 else { 51 54 super.setXY(x, y); 55 } 52 56 invalidateFill(); 53 57 } … … 164 168 } 165 169 170 public void setAnchorCornerX(Float anchorLeft, Float anchorRight) { 171 _anchorLeft = anchorLeft; 172 _anchorRight = anchorRight; 173 } 174 175 public void setAnchorCornerY(Float anchorTop, Float anchorBottom) { 176 _anchorTop = anchorTop; 177 _anchorBottom= anchorBottom; 178 } 179 180 @Override 181 public void setAnchorLeft(Float anchor) { 182 _widgetSource.setAnchorLeft(anchor); 183 _anchorLeft = anchor; 184 _anchorRight = null; 185 } 186 187 @Override 188 public void setAnchorRight(Float anchor) { 189 _widgetSource.setAnchorRight(anchor); 190 _anchorLeft = null; 191 _anchorRight = anchor; 192 } 193 166 194 @Override 167 195 public void setAnchorTop(Float anchor) { 168 196 _widgetSource.setAnchorTop(anchor); 197 _anchorTop = anchor; 198 _anchorBottom = null; 169 199 } 170 200 … … 172 202 public void setAnchorBottom(Float anchor) { 173 203 _widgetSource.setAnchorBottom(anchor); 174 } 175 176 @Override 177 public void setAnchorLeft(Float anchor) { 178 _widgetSource.setAnchorLeft(anchor); 179 } 180 181 @Override 182 public void setAnchorRight(Float anchor) { 183 _widgetSource.setAnchorRight(anchor); 184 } 185 204 _anchorTop = null; 205 _anchorBottom = anchor; 206 } 207 208 /* 186 209 @Override 187 210 public Float getAnchorTop() { … … 203 226 return _widgetSource.getSource().getAnchorRight(); 204 227 } 205 228 */ 229 206 230 @Override 207 231 public void setLink(String link) {
Note:
See TracChangeset
for help on using the changeset viewer.