001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * RenderBox.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.layout.model;
030:
031: import org.jfree.report.layout.model.context.BoxDefinition;
032: import org.jfree.report.layout.model.context.StaticBoxLayoutProperties;
033: import org.jfree.report.layout.text.ExtendedBaselineInfo;
034: import org.jfree.report.style.BandStyleKeys;
035: import org.jfree.report.style.StyleSheet;
036: import org.jfree.report.style.ElementStyleKeys;
037: import org.jfree.report.util.geom.StrictBounds;
038: import org.jfree.util.Log;
039:
040: /**
041: * Creation-Date: 03.04.2007, 13:17:47
042: *
043: * @author Thomas Morgner
044: */
045: public abstract class RenderBox extends RenderNode {
046: public static final int NO_MANUAL_BREAK = 0;
047: public static final int DIRECT_MANUAL_BREAK = 1;
048: public static final int INDIRECT_MANUAL_BREAK = 2;
049:
050: public static final boolean LOG_PRUNE = true;
051:
052: private long contentAreaX1;
053: private long contentAreaX2;
054: private BoxDefinition boxDefinition;
055: private StaticBoxLayoutProperties staticBoxLayoutProperties;
056: private RenderNode firstChild;
057: private RenderNode lastChild;
058: private boolean open;
059: private ExtendedBaselineInfo baselineInfo;
060: private String name;
061: private int manualBreakIndicator;
062: private long staticBoxPropertiesAge;
063: private Object stateKey;
064: private RenderBox textEllipseBox;
065:
066: private RenderNode prunedChild;
067: private boolean deepFinished;
068:
069: protected RenderBox(final StyleSheet styleSheet,
070: final BoxDefinition boxDefinition, final Object stateKey) {
071: super (styleSheet);
072: if (boxDefinition == null) {
073: throw new NullPointerException();
074: }
075:
076: this .boxDefinition = boxDefinition;
077: this .open = true;
078: this .staticBoxLayoutProperties = new StaticBoxLayoutProperties();
079: this .staticBoxPropertiesAge = -1;
080: this .staticBoxLayoutProperties
081: .setBreakAfter(getStyleSheet().getBooleanStyleProperty(
082: BandStyleKeys.PAGEBREAK_AFTER));
083: this .stateKey = stateKey;
084: }
085:
086: public boolean isSizeSpecifiesBorderBox() {
087: return boxDefinition.isSizeSpecifiesBorderBox();
088: }
089:
090: public RenderBox getTextEllipseBox() {
091: return textEllipseBox;
092: }
093:
094: public void setTextEllipseBox(final RenderBox textEllipseBox) {
095: this .textEllipseBox = textEllipseBox;
096: }
097:
098: public Object getStateKey() {
099: return stateKey;
100: }
101:
102: public int getManualBreakIndicator() {
103: return manualBreakIndicator;
104: }
105:
106: public void setManualBreakIndicator(final int manualBreakIndicator) {
107: this .manualBreakIndicator = manualBreakIndicator;
108: }
109:
110: public BoxDefinition getBoxDefinition() {
111: return boxDefinition;
112: }
113:
114: public RenderNode getFirstChild() {
115: return firstChild;
116: }
117:
118: protected void setFirstChild(final RenderNode firstChild) {
119: this .firstChild = firstChild;
120: }
121:
122: public RenderNode getLastChild() {
123: return lastChild;
124: }
125:
126: protected void setLastChild(final RenderNode lastChild) {
127: this .lastChild = lastChild;
128: }
129:
130: public void addGeneratedChild(final RenderNode child) {
131: if (child == null) {
132: throw new NullPointerException(
133: "Child to be added must not be null.");
134: }
135:
136: if (isHibernated()) {
137: throw new IllegalStateException(
138: "Check your state management, you've messed with an hibernated element.");
139: }
140:
141: if (lastChild != null) {
142: lastChild.setNext(child);
143: }
144:
145: child.setPrev(lastChild);
146: child.setNext(null);
147: lastChild = child;
148:
149: if (firstChild == null) {
150: firstChild = child;
151: }
152:
153: child.setParent(this );
154:
155: if (isFrozen()) {
156: child.freeze();
157: }
158: child.updateChangeTracker();
159: }
160:
161: public void addChild(final RenderNode child) {
162: if (child == null) {
163: throw new NullPointerException(
164: "Child to be added must not be null.");
165: }
166:
167: if (isOpen() == false) {
168: throw new IllegalStateException(
169: "Adding content to an already closed element: "
170: + this );
171: }
172:
173: if (isHibernated()) {
174: throw new IllegalStateException(
175: "Check your state management. You tried to modify a hibernated element.");
176: }
177:
178: if (this instanceof BlockRenderBox) {
179: if (child instanceof InlineRenderBox) {
180: throw new IllegalStateException();
181: }
182: }
183: if (lastChild != null) {
184: lastChild.setNext(child);
185: }
186:
187: child.setPrev(lastChild);
188: child.setNext(null);
189: lastChild = child;
190:
191: if (firstChild == null) {
192: firstChild = child;
193: }
194:
195: child.setParent(this );
196: if (isFrozen()) {
197: child.freeze();
198: }
199:
200: child.updateChangeTracker();
201: }
202:
203: /**
204: * Inserts the given target after the specified node. If the node is null, the target is inserted as first node.
205: *
206: * @param node
207: * @param target
208: */
209: protected void insertAfter(final RenderNode node,
210: final RenderNode target) {
211: if (node == null) {
212: // ok, insert as new first element.
213: final RenderNode firstChild = getFirstChild();
214: if (firstChild == null) {
215: setLastChild(target);
216: setFirstChild(target);
217: target.setParent(this );
218: target.setPrev(null);
219: target.setNext(null);
220: target.updateChangeTracker();
221: return;
222: }
223:
224: // we have a first-child.
225: firstChild.setPrev(target);
226: setFirstChild(target);
227: target.setParent(this );
228: target.setPrev(null);
229: target.setNext(firstChild);
230: target.updateChangeTracker();
231: return;
232: }
233:
234: if (node.getParent() != this ) {
235: throw new IllegalStateException("You made a big boo");
236: }
237:
238: final RenderNode next = node.getNext();
239: node.setNext(target);
240: target.setPrev(node);
241: target.setParent(this );
242: target.setNext(next);
243: if (next != null) {
244: next.setPrev(target);
245: } else {
246: setLastChild(target);
247: }
248: target.updateChangeTracker();
249: }
250:
251: /**
252: * Inserts the given target directly before the the specified node. If the node is null, the element is inserted at
253: * the last position.
254: *
255: * @param node
256: * @param target
257: */
258: protected void insertBefore(final RenderNode node,
259: final RenderNode target) {
260: if (node == null) {
261: final RenderNode lastChild = getLastChild();
262: if (lastChild == null) {
263: target.setParent(this );
264: target.setPrev(null);
265: target.setNext(null);
266: setFirstChild(target);
267: setLastChild(target);
268: target.updateChangeTracker();
269: return;
270: }
271:
272: setLastChild(target);
273: target.setParent(this );
274: target.setPrev(lastChild);
275: target.setNext(null);
276: lastChild.setNext(target);
277: target.updateChangeTracker();
278: return;
279: }
280:
281: if (node.getParent() != this ) {
282: throw new IllegalStateException("You made a big boo");
283: }
284:
285: final RenderNode prev = node.getPrev();
286: node.setPrev(target);
287: target.setNext(node);
288: target.setParent(this );
289: target.setPrev(prev);
290: if (prev != null) {
291: prev.setNext(target);
292: } else {
293: setFirstChild(target);
294: }
295: target.updateChangeTracker();
296: }
297:
298: public void replaceChild(final RenderNode old,
299: final RenderNode replacement) {
300: if (old.getParent() != this ) {
301: throw new IllegalArgumentException("None of my childs.");
302: }
303: if (old == replacement) {
304: // nothing to do ...
305: return;
306: }
307:
308: if (old == firstChild) {
309: firstChild = replacement;
310: }
311: if (old == lastChild) {
312: lastChild = replacement;
313: }
314:
315: final RenderNode prev = old.getPrev();
316: final RenderNode next = old.getNext();
317: replacement.setPrev(prev);
318: replacement.setNext(next);
319:
320: if (prev != null) {
321: prev.setNext(replacement);
322: }
323: if (next != null) {
324: next.setPrev(replacement);
325: }
326:
327: replacement.setParent(this );
328:
329: old.setNext(null);
330: old.setPrev(null);
331: old.setParent(null);
332: old.updateChangeTracker();
333: replacement.updateChangeTracker();
334: }
335:
336: public void replaceChilds(final RenderNode old,
337: final RenderNode[] replacement) {
338: if (old.getParent() != this ) {
339: throw new IllegalArgumentException("None of my childs.");
340: }
341:
342: final int replacementCount = replacement.length;
343: if (replacementCount == 0) {
344: throw new IndexOutOfBoundsException("Array is empty ..");
345: }
346:
347: if (old == replacement[0]) {
348: if (replacementCount == 1) {
349: // nothing to do ...
350: return;
351: }
352: // throw new IllegalArgumentException
353: // ("Thou shall not use the replace method to insert new elements!");
354: }
355:
356: old.setParent(null);
357:
358: final RenderNode oldPrev = old.getPrev();
359: final RenderNode oldNext = old.getNext();
360:
361: // first, connect all replacements ...
362: RenderNode first = null;
363: RenderNode last = null;
364:
365: for (int i = 0; i < replacementCount; i++) {
366: if (last == null) {
367: last = replacement[i];
368: if (last != null) {
369: first = last;
370: first.setParent(this );
371: }
372: continue;
373: }
374:
375: final RenderNode node = replacement[i];
376:
377: last.setNext(node);
378: node.setPrev(last);
379: node.setParent(this );
380: last = node;
381: }
382:
383: if (first == null) {
384: throw new IndexOutOfBoundsException(
385: "Array is empty (NullValues stripped)..");
386: }
387:
388: if (old == firstChild) {
389: firstChild = first;
390: }
391:
392: if (old == lastChild) {
393: lastChild = last;
394: }
395:
396: // Something inbetween ...
397: first.setPrev(oldPrev);
398: last.setNext(oldNext);
399:
400: if (oldPrev != null) {
401: oldPrev.setNext(first);
402: }
403: if (oldNext != null) {
404: oldNext.setPrev(last);
405: }
406:
407: old.updateChangeTracker();
408:
409: for (int i = 0; i < replacementCount; i++) {
410: final RenderNode renderNode = replacement[i];
411: renderNode.updateChangeTracker();
412: }
413: }
414:
415: /**
416: * Derive creates a disconnected node that shares all the properties of the original node. The derived node will no
417: * longer have any parent, silbling, child or any other relationships with other nodes.
418: *
419: * @return
420: */
421: public RenderNode derive(final boolean deepDerive) {
422: final RenderBox box = (RenderBox) super .derive(deepDerive);
423:
424: if (deepDerive) {
425: RenderNode node = firstChild;
426: RenderNode currentNode = null;
427: while (node != null) {
428: final RenderNode previous = currentNode;
429:
430: currentNode = node.derive(true);
431: currentNode.setParent(box);
432: if (previous == null) {
433: box.firstChild = currentNode;
434: currentNode.setPrev(null);
435: } else {
436: previous.setNext(currentNode);
437: currentNode.setPrev(previous);
438: }
439: node = node.getNext();
440: }
441:
442: box.lastChild = currentNode;
443: if (lastChild != null) {
444: box.lastChild.setNext(null);
445: }
446: } else {
447: box.firstChild = null;
448: box.lastChild = null;
449: }
450: return box;
451: }
452:
453: /**
454: * Derive creates a disconnected node that shares all the properties of the original node. The derived node will no
455: * longer have any parent, silbling, child or any other relationships with other nodes.
456: *
457: * @return
458: */
459: public RenderNode hibernate() {
460: final RenderBox box = (RenderBox) super .hibernate();
461:
462: RenderNode node = firstChild;
463: RenderNode currentNode = null;
464: while (node != null) {
465: final RenderNode previous = currentNode;
466:
467: currentNode = node.hibernate();
468: currentNode.setParent(box);
469: if (previous == null) {
470: box.firstChild = currentNode;
471: currentNode.setPrev(null);
472: } else {
473: previous.setNext(currentNode);
474: currentNode.setPrev(previous);
475: }
476: node = node.getNext();
477: }
478:
479: box.lastChild = currentNode;
480: if (lastChild != null) {
481: box.lastChild.setNext(null);
482: }
483: return box;
484: }
485:
486: /**
487: * Derive creates a disconnected node that shares all the properties of the original node. The derived node will no
488: * longer have any parent, silbling, child or any other relationships with other nodes.
489: *
490: * @return
491: */
492: public RenderNode deriveFrozen(final boolean deepDerive) {
493: final RenderBox box = (RenderBox) super
494: .deriveFrozen(deepDerive);
495: if (deepDerive) {
496: RenderNode node = firstChild;
497: RenderNode currentNode = null;
498: while (node != null) {
499: final RenderNode previous = currentNode;
500:
501: currentNode = node.deriveFrozen(true);
502: currentNode.setParent(box);
503: if (previous == null) {
504: box.firstChild = currentNode;
505: currentNode.setPrev(null);
506: } else {
507: previous.setNext(currentNode);
508: currentNode.setPrev(previous);
509: }
510: node = node.getNext();
511: }
512:
513: box.lastChild = currentNode;
514: if (lastChild != null) {
515: box.lastChild.setNext(null);
516: }
517: } else {
518: box.firstChild = null;
519: box.lastChild = null;
520: }
521: return box;
522: }
523:
524: public void addChilds(final RenderNode[] nodes) {
525: final int length = nodes.length;
526: for (int i = 0; i < length; i++) {
527: addChild(nodes[i]);
528: }
529: }
530:
531: public void addGeneratedChilds(final RenderNode[] nodes) {
532: final int nodeLength = nodes.length;
533: for (int i = 0; i < nodeLength; i++) {
534: addGeneratedChild(nodes[i]);
535: }
536: }
537:
538: public RenderNode findNodeById(final Object instanceId) {
539: if (instanceId == getInstanceId()) {
540: return this ;
541: }
542:
543: RenderNode child = getLastChild();
544: while (child != null) {
545: final RenderNode nodeById = child.findNodeById(instanceId);
546: if (nodeById != null) {
547: return nodeById;
548: }
549: child = child.getPrev();
550: }
551: return null;
552: }
553:
554: public boolean isAppendable() {
555: return isOpen();
556: }
557:
558: /**
559: * Removes all children.
560: */
561: public void clear() {
562: RenderNode child = getFirstChild();
563: while (child != null) {
564: final RenderNode nextChild = child.getNext();
565: if (child != getFirstChild()) {
566: child.getPrev().setNext(null);
567: }
568: child.setPrev(null);
569: child.setParent(null);
570: child = nextChild;
571: }
572: setFirstChild(null);
573: setLastChild(null);
574: updateChangeTracker();
575: }
576:
577: public RenderNode getVisibleFirst() {
578: RenderNode firstChild = getFirstChild();
579: while (firstChild != null) {
580: if (firstChild.isIgnorableForRendering() == false) {
581: return firstChild;
582: }
583: firstChild = firstChild.getNext();
584: }
585: return null;
586: }
587:
588: public RenderNode getVisibleLast() {
589: RenderNode lastChild = getLastChild();
590: while (lastChild != null) {
591: if (lastChild.isIgnorableForRendering() == false) {
592: return lastChild;
593: }
594: lastChild = lastChild.getPrev();
595: }
596: return null;
597: }
598:
599: private RenderNode getFirstNonEmpty() {
600: RenderNode firstChild = getFirstChild();
601: while (firstChild != null) {
602: if (firstChild.isEmpty() == false) {
603: return firstChild;
604: }
605: firstChild = firstChild.getNext();
606: }
607: return null;
608: }
609:
610: public boolean isEmpty() {
611: if (getBoxDefinition().isEmpty() == false) {
612: return false;
613: }
614:
615: final RenderNode node = getFirstNonEmpty();
616: if (node != null) {
617: return false;
618: }
619: // Ok, the childs were not able to tell us some truth ..
620: // lets try something else.
621: return true;
622: }
623:
624: public boolean isDiscardable() {
625: if (getBoxDefinition().isEmpty() == false) {
626: return false;
627: }
628:
629: RenderNode node = getFirstChild();
630: while (node != null) {
631: if (node.isDiscardable() == false) {
632: return false;
633: }
634: node = node.getNext();
635: }
636: return true;
637: }
638:
639: public void close() {
640: if (isOpen() == false) {
641: throw new IllegalStateException("Double close..");
642: }
643:
644: if (isHibernated()) {
645: throw new IllegalStateException(
646: "Check your state management. You tried to mess with an hibernated element.");
647: }
648:
649: this .open = false;
650:
651: RenderNode lastChild = getLastChild();
652: while (lastChild != null) {
653: if (lastChild.isDiscardable()) {
654: if (LOG_PRUNE) {
655: Log.debug("Pruning: " + lastChild);
656: }
657: remove(lastChild);
658: if (prunedChild == null) {
659: prunedChild = lastChild;
660: } else {
661: lastChild.setPrev(prunedChild);
662: prunedChild = lastChild;
663: }
664:
665: lastChild = getLastChild();
666: } else {
667: break;
668: }
669: }
670: }
671:
672: public void remove(final RenderNode child) {
673: final RenderBox parent = child.getParent();
674: if (parent != this ) {
675: throw new IllegalArgumentException("None of my childs");
676: }
677:
678: child.setParent(null);
679:
680: final RenderNode prev = child.getPrev();
681: final RenderNode next = child.getNext();
682:
683: if (prev != null) {
684: prev.setNext(next);
685: }
686:
687: if (next != null) {
688: next.setPrev(prev);
689: }
690:
691: if (firstChild == child) {
692: firstChild = next;
693: }
694: if (lastChild == child) {
695: lastChild = prev;
696: }
697: child.updateChangeTracker();
698: this .updateChangeTracker();
699: }
700:
701: public boolean isOpen() {
702: return open;
703: }
704:
705: public void freeze() {
706: if (isFrozen()) {
707: return;
708: }
709:
710: super .freeze();
711: RenderNode node = getFirstChild();
712: while (node != null) {
713: node.freeze();
714: node = node.getNext();
715: }
716: }
717:
718: /**
719: * Performs a simple split. This box will be altered to form the left/top side of the split, and a derived empty box
720: * will be returned, which makes up the right/bottom side.
721: * <p/>
722: * A split will only happen on inline-boxes during the line-break-step. In the ordinary layouting, splitting is not
723: * necesary.
724: *
725: * @param axis
726: * @return
727: */
728: public RenderBox split(final int axis) {
729: final RenderBox otherBox = (RenderBox) derive(false);
730: final BoxDefinition[] boxDefinitions = boxDefinition
731: .split(axis);
732: boxDefinition = boxDefinitions[0];
733: otherBox.boxDefinition = boxDefinitions[1];
734: return otherBox;
735: }
736:
737: public long getContentAreaX1() {
738: return contentAreaX1;
739: }
740:
741: public void setContentAreaX1(final long contentAreaX1) {
742: this .contentAreaX1 = contentAreaX1;
743: }
744:
745: public long getContentAreaX2() {
746: return contentAreaX2;
747: }
748:
749: public void setContentAreaX2(final long contentAreaX2) {
750: this .contentAreaX2 = contentAreaX2;
751: }
752:
753: public StaticBoxLayoutProperties getStaticBoxLayoutProperties() {
754: return staticBoxLayoutProperties;
755: }
756:
757: public ExtendedBaselineInfo getBaselineInfo() {
758: return baselineInfo;
759: }
760:
761: public void setBaselineInfo(final ExtendedBaselineInfo baselineInfo) {
762: this .baselineInfo = baselineInfo;
763: }
764:
765: public String getName() {
766: return name;
767: }
768:
769: public void setName(final String name) {
770: this .name = name;
771: }
772:
773: public boolean isBreakAfter() {
774: return staticBoxLayoutProperties.isBreakAfter();
775: }
776:
777: public long getStaticBoxPropertiesAge() {
778: return staticBoxPropertiesAge;
779: }
780:
781: public void setStaticBoxPropertiesAge(
782: final long staticBoxPropertiesAge) {
783: if (staticBoxLayoutProperties.getNominalBaselineInfo() == null) {
784: throw new IllegalStateException(
785: "Assertation: Cannot declare static-properties finished without a nominal baseline info");
786: }
787: this .staticBoxPropertiesAge = staticBoxPropertiesAge;
788: }
789:
790: public String toString() {
791: return getClass().getName() + '{' + "name='" + name + '\''
792: + ", x='" + getX() + '\'' + ", y='" + getY() + '\''
793: + ", width='" + getWidth() + '\'' + ", height='"
794: + getHeight() + '\'' + ", hexId='"
795: + System.identityHashCode(this ) + '\'' + ", finished='"
796: + isFinished() + '\'' + ", commited='" + isCommited()
797: + '\'' + '}';
798: }
799:
800: public void markCacheClean() {
801: super .markCacheClean();
802: this .staticBoxPropertiesAge = getChangeTracker();
803: }
804:
805: private boolean markedSeen;
806: private boolean markedOpen;
807:
808: private boolean appliedSeen;
809: private boolean appliedOpen;
810:
811: public void commitApplyMark() {
812: appliedOpen = markedOpen;
813: appliedSeen = markedSeen;
814: }
815:
816: public boolean isAppliedOpen() {
817: return appliedOpen;
818: }
819:
820: public boolean isAppliedSeen() {
821: return appliedSeen;
822: }
823:
824: public boolean isMarkedOpen() {
825: return markedOpen;
826: }
827:
828: public void setMarkedOpen(final boolean markedOpen) {
829: this .markedOpen = markedOpen;
830: }
831:
832: public boolean isMarkedSeen() {
833: return markedSeen;
834: }
835:
836: public void setMarkedSeen(final boolean markedSeen) {
837: this .markedSeen = markedSeen;
838: }
839:
840: public boolean isCommited() {
841: return appliedOpen == false && appliedSeen == true;
842: }
843:
844: public void reopenAfterRollback() {
845: this .open = appliedOpen;
846:
847: while (this .prunedChild != null) {
848: final RenderNode child = this .prunedChild;
849: this .prunedChild = child.getPrev();
850: addChild(child);
851: }
852: prunedChild = null;
853: }
854:
855: public boolean isDeepFinished() {
856: return deepFinished;
857: }
858:
859: public void setDeepFinished(final boolean deepFinished) {
860: this .deepFinished = deepFinished;
861: }
862:
863: public final boolean isBoxVisible(final StrictBounds drawArea) {
864: if (isNodeVisible(drawArea) == false) {
865: return false;
866: }
867:
868: final RenderBox parent = getParent();
869: if (parent == null) {
870: return true;
871: }
872:
873: final StyleSheet styleSheet = getStyleSheet();
874: if (styleSheet.getStyleProperty(ElementStyleKeys.ANCHOR_NAME) != null) {
875: return true;
876: }
877:
878: if (Boolean.FALSE.equals(styleSheet
879: .getStyleProperty(ElementStyleKeys.OVERFLOW_X))) {
880: final long parentX1 = parent.getX();
881: final long parentX2 = parentX1 + parent.getWidth();
882:
883: if (getWidth() == 0) {
884: // could be a line ..
885: return true;
886: }
887:
888: final long boxX1 = getX();
889: final long boxX2 = boxX1 + getWidth();
890:
891: if (boxX2 <= parentX1) {
892: return false;
893: }
894: if (boxX1 >= parentX2) {
895: return false;
896: }
897: }
898:
899: if (Boolean.FALSE.equals(styleSheet
900: .getStyleProperty(ElementStyleKeys.OVERFLOW_Y))) {
901: // Compute whether the box is at least partially contained in the parent's bounding box.
902: final long parentY1 = parent.getY();
903: final long parentY2 = parentY1 + parent.getHeight();
904:
905: if (getHeight() == 0) {
906: // could be a line ..
907: return true;
908: }
909:
910: final long boxY1 = getY();
911: final long boxY2 = boxY1 + getHeight();
912:
913: if (boxY2 <= parentY1) {
914: return false;
915: }
916: if (boxY1 >= parentY2) {
917: return false;
918: }
919: }
920: return true;
921: }
922: }
|