Source Code Cross Referenced for BoundingBox.java in  » PDF » gnujpdf » gnu » jpdf » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » PDF » gnujpdf » gnu.jpdf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: BoundingBox.java,v 1.8 2002/02/05 19:25:35 ezb Exp $
003:         *
004:         * $Date: 2002/02/05 19:25:35 $
005:         *
006:         * Copyright (c) Eric Z. Beard, ericzbeard@hotmail.com 
007:         *
008:         * This library is free software; you can redistribute it and/or
009:         * modify it under the terms of the GNU Lesser General Public
010:         * License as published by the Free Software Foundation; either
011:         * version 2.1 of the License, or (at your option) any later version.
012:         *
013:         * This library is distributed in the hope that it will be useful,
014:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
015:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
016:         * Lesser General Public License for more details.
017:         *
018:         * You should have received a copy of the GNU Lesser General Public
019:         * License along with this library; if not, write to the Free Software
020:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
021:         * 
022:         */
023:        package gnu.jpdf;
024:
025:        import java.awt.*;
026:        import java.util.*;
027:
028:        /**
029:         * <p>This class simplifies the placement of Strings within 
030:         * a canvas area where the placement of objects is absolute</p>
031:         *
032:         * <p>A <code>BoundingBox</code> is just a Rectangle that knows how to 
033:         * find the coordinates for a String based on the desired alignment and 
034:         * <code>FontMetrics</code>.  For each new String, a new child 
035:         * <code>BoundingBox</code> is made that can be subtracted from the 
036:         * original box so new Strings can be added</p>
037:         *
038:         * <p>One of the more helpful features of this class is the string wrap 
039:         * feature of <code>getStringBounds</code>.  The box returned by that method 
040:         * will contain an array of strings that have been broken down to fit the 
041:         * box.  The box's coordinates and size will reflect the size of the 
042:         * entire group of strings if it is laid out as expected.  Using the 
043:         * returned box and iterating through the array of strings from top to 
044:         * bottom, getting new bounding boxes for each one (with upper left 
045:         * alignment and no padding) will result in the correct string wrap.</p>
046:         *
047:         * <p>Note that you will need to have Xvfb running on a Unix server to 
048:         * use this class</p>
049:         *
050:         * @author Eric Z. Beard, ericzbeard@hotmail.com
051:         * @author $Author: ezb $
052:         * @version $Revision: 1.8 $, $Date: 2002/02/05 19:25:35 $
053:         */
054:        public class BoundingBox extends Rectangle {
055:            /** Percent f line height to space lines */
056:            public static final int LINE_SPACING_PERCENTAGE = 20;
057:
058:            /** Used to a align a String centered vertically */
059:            public static final int VERT_ALIGN_CENTER = 0;
060:
061:            /** Used to align a String at the top of the box */
062:            public static final int VERT_ALIGN_TOP = 1;
063:
064:            /** Used to align a String at the bottom of the box */
065:            public static final int VERT_ALIGN_BOTTOM = 2;
066:
067:            /** Used to align a String horizontally in the center of the box */
068:            public static final int HORIZ_ALIGN_CENTER = 3;
069:
070:            /** Used to align a String to the left in the box */
071:            public static final int HORIZ_ALIGN_LEFT = 4;
072:
073:            /** Used to aling a String to the right in a box */
074:            public static final int HORIZ_ALIGN_RIGHT = 5;
075:
076:            /** Used to subtract a child from a box, *leaving* the top portion */
077:            public static final int SUBTRACT_FROM_TOP = 6;
078:
079:            /** Used to subtract a child from a box, *leaving* the bottom portion */
080:            public static final int SUBTRACT_FROM_BOTTOM = 7;
081:
082:            /** Used to subtract a child from a box, *leaving* the left portion */
083:            public static final int SUBTRACT_FROM_LEFT = 8;
084:
085:            /** Used to subtract a child from a box, *leaving" the right portion */
086:            public static final int SUBTRACT_FROM_RIGHT = 9;
087:
088:            private static final int[] VERT_ALIGNS = { VERT_ALIGN_CENTER,
089:                    VERT_ALIGN_TOP, VERT_ALIGN_BOTTOM };
090:
091:            private static final int[] HORIZ_ALIGNS = { HORIZ_ALIGN_CENTER,
092:                    HORIZ_ALIGN_LEFT, HORIZ_ALIGN_RIGHT };
093:
094:            private static final int[] SUBTRACTS = { SUBTRACT_FROM_TOP,
095:                    SUBTRACT_FROM_BOTTOM, SUBTRACT_FROM_LEFT,
096:                    SUBTRACT_FROM_RIGHT };
097:
098:            /** The point to use for Graphics.drawString() */
099:            private Point drawingPoint;
100:
101:            /** The absolute, world location of the box */
102:            private Point absoluteLocation;
103:
104:            /** Link to parent box */
105:            private BoundingBox parent;
106:
107:            /** 
108:             * If this box was the result of a getStringBounds call, this 
109:             * array will hold the broken strings
110:             */
111:            private String[] stringArray;
112:
113:            /** The string specified in getStringBounds */
114:            private String fullString;
115:
116:            /**
117:             * Creates a new <code>BoundingBox</code> instance.
118:             *
119:             * @param p a <code>Point</code>, upper left coords
120:             * @param d a <code>Dimension</code>, used to determine height and width
121:             */
122:            public BoundingBox(Point p, Dimension d) {
123:                super (p, d);
124:                this .drawingPoint = this .getLocation();
125:                this .absoluteLocation = this .getLocation();
126:            }
127:
128:            /**
129:             * <p>Returns true if this box has a parent.  The 'world', or 
130:             * enclosing canvas is not considered a parent</p>
131:             *
132:             * @return a <code>boolean</code> value
133:             */
134:            public boolean hasParent() {
135:                if (parent == null) {
136:                    return false;
137:                } else {
138:                    return true;
139:                }
140:            }
141:
142:            /**
143:             * <p>Get this box's parent box</p>
144:             *
145:             * @return a <code>BoundingBox</code> value
146:             */
147:            public BoundingBox getParent() {
148:                return parent;
149:            }
150:
151:            /**
152:             * <p>Make the specified box this box's child.  Equivalent to 
153:             * <code>child.setParent(parent)</code> where the specified 'parent' is 
154:             * this instance</p>
155:             *
156:             * @param child a <code>BoundingBox</code>, any box that can fit inside 
157:             *              this one.  The results of calling 
158:             *              <code>getAbsoluteLocation()</code> on the child will be 
159:             *              altered after this to take into account the child's 
160:             *              new location in the 'world'
161:             *
162:             */
163:            public void add(BoundingBox child) {
164:                child.setParent(this );
165:            }
166:
167:            /**
168:             * <p>Make the specified box this box's parent</p>
169:             *
170:             * @param parent a <code>BoundingBox</code> value
171:             */
172:            public void setParent(BoundingBox parent) {
173:                // Prevent infinite recursion
174:                if (this  == parent) {
175:                    return;
176:                }
177:                this .parent = parent;
178:
179:                // If this box was created empty, without a String inside,
180:                // determine its absolute location
181:                if (this .getLocation().equals(this .getAbsoluteLocation())) {
182:                    int ancestorTranslateX = 0;
183:                    int ancestorTranslateY = 0;
184:
185:                    BoundingBox ancestor = this ;
186:                    while (ancestor.hasParent()) {
187:                        BoundingBox oldRef = ancestor;
188:                        ancestor = ancestor.getParent();
189:                        // Prevent infinite recursion
190:                        if (ancestor == oldRef) {
191:                            break;
192:                        }
193:                        ancestorTranslateX += (int) ancestor.getLocation()
194:                                .getX();
195:                        ancestorTranslateY += (int) ancestor.getLocation()
196:                                .getY();
197:                    }
198:
199:                    this .getAbsoluteLocation().translate(ancestorTranslateX,
200:                            ancestorTranslateY);
201:                } // end if
202:            } // end setParent
203:
204:            /**
205:             * <p>Get the wrapped strings if this box was from a call to getStringBounds,
206:             * otherwise this method returns null</p>
207:             *
208:             * @return a <code>String[]</code> array of strings, top to bottom in layout
209:             */
210:            public String[] getStringArray() {
211:                return stringArray;
212:            } // end getStringArray
213:
214:            /**
215:             * <p>Set the value of the string array</p>
216:             *
217:             * @param strArray  a <code>String</code> array
218:             * 
219:             */
220:            public void setStringArray(String[] strArray) {
221:                this .stringArray = strArray;
222:            }
223:
224:            /**
225:             * <p>Set the absolute upper left world location point for this box</p>
226:             *
227:             * @param point a <code>Point</code> value
228:             */
229:            public void setAbsoluteLocation(Point point) {
230:                this .absoluteLocation = point;
231:            }
232:
233:            /** 
234:             * <p>Returns false if for any reason this box has negative dimensions</p>
235:             */
236:            public boolean boxExists() {
237:                if ((this .getHeight() < 0) || (this .getWidth() < 0)) {
238:                    return false;
239:                }
240:                return true;
241:            } // end boxExists
242:
243:            /**
244:             * <p>Get the absolute upper left location point for this box</p>
245:             *
246:             * @return a <code>Point</code> value
247:             */
248:            public Point getAbsoluteLocation() {
249:                return absoluteLocation;
250:            }
251:
252:            /**
253:             * <p>Returns the full string associated with a call to 
254:             *    <code>getStringBounds</code></p>
255:             */
256:            public String getFullString() {
257:                return fullString;
258:            }
259:
260:            /**
261:             * <p>Sets the full string associated with <code>getStringBounds</code></p>
262:             *
263:             * @param string a <code>String</code>
264:             */
265:            public void setFullString(String string) {
266:                this .fullString = string;
267:            }
268:
269:            /**
270:             * <p>Gets the location of a String after it is adjusted for 
271:             * alignment within this box.  The point's coordinates are 
272:             * either within this box or within the enclosing area.</p>
273:             *
274:             * @param string a <code>String</code>, the String to be placed
275:             * @param hAlign an <code>int</code>, HORIZ_ALIGN_CENTER, 
276:             *        HORIZ_ALIGN_LEFT, HORIX_ALIGN_RIGHT         
277:             * @param vAlign an <code>int</code>, VERT_ALIGN_CENTER, 
278:             *        VERT_ALIGN_TOP, VERT_ALIGN_BOTTOM
279:             * @param fm a <code>FontMetrics</code> object for this String
280:             * @param padding an <code>int</code>, the padding around the String
281:             * @param enforce a <code>boolean</code>, if true the method will throw 
282:             *        an exception when the string is too big, if not true it will break 
283:             *        the string down and overrun the bottom of the box.  If the box 
284:             *        is too small for even one word, the exception will be thrown
285:             * @return a <code>Point</code>, the coords to use in drawString()
286:             * @see #HORIZ_ALIGN_LEFT
287:             * @see #HORIZ_ALIGN_CENTER
288:             * @see #HORIZ_ALIGN_RIGHT
289:             * @see #VERT_ALIGN_TOP
290:             * @see #VERT_ALIGN_CENTER
291:             * @see #VERT_ALIGN_BOTTOM
292:             * @throws <code>IllegalArgumentException</code> if the args are invalid
293:             * @throws <code>StringTooLongException</code> if the string won't fit 
294:             *         and enforce is set to true.  The exception can still be thrown 
295:             *         if enforce is false, but only in cases such as the box having 
296:             *         no height or width
297:             */
298:            public BoundingBox getStringBounds(String string, int hAlign,
299:                    int vAlign, FontMetrics fm, int padding, boolean enforce)
300:                    throws IllegalArgumentException, StringTooLongException {
301:                // Check to make sure the values passed in are valid
302:                if (!checkHAlign(hAlign)) {
303:                    throw new IllegalArgumentException(
304:                            "BoundingBox.getStringBounds, "
305:                                    + "hAlign invalid : " + hAlign);
306:                }
307:                if (!checkVAlign(vAlign)) {
308:                    throw new IllegalArgumentException(
309:                            "BoundingBox.getStringBounds, "
310:                                    + "vAlign invalid : " + hAlign);
311:                }
312:                if (fm == null) {
313:                    throw new IllegalArgumentException(
314:                            "BoundingBox.getStringBounds, "
315:                                    + "FontMetrics null");
316:                }
317:                if (string == null) {
318:                    throw new IllegalArgumentException(
319:                            "BoundingBox.getStringBounds, " + "String null");
320:                }
321:
322:                // NOTE: For this portion of the method, parent refers 
323:                // to this object and child refers to the object about 
324:                // to be created.  When the absolute point for drawing the 
325:                // String is determined, this object's ancestors are checked.
326:                Point parentLocation = this .getLocation();
327:                Dimension parentSize = this .getSize();
328:
329:                Point childLocation;
330:                Dimension childSize;
331:
332:                // String ascent, width, height, parent, child width, height
333:                int sa, sw, sh, pw, ph, cw, ch;
334:
335:                // Child, parent x, y coords for upper left
336:                int cx, cy, px, py;
337:
338:                sa = fm.getMaxAscent();
339:                sw = fm.stringWidth(string);
340:                sh = sa + fm.getMaxDescent();
341:                pw = (int) parentSize.getWidth();
342:                ph = (int) parentSize.getHeight();
343:                if (pw < 0) {
344:                    throw new StringTooLongException(
345:                            "The parent box has a negative width " + " (" + pw
346:                                    + ")");
347:                }
348:                if (ph < 0) {
349:                    throw new StringTooLongException(
350:                            "The parent box has a negative height" + " (" + ph
351:                                    + ")");
352:                }
353:                cw = sw + padding * 2;
354:                ch = sh + padding * 2;
355:                px = (int) this .getX();
356:                py = (int) this .getY();
357:
358:                String[] childStrArray = null;
359:
360:                if ((cw > pw) || (string.indexOf("\n") != -1)) {
361:                    cw = pw - (padding * 2);
362:                    childStrArray = createStringArray(string, fm, padding, pw);
363:                    ch = getWrappedHeight(childStrArray, fm, padding);
364:                    if (ch > ph) {
365:                        // If enforce is not true, it means we want the box to 
366:                        // be returned anyway (along with the strings in the array)
367:                        // so we can chop them manually and try again
368:                        if (enforce) {
369:                            throw new StringTooLongException(
370:                                    "The wrapped strings do not "
371:                                            + "fit into the parent box, pw="
372:                                            + pw + ", ph=" + ph + ", ch=" + ch
373:                                            + ", cw=" + cw + ", string: "
374:                                            + string);
375:                        }
376:                    }
377:                }
378:
379:                // Need to have child width and height, and string array set
380:
381:                // Child location is relative to this (parent) box, not the world
382:                if (vAlign == VERT_ALIGN_TOP) {
383:                    cy = 0;
384:                } else if (vAlign == VERT_ALIGN_CENTER) {
385:                    cy = (ph / 2) - (ch / 2);
386:                } else {
387:                    cy = ph - ch;
388:                }
389:
390:                if (hAlign == HORIZ_ALIGN_LEFT) {
391:                    cx = 0;
392:                } else if (hAlign == HORIZ_ALIGN_CENTER) {
393:                    cx = (pw / 2) - (cw / 2);
394:                } else {
395:                    cx = pw - cw;
396:                }
397:
398:                childLocation = new Point(cx, cy);
399:                childSize = new Dimension(cw, ch);
400:
401:                // Drawing location is based on the baseline of the String, and 
402:                // relative to the world, not this box.  The drawing point differs 
403:                // from the absolute box location because of padding and ascent
404:                int dpx, dpy, abx, aby;
405:
406:                // If this object also has a parent (maybe grandparents), iterate 
407:                // through them and find the absolute 'world' location
408:                int ancestorTranslateX = 0;
409:                int ancestorTranslateY = 0;
410:
411:                BoundingBox ancestor = this ;
412:                while (ancestor.hasParent()) {
413:                    BoundingBox oldRef = ancestor;
414:                    ancestor = ancestor.getParent();
415:                    // Prevent infinite recursion
416:                    if (ancestor == oldRef) {
417:                        break;
418:                    }
419:                    ancestorTranslateX += (int) ancestor.getLocation().getX();
420:                    ancestorTranslateY += (int) ancestor.getLocation().getY();
421:                }
422:
423:                // Determine the absolute location for the box
424:                abx = px + cx + ancestorTranslateX;
425:                aby = py + cy + ancestorTranslateY;
426:
427:                // Determine the absolute drawing point for the String
428:                dpx = abx + padding;
429:                dpy = aby + padding + sa;
430:
431:                Point drawingPoint = new Point(dpx, dpy);
432:                BoundingBox returnChild = new BoundingBox(childLocation,
433:                        childSize, drawingPoint, new Point(abx, aby));
434:                this .add(returnChild);
435:                returnChild.setFullString(string);
436:                returnChild.setStringArray(childStrArray);
437:                return returnChild;
438:
439:            } // end getStringBounds
440:
441:            /**
442:             * <p>Gets the location of a String after it is adjusted for 
443:             * alignment within this box.  The point's coordinates are 
444:             * either within this box or within the enclosing area.</p>
445:             *
446:             * <p>By default, this method enforces string length and throws the 
447:             * exception if it is too long</p>
448:             *
449:             * @param string a <code>String</code>, the String to be placed
450:             * @param hAlign an <code>int</code>, HORIZ_ALIGN_CENTER, 
451:             *        HORIZ_ALIGN_LEFT, HORIX_ALIGN_RIGHT         
452:             * @param vAlign an <code>int</code>, VERT_ALIGN_CENTER, 
453:             *        VERT_ALIGN_TOP, VERT_ALIGN_BOTTOM
454:             * @param fm a <code>FontMetrics</code> object for this String
455:             * @param padding an <code>int</code>, the padding around the String
456:             * @return a <code>Point</code>, the coords to use in drawString()
457:             * @throws <code>IllegalArgumentException</code> if the args are invalid
458:             * @throws <code>StringTooLongException</code> if the string won't fit
459:             */
460:            public BoundingBox getStringBounds(String string, int hAlign,
461:                    int vAlign, FontMetrics fm, int padding)
462:                    throws StringTooLongException, IllegalArgumentException {
463:                return getStringBounds(string, hAlign, vAlign, fm, padding,
464:                        true);
465:            } // end getStringBounds (enforce true by default)
466:
467:            /**
468:             * <p>This method is called after getting the box by calling 
469:             * <code>getStringBounds</code> on the parent.  Wraps the string at 
470:             * word boundaries and draws it to the specified <code>Graphics</code>
471:             * context.  Make sure padding is the same as specified for the 
472:             * <code>getStringBounds</code> call, or you may get an unexpected 
473:             * {@link gnu.jpdf.StringTooLongException}</p>
474:             *
475:             * @param g the <code>Graphics</code> object
476:             * @param fm the <code>FontMetrics</code> to use for sizing
477:             * @param padding an int, the padding around the strings
478:             * @param hAlign the <code>int</code> horizontal alignment
479:             * @throws <code>IllegalArgumentException</code> if the args are invalid
480:             * @throws <code>StringTooLongException</code> if the string 
481:             *         won't fit this will only happen if the fm or padding has 
482:             *         been changed since getStringBounds was called succesfully
483:             */
484:            public void drawWrappedString(Graphics g, FontMetrics fm,
485:                    int padding, int hAlign) throws IllegalArgumentException,
486:                    StringTooLongException {
487:                if (getStringArray() == null) {
488:                    Point p = getDrawingPoint();
489:                    int xx = (int) p.getX();
490:                    int yy = (int) p.getY();
491:                    g.drawString(getFullString(), xx, yy);
492:                } else {
493:                    int len = stringArray.length;
494:                    for (int i = 0; i < len; i++) {
495:                        BoundingBox wrappedBox = null;
496:                        wrappedBox = getStringBounds(stringArray[i], hAlign,
497:                                BoundingBox.VERT_ALIGN_TOP, fm, 0);
498:                        Point pp = wrappedBox.getDrawingPoint();
499:                        int xx = (int) pp.getX();
500:                        if (hAlign == BoundingBox.HORIZ_ALIGN_RIGHT) {
501:                            xx -= padding;
502:                        }
503:                        if (hAlign == BoundingBox.HORIZ_ALIGN_LEFT) {
504:                            xx += padding;
505:                        }
506:                        int yy = (int) pp.getY() + padding;
507:                        g.drawString(stringArray[i], xx, yy);
508:                        subtract(wrappedBox, BoundingBox.SUBTRACT_FROM_BOTTOM);
509:                    }
510:                }
511:            } // end drawWrappedString
512:
513:            /**
514:             * <p>Draws lines from the wrapped string until there is no more room and
515:             * then stops.  If there is no string or the box is too small for 
516:             * anything to be drawn, does nothing</p>
517:             *
518:             * @param g the <code>Graphics</code> object to draw to
519:             * @param fm the <code>FontMetrics</code> object to use for string sizing
520:             * @param padding the <code>int</code> amount of padding around the string
521:             * @param hAlign the <code>int</code> horizontal alignment
522:             * 
523:             */
524:            public void drawWrappedStringTruncate(Graphics g, FontMetrics fm,
525:                    int padding, int hAlign) {
526:
527:                if (getStringArray() == null) {
528:                    Point p = getDrawingPoint();
529:                    int xx = (int) p.getX();
530:                    int yy = (int) p.getY();
531:                    if (getFullString() != null) {
532:                        g.drawString(getFullString(), xx, yy);
533:                    } else {
534:                        System.err
535:                                .println("getStringArray and getFullString are null");
536:                    }
537:                } else {
538:                    int totalHeight = 0;
539:                    int len = stringArray.length;
540:                    for (int i = 0; i < len; i++) {
541:                        BoundingBox wrappedBox = null;
542:                        try {
543:                            wrappedBox = getStringBounds(stringArray[i],
544:                                    hAlign, BoundingBox.VERT_ALIGN_TOP, fm, 0,
545:                                    false);
546:                            totalHeight += (int) wrappedBox.getHeight();
547:                            if (getParent() != null) {
548:                                if (totalHeight > (int) (getParent()
549:                                        .getHeight())) {
550:                                    return;
551:                                }
552:                            }
553:                        } catch (StringTooLongException stle) {
554:                            stle.printStackTrace();
555:                            return;
556:                        }
557:                        wrappedBox.drawChoppedString(g, fm, padding, hAlign);
558:                        subtract(wrappedBox, BoundingBox.SUBTRACT_FROM_BOTTOM);
559:                    }
560:                }
561:            } // end drawWrappedStringTruncate
562:
563:            /**
564:             * <p>Take the first line of the string (if it is wrapped, otherwise just 
565:             * take the whole string) and chop the end of it off to make it fit in the 
566:             * box.  If the box is smaller than one letter, draw nothing</p>
567:             *
568:             * @param g the <code>Graphics</code> object to draw to
569:             * @param fm the <code>FontMetrics</code> object to use for string sizing
570:             * @param padding the <code>int</code> amount of padding around the string
571:             * @param hAlign the <code>int</code> horizontal alignment
572:             */
573:            public void drawChoppedString(Graphics g, FontMetrics fm,
574:                    int padding, int hAlign) {
575:
576:                String string = "";
577:                if (getStringArray() != null) {
578:                    string = new String(getStringArray()[0]);
579:                } else {
580:                    string = new String(getFullString());
581:                }
582:                BoundingBox choppedBox = null;
583:                try {
584:                    choppedBox = getStringBounds(string, hAlign,
585:                            VERT_ALIGN_TOP, fm, padding);
586:                    Point p = choppedBox.getDrawingPoint();
587:                    int x = (int) p.getX();
588:                    int y = (int) p.getY();
589:                    g.drawString(string, x, y);
590:                } catch (StringTooLongException stle) {
591:                    // Doesn't fit - start cutting from the end until it does
592:                    StringBuffer buf = new StringBuffer().append(string);
593:                    if (buf.length() == 0) {
594:                        System.out
595:                                .println("BoundingBox.drawChoppedString, buf len 0 ??");
596:                        //return;
597:                        throw new RuntimeException();
598:                    }
599:                    buf.deleteCharAt(buf.length() - 1);
600:                    while ((fm.stringWidth(buf.toString()) > (int) getWidth())
601:                            && (buf.length() > 0)) {
602:                        buf.deleteCharAt(buf.length() - 1);
603:                    }
604:
605:                    try {
606:                        choppedBox = getStringBounds(buf.toString(), hAlign,
607:                                VERT_ALIGN_TOP, fm, padding);
608:                        Point pp = choppedBox.getDrawingPoint();
609:                        int xx = (int) pp.getX();
610:                        int yy = (int) pp.getY();
611:                        g.drawString(string, xx, yy);
612:                    } catch (StringTooLongException sstle) {
613:                        // Must be a really small box!
614:                        sstle.printStackTrace();
615:                    }
616:                }
617:            } // end drawChoppedString
618:
619:            /**
620:             * <p>Get the total height of the box needed to contain the strings in 
621:             * the specified array</p>
622:             */
623:            private int getWrappedHeight(String[] strings, FontMetrics fm,
624:                    int padding) {
625:                int ma = fm.getMaxAscent();
626:                int md = fm.getMaxDescent();
627:                int sh = ma + md;
628:                int hPad = sh / LINE_SPACING_PERCENTAGE;
629:                sh += hPad;
630:                int total = sh * strings.length;
631:
632:                return total + (padding * 2);
633:            } // end getWrappedHeight
634:
635:            /**
636:             *
637:             * <p>Make a string array from a string, wrapped to fit the box</p> 
638:             *
639:             * <p>If the line width is too short, the array is just a 
640:             * tokenized version of the string</p>
641:             *
642:             * @param string - the <code>String</code> to convert to an array
643:             * @param
644:             */
645:            private String[] createStringArray(String string, FontMetrics fm,
646:                    int padding, int pw) {
647:                if (string == null) {
648:                    System.err
649:                            .println("Tried createStringArray with null String");
650:                    return null;
651:                }
652:                if (fm == null) {
653:                    System.err
654:                            .println("Tried createStringArray with null FontMetrics");
655:                }
656:
657:                int sw = fm.stringWidth(string);
658:                int lw = pw - (padding * 2);
659:
660:                Vector returnVector = new Vector();
661:                // Return delimiters as tokens
662:                StringTokenizer st = new StringTokenizer(string, " \t\n\r\f",
663:                        true);
664:                StringBuffer tempBuffer = new StringBuffer();
665:                StringBuffer finalBuffer = new StringBuffer();
666:
667:                while (st.hasMoreTokens()) {
668:                    // Get the next word and add a space after it 
669:                    String tempString = st.nextToken();
670:                    tempBuffer.append(tempString);
671:
672:                    // If we haven't reached the width with our current 
673:                    // line, keep adding tokens.  Also, check for hard returns
674:                    if ((fm.stringWidth(tempBuffer.toString()) < lw)
675:                            && (tempBuffer.toString().charAt(
676:                                    tempBuffer.toString().length() - 1) != '\n')
677:                            && (tempBuffer.toString().charAt(
678:                                    tempBuffer.toString().length() - 1) != '\r')) {
679:                        finalBuffer.append(tempString);
680:                        continue;
681:                    } else {
682:                        returnVector.addElement(finalBuffer.toString());
683:                        finalBuffer.delete(0, finalBuffer.length());
684:                        tempBuffer.delete(0, tempBuffer.length());
685:                        if ((tempString.charAt(0) != '\n')
686:                                && (tempString.charAt(0) != '\r')) {
687:                            tempBuffer.append(tempString);
688:                            finalBuffer.append(tempString);
689:                        }
690:                        continue;
691:                    }
692:
693:                } // end while
694:                returnVector.addElement(finalBuffer.toString());
695:
696:                int len = returnVector.size();
697:                // Init the class member field stringArray
698:                String[] childStrArray = new String[len];
699:                for (int i = 0; i < len; i++) {
700:                    String curStr = (String) returnVector.get(i);
701:                    childStrArray[i] = curStr;
702:                }
703:
704:                return childStrArray;
705:
706:            } // end createStringArray 
707:
708:            /**
709:             * <p>Removes the child box from this parent box.  The child must 
710:             * have this object as its parent or the method does nothing.  
711:             * The BoundingBox returned will be cut by an area equal to 
712:             * the child area plus the horizontal or vertical strip in 
713:             * which it sits, depending on the 'subtractFrom' value passed
714:             * in</p>
715:             *
716:             * @param child a <code>BoundingBox</code> value
717:             * @param int an <code>int</code>, SUBTRACT_FROM_LEFT, 
718:                      SUBTRACT_FROM_RIGHT, SUBTRACT_FROM_TOP,
719:                      SUBTRACT_FROM_BOTTOM
720:             * @return a <code>BoundingBox</code> value
721:             * @see #SUBTRACT_FROM_LEFT
722:             * @see #SUBTRACT_FROM_RIGHT
723:             * @see #SUBTRACT_FROM_TOP
724:             * @see #SUBTRACT_FROM_BOTTOM
725:             */
726:            public BoundingBox subtract(BoundingBox child, int subtractFrom) {
727:                // First, check to see if the params are valid
728:                if (child == null) {
729:                    throw new IllegalArgumentException("BoundingBox.subtract, "
730:                            + "BoundingBox child is null");
731:                }
732:                if (!child.hasParent()) {
733:                    throw new IllegalArgumentException("BoundingBox.subtract, "
734:                            + "BoundingBox child has no parent");
735:                } else {
736:                    if (!(child.getParent() == this )) {
737:                        throw new IllegalArgumentException(
738:                                "BoundingBox.subtract, "
739:                                        + "this is not BoundingBox child's parent");
740:                    } else {
741:                        // Now that we know the child is this object's child, we continue
742:                        // and check the subtractFrom param
743:                        int len = SUBTRACTS.length;
744:                        boolean valid = false;
745:                        for (int i = 0; i < len; i++) {
746:                            if (subtractFrom == SUBTRACTS[i]) {
747:                                valid = true;
748:                            }
749:                        }
750:                        if (!valid) {
751:                            throw new IllegalArgumentException(
752:                                    "BoundingBox.subtract, "
753:                                            + "subtractFrom invalid: "
754:                                            + subtractFrom);
755:                        }
756:
757:                        // Now we know the child is valid, and if the subtractFrom 
758:                        // preference was invalid, we subtract from the bottom
759:
760:                        // The child should no longer be used, since the parent 
761:                        // reference will be invalid
762:                        child.setParent(null);
763:
764:                        int cx = (int) child.getLocation().getX();
765:                        int cy = (int) child.getLocation().getY();
766:                        int cw = (int) child.getSize().getWidth();
767:                        int ch = (int) child.getSize().getHeight();
768:                        int px = (int) this .getLocation().getX();
769:                        int py = (int) this .getLocation().getY();
770:                        int pw = (int) this .getSize().getWidth();
771:                        int ph = (int) this .getSize().getHeight();
772:
773:                        switch (subtractFrom) {
774:                        case SUBTRACT_FROM_LEFT:
775:                            // This will be useful for right-justified Strings in tables
776:                            pw = cx;
777:                            this .setSize(new Dimension(pw, ph));
778:                            return this ;
779:
780:                        case SUBTRACT_FROM_RIGHT:
781:                            // This will be useful for left justified Strings in tables
782:                            px = px + cw + cx;
783:                            pw = pw - cw - cx;
784:                            this .setLocation(new Point(px, py));
785:                            this .setSize(new Dimension(pw, ph));
786:                            return this ;
787:
788:                        case SUBTRACT_FROM_BOTTOM:
789:                            py = py + ch + cy;
790:                            ph = ph - ch - cy;
791:                            this .setLocation(new Point(px, py));
792:                            this .setSize(new Dimension(pw, ph));
793:                            return this ;
794:
795:                        case SUBTRACT_FROM_TOP:
796:                            ph = cy;
797:                            this .setSize(new Dimension(pw, ph));
798:                            return this ;
799:
800:                        default: // Should never happen
801:                            break;
802:                        } // end switch
803:                    }
804:                }
805:                return this ;
806:            } // end subtract
807:
808:            /**
809:             * <p>Gets the drawing point to use in Graphics drawing 
810:             * methods.  After getting a new BoundingBox with getStringBounds(),
811:             * calling this method will give you an absolute point, accounting 
812:             * for alignment and padding, etc, from which to start drawing the 
813:             * String</p>
814:             *
815:             * <p>If getStringBounds was not called (this is a parent box), the 
816:             * upper left coordinates will be returned (this.getLocation())</p>
817:             *
818:             * @return a <code>Point</code>
819:             */
820:            public Point getDrawingPoint() {
821:                return drawingPoint;
822:            }
823:
824:            // main method is for testing /////////////////
825:
826:            /**
827:             * For testing
828:             *
829:             * @param args a <code>String[]</code> value
830:             */
831:            public static void main(String[] args) {
832:                Point upperLeft = new Point(5, 5);
833:                Dimension bounds = new Dimension(100, 100);
834:                BoundingBox parent = new BoundingBox(upperLeft, bounds);
835:                String string = "Hello World!";
836:                Font font = new Font("SansSerif", Font.PLAIN, 12);
837:                Frame frame = new Frame();
838:                frame.addNotify();
839:                try {
840:                    Image image = frame.createImage(100, 100);
841:                    if (image == null) {
842:                        System.err.println("image is null");
843:                    }
844:                    Graphics graphics = image.getGraphics();
845:                    FontMetrics fm = graphics.getFontMetrics(font);
846:                    BoundingBox child = parent.getStringBounds(string,
847:                            BoundingBox.HORIZ_ALIGN_LEFT,
848:                            BoundingBox.VERT_ALIGN_TOP, fm, 5);
849:                    System.out.println("Drawing Point: "
850:                            + child.getDrawingPoint().toString());
851:                    System.out.println("Now testing subtract() method...");
852:
853:                    parent = new BoundingBox(new Point(10, 10), new Dimension(
854:                            300, 300));
855:                    System.out.println("parent: " + parent.toString());
856:                    child = new BoundingBox(new Point(90, 110), new Dimension(
857:                            100, 100));
858:                    parent.add(child);
859:                    System.out.println("child: " + child.toString());
860:                    System.out.println();
861:                    System.out.println("subtracting the child from the parent");
862:                    System.out.println("SUBTRACT_FROM_TOP: ");
863:                    parent = parent.subtract(child, SUBTRACT_FROM_TOP);
864:                    System.out.println("new parent: " + parent.toString());
865:                    System.out.println();
866:                    System.out.println("Resetting parent");
867:                    parent = new BoundingBox(new Point(10, 10), new Dimension(
868:                            300, 300));
869:                    parent.add(child);
870:                    System.out.println("SUBTRACT_FROM_BOTTOM");
871:                    parent.subtract(child, SUBTRACT_FROM_BOTTOM);
872:                    System.out.println("new parent: " + parent.toString());
873:                    System.out.println();
874:                    System.out.println("Resetting parent");
875:                    parent = new BoundingBox(new Point(10, 10), new Dimension(
876:                            300, 300));
877:                    parent.add(child);
878:                    System.out.println("SUBTRACT_FROM_LEFT");
879:                    parent.subtract(child, SUBTRACT_FROM_LEFT);
880:                    System.out.println("new parent: " + parent.toString());
881:                    System.out.println();
882:                    System.out.println("Resetting parent");
883:                    parent = new BoundingBox(new Point(10, 10), new Dimension(
884:                            300, 300));
885:                    parent.add(child);
886:                    System.out.println("SUBTRACT_FROM_RIGHT");
887:                    parent.subtract(child, SUBTRACT_FROM_RIGHT);
888:                    System.out.println("new parent: " + parent.toString());
889:                    System.out.println();
890:
891:                    System.exit(0);
892:                } catch (Exception e) {
893:                    e.printStackTrace();
894:                    System.exit(1);
895:                }
896:            }
897:
898:            // Private methods /////////////////////////////
899:
900:            /**
901:             * Creates a new <code>BoundingBox</code> instance.
902:             *
903:             * @param p a <code>Point</code> value
904:             * @param d a <code>Dimension</code> value
905:             * @param drawingPoint a <code>Point</code> value
906:             */
907:            private BoundingBox(Point p, Dimension d, Point drawingPoint,
908:                    Point absolute) {
909:                super (p, d);
910:                this .drawingPoint = drawingPoint;
911:                this .absoluteLocation = absolute;
912:            }
913:
914:            /**
915:             * <p>Checks the horizontal alignment passed into a 
916:             * method to make sure it is one of the valid values</p>
917:             *
918:             * @param hAlign an <code>int</code> value
919:             * @return a <code>boolean</code> value
920:             */
921:            private boolean checkHAlign(int hAlign) {
922:                int len = HORIZ_ALIGNS.length;
923:                for (int i = 0; i < len; i++) {
924:                    if (hAlign == HORIZ_ALIGNS[i]) {
925:                        return true;
926:                    }
927:                }
928:                return false;
929:            }
930:
931:            /**
932:             * <p>Checks the vertical alignment passed into a 
933:             * method to make sure it is one of the valid values</p>
934:             *
935:             * @param vAlign an <code>int</code> value
936:             * @return a <code>boolean</code> value
937:             */
938:            private boolean checkVAlign(int vAlign) {
939:                int len = VERT_ALIGNS.length;
940:                for (int i = 0; i < len; i++) {
941:                    if (vAlign == VERT_ALIGNS[i]) {
942:                        return true;
943:                    }
944:                }
945:                return false;
946:            }
947:
948:        } // end class BoundingBox
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.