1:
84:
85: package ;
86:
87: import ;
88: import ;
89: import ;
90: import ;
91: import ;
92: import ;
93: import ;
94: import ;
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101: import ;
102:
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110: import ;
111: import ;
112: import ;
113: import ;
114: import ;
115: import ;
116: import ;
117: import ;
118: import ;
119: import ;
120:
121:
124: public class CategoryAxis extends Axis implements Cloneable, Serializable {
125:
126:
127: private static final long serialVersionUID = 5886554608114265863L;
128:
129:
132: public static final double DEFAULT_AXIS_MARGIN = 0.05;
133:
134:
138: public static final double DEFAULT_CATEGORY_MARGIN = 0.20;
139:
140:
141: private double lowerMargin;
142:
143:
144: private double upperMargin;
145:
146:
147: private double categoryMargin;
148:
149:
150: private int maximumCategoryLabelLines;
151:
152:
156: private float maximumCategoryLabelWidthRatio;
157:
158:
159: private int categoryLabelPositionOffset;
160:
161:
165: private CategoryLabelPositions categoryLabelPositions;
166:
167:
168: private Map tickLabelFontMap;
169:
170:
171: private transient Map tickLabelPaintMap;
172:
173:
174: private Map categoryLabelToolTips;
175:
176:
179: public CategoryAxis() {
180: this(null);
181: }
182:
183:
188: public CategoryAxis(String label) {
189:
190: super(label);
191:
192: this.lowerMargin = DEFAULT_AXIS_MARGIN;
193: this.upperMargin = DEFAULT_AXIS_MARGIN;
194: this.categoryMargin = DEFAULT_CATEGORY_MARGIN;
195: this.maximumCategoryLabelLines = 1;
196: this.maximumCategoryLabelWidthRatio = 0.0f;
197:
198: setTickMarksVisible(false);
199:
200: this.categoryLabelPositionOffset = 4;
201: this.categoryLabelPositions = CategoryLabelPositions.STANDARD;
202: this.tickLabelFontMap = new HashMap();
203: this.tickLabelPaintMap = new HashMap();
204: this.categoryLabelToolTips = new HashMap();
205:
206: }
207:
208:
213: public double getLowerMargin() {
214: return this.lowerMargin;
215: }
216:
217:
224: public void setLowerMargin(double margin) {
225: this.lowerMargin = margin;
226: notifyListeners(new AxisChangeEvent(this));
227: }
228:
229:
234: public double getUpperMargin() {
235: return this.upperMargin;
236: }
237:
238:
245: public void setUpperMargin(double margin) {
246: this.upperMargin = margin;
247: notifyListeners(new AxisChangeEvent(this));
248: }
249:
250:
255: public double getCategoryMargin() {
256: return this.categoryMargin;
257: }
258:
259:
267: public void setCategoryMargin(double margin) {
268: this.categoryMargin = margin;
269: notifyListeners(new AxisChangeEvent(this));
270: }
271:
272:
277: public int getMaximumCategoryLabelLines() {
278: return this.maximumCategoryLabelLines;
279: }
280:
281:
287: public void setMaximumCategoryLabelLines(int lines) {
288: this.maximumCategoryLabelLines = lines;
289: notifyListeners(new AxisChangeEvent(this));
290: }
291:
292:
297: public float getMaximumCategoryLabelWidthRatio() {
298: return this.maximumCategoryLabelWidthRatio;
299: }
300:
301:
307: public void setMaximumCategoryLabelWidthRatio(float ratio) {
308: this.maximumCategoryLabelWidthRatio = ratio;
309: notifyListeners(new AxisChangeEvent(this));
310: }
311:
312:
318: public int getCategoryLabelPositionOffset() {
319: return this.categoryLabelPositionOffset;
320: }
321:
322:
328: public void setCategoryLabelPositionOffset(int offset) {
329: this.categoryLabelPositionOffset = offset;
330: notifyListeners(new AxisChangeEvent(this));
331: }
332:
333:
339: public CategoryLabelPositions getCategoryLabelPositions() {
340: return this.categoryLabelPositions;
341: }
342:
343:
349: public void setCategoryLabelPositions(CategoryLabelPositions positions) {
350: if (positions == null) {
351: throw new IllegalArgumentException("Null 'positions' argument.");
352: }
353: this.categoryLabelPositions = positions;
354: notifyListeners(new AxisChangeEvent(this));
355: }
356:
357:
364: public Font getTickLabelFont(Comparable category) {
365: if (category == null) {
366: throw new IllegalArgumentException("Null 'category' argument.");
367: }
368: Font result = (Font) this.tickLabelFontMap.get(category);
369:
370: if (result == null) {
371: result = getTickLabelFont();
372: }
373: return result;
374: }
375:
376:
383: public void setTickLabelFont(Comparable category, Font font) {
384: if (category == null) {
385: throw new IllegalArgumentException("Null 'category' argument.");
386: }
387: if (font == null) {
388: this.tickLabelFontMap.remove(category);
389: }
390: else {
391: this.tickLabelFontMap.put(category, font);
392: }
393: notifyListeners(new AxisChangeEvent(this));
394: }
395:
396:
403: public Paint getTickLabelPaint(Comparable category) {
404: if (category == null) {
405: throw new IllegalArgumentException("Null 'category' argument.");
406: }
407: Paint result = (Paint) this.tickLabelPaintMap.get(category);
408:
409: if (result == null) {
410: result = getTickLabelPaint();
411: }
412: return result;
413: }
414:
415:
422: public void setTickLabelPaint(Comparable category, Paint paint) {
423: if (category == null) {
424: throw new IllegalArgumentException("Null 'category' argument.");
425: }
426: if (paint == null) {
427: this.tickLabelPaintMap.remove(category);
428: }
429: else {
430: this.tickLabelPaintMap.put(category, paint);
431: }
432: notifyListeners(new AxisChangeEvent(this));
433: }
434:
435:
442: public void addCategoryLabelToolTip(Comparable category, String tooltip) {
443: if (category == null) {
444: throw new IllegalArgumentException("Null 'category' argument.");
445: }
446: this.categoryLabelToolTips.put(category, tooltip);
447: notifyListeners(new AxisChangeEvent(this));
448: }
449:
450:
458: public String getCategoryLabelToolTip(Comparable category) {
459: if (category == null) {
460: throw new IllegalArgumentException("Null 'category' argument.");
461: }
462: return (String) this.categoryLabelToolTips.get(category);
463: }
464:
465:
471: public void removeCategoryLabelToolTip(Comparable category) {
472: if (category == null) {
473: throw new IllegalArgumentException("Null 'category' argument.");
474: }
475: this.categoryLabelToolTips.remove(category);
476: notifyListeners(new AxisChangeEvent(this));
477: }
478:
479:
483: public void clearCategoryLabelToolTips() {
484: this.categoryLabelToolTips.clear();
485: notifyListeners(new AxisChangeEvent(this));
486: }
487:
488:
499: public double getCategoryJava2DCoordinate(CategoryAnchor anchor,
500: int category,
501: int categoryCount,
502: Rectangle2D area,
503: RectangleEdge edge) {
504:
505: double result = 0.0;
506: if (anchor == CategoryAnchor.START) {
507: result = getCategoryStart(category, categoryCount, area, edge);
508: }
509: else if (anchor == CategoryAnchor.MIDDLE) {
510: result = getCategoryMiddle(category, categoryCount, area, edge);
511: }
512: else if (anchor == CategoryAnchor.END) {
513: result = getCategoryEnd(category, categoryCount, area, edge);
514: }
515: return result;
516:
517: }
518:
519:
529: public double getCategoryStart(int category, int categoryCount,
530: Rectangle2D area,
531: RectangleEdge edge) {
532:
533: double result = 0.0;
534: if ((edge == RectangleEdge.TOP) || (edge == RectangleEdge.BOTTOM)) {
535: result = area.getX() + area.getWidth() * getLowerMargin();
536: }
537: else if ((edge == RectangleEdge.LEFT)
538: || (edge == RectangleEdge.RIGHT)) {
539: result = area.getMinY() + area.getHeight() * getLowerMargin();
540: }
541:
542: double categorySize = calculateCategorySize(categoryCount, area, edge);
543: double categoryGapWidth = calculateCategoryGapSize(
544: categoryCount, area, edge
545: );
546:
547: result = result + category * (categorySize + categoryGapWidth);
548:
549: return result;
550: }
551:
552:
562: public double getCategoryMiddle(int category, int categoryCount,
563: Rectangle2D area, RectangleEdge edge) {
564:
565: return getCategoryStart(category, categoryCount, area, edge)
566: + calculateCategorySize(categoryCount, area, edge) / 2;
567:
568: }
569:
570:
580: public double getCategoryEnd(int category, int categoryCount,
581: Rectangle2D area, RectangleEdge edge) {
582:
583: return getCategoryStart(category, categoryCount, area, edge)
584: + calculateCategorySize(categoryCount, area, edge);
585:
586: }
587:
588:
598: protected double calculateCategorySize(int categoryCount, Rectangle2D area,
599: RectangleEdge edge) {
600:
601: double result = 0.0;
602: double available = 0.0;
603:
604: if ((edge == RectangleEdge.TOP) || (edge == RectangleEdge.BOTTOM)) {
605: available = area.getWidth();
606: }
607: else if ((edge == RectangleEdge.LEFT)
608: || (edge == RectangleEdge.RIGHT)) {
609: available = area.getHeight();
610: }
611: if (categoryCount > 1) {
612: result = available * (1 - getLowerMargin() - getUpperMargin()
613: - getCategoryMargin());
614: result = result / categoryCount;
615: }
616: else {
617: result = available * (1 - getLowerMargin() - getUpperMargin());
618: }
619: return result;
620:
621: }
622:
623:
633: protected double calculateCategoryGapSize(int categoryCount,
634: Rectangle2D area,
635: RectangleEdge edge) {
636:
637: double result = 0.0;
638: double available = 0.0;
639:
640: if ((edge == RectangleEdge.TOP) || (edge == RectangleEdge.BOTTOM)) {
641: available = area.getWidth();
642: }
643: else if ((edge == RectangleEdge.LEFT)
644: || (edge == RectangleEdge.RIGHT)) {
645: available = area.getHeight();
646: }
647:
648: if (categoryCount > 1) {
649: result = available * getCategoryMargin() / (categoryCount - 1);
650: }
651:
652: return result;
653:
654: }
655:
656:
667: public AxisSpace reserveSpace(Graphics2D g2, Plot plot,
668: Rectangle2D plotArea,
669: RectangleEdge edge, AxisSpace space) {
670:
671:
672: if (space == null) {
673: space = new AxisSpace();
674: }
675:
676:
677: if (!isVisible()) {
678: return space;
679: }
680:
681:
682: double tickLabelHeight = 0.0;
683: double tickLabelWidth = 0.0;
684: if (isTickLabelsVisible()) {
685: g2.setFont(getTickLabelFont());
686: AxisState state = new AxisState();
687:
688: refreshTicks(g2, state, plotArea, edge);
689: if (edge == RectangleEdge.TOP) {
690: tickLabelHeight = state.getMax();
691: }
692: else if (edge == RectangleEdge.BOTTOM) {
693: tickLabelHeight = state.getMax();
694: }
695: else if (edge == RectangleEdge.LEFT) {
696: tickLabelWidth = state.getMax();
697: }
698: else if (edge == RectangleEdge.RIGHT) {
699: tickLabelWidth = state.getMax();
700: }
701: }
702:
703:
704: Rectangle2D labelEnclosure = getLabelEnclosure(g2, edge);
705: double labelHeight = 0.0;
706: double labelWidth = 0.0;
707: if (RectangleEdge.isTopOrBottom(edge)) {
708: labelHeight = labelEnclosure.getHeight();
709: space.add(
710: labelHeight + tickLabelHeight
711: + this.categoryLabelPositionOffset, edge
712: );
713: }
714: else if (RectangleEdge.isLeftOrRight(edge)) {
715: labelWidth = labelEnclosure.getWidth();
716: space.add(
717: labelWidth + tickLabelWidth + this.categoryLabelPositionOffset,
718: edge
719: );
720: }
721: return space;
722:
723: }
724:
725:
728: public void configure() {
729:
730: }
731:
732:
748: public AxisState draw(Graphics2D g2,
749: double cursor,
750: Rectangle2D plotArea,
751: Rectangle2D dataArea,
752: RectangleEdge edge,
753: PlotRenderingInfo plotState) {
754:
755:
756: if (!isVisible()) {
757: return new AxisState(cursor);
758: }
759:
760: if (isAxisLineVisible()) {
761: drawAxisLine(g2, cursor, dataArea, edge);
762: }
763:
764:
765: AxisState state = new AxisState(cursor);
766: state = drawCategoryLabels(g2, dataArea, edge, state, plotState);
767: state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state);
768:
769: return state;
770:
771: }
772:
773:
789: protected AxisState drawCategoryLabels(Graphics2D g2,
790: Rectangle2D dataArea,
791: RectangleEdge edge,
792: AxisState state,
793: PlotRenderingInfo plotState) {
794:
795:
796:
797: return drawCategoryLabels(g2, dataArea, dataArea, edge, state,
798: plotState);
799: }
800:
801:
815: protected AxisState drawCategoryLabels(Graphics2D g2,
816: Rectangle2D plotArea,
817: Rectangle2D dataArea,
818: RectangleEdge edge,
819: AxisState state,
820: PlotRenderingInfo plotState) {
821:
822: if (state == null) {
823: throw new IllegalArgumentException("Null 'state' argument.");
824: }
825:
826: if (isTickLabelsVisible()) {
827: List ticks = refreshTicks(g2, state, plotArea, edge);
828: state.setTicks(ticks);
829:
830: int categoryIndex = 0;
831: Iterator iterator = ticks.iterator();
832: while (iterator.hasNext()) {
833:
834: CategoryTick tick = (CategoryTick) iterator.next();
835: g2.setFont(getTickLabelFont(tick.getCategory()));
836: g2.setPaint(getTickLabelPaint(tick.getCategory()));
837:
838: CategoryLabelPosition position
839: = this.categoryLabelPositions.getLabelPosition(edge);
840: double x0 = 0.0;
841: double x1 = 0.0;
842: double y0 = 0.0;
843: double y1 = 0.0;
844: if (edge == RectangleEdge.TOP) {
845: x0 = getCategoryStart(categoryIndex, ticks.size(),
846: dataArea, edge);
847: x1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea,
848: edge);
849: y1 = state.getCursor() - this.categoryLabelPositionOffset;
850: y0 = y1 - state.getMax();
851: }
852: else if (edge == RectangleEdge.BOTTOM) {
853: x0 = getCategoryStart(categoryIndex, ticks.size(),
854: dataArea, edge);
855: x1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea,
856: edge);
857: y0 = state.getCursor() + this.categoryLabelPositionOffset;
858: y1 = y0 + state.getMax();
859: }
860: else if (edge == RectangleEdge.LEFT) {
861: y0 = getCategoryStart(categoryIndex, ticks.size(),
862: dataArea, edge);
863: y1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea,
864: edge);
865: x1 = state.getCursor() - this.categoryLabelPositionOffset;
866: x0 = x1 - state.getMax();
867: }
868: else if (edge == RectangleEdge.RIGHT) {
869: y0 = getCategoryStart(categoryIndex, ticks.size(),
870: dataArea, edge);
871: y1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea,
872: edge);
873: x0 = state.getCursor() + this.categoryLabelPositionOffset;
874: x1 = x0 - state.getMax();
875: }
876: Rectangle2D area = new Rectangle2D.Double(x0, y0, (x1 - x0),
877: (y1 - y0));
878: Point2D anchorPoint = RectangleAnchor.coordinates(area,
879: position.getCategoryAnchor());
880: TextBlock block = tick.getLabel();
881: block.draw(g2, (float) anchorPoint.getX(),
882: (float) anchorPoint.getY(), position.getLabelAnchor(),
883: (float) anchorPoint.getX(), (float) anchorPoint.getY(),
884: position.getAngle());
885: Shape bounds = block.calculateBounds(g2,
886: (float) anchorPoint.getX(), (float) anchorPoint.getY(),
887: position.getLabelAnchor(), (float) anchorPoint.getX(),
888: (float) anchorPoint.getY(), position.getAngle());
889: if (plotState != null && plotState.getOwner() != null) {
890: EntityCollection entities
891: = plotState.getOwner().getEntityCollection();
892: if (entities != null) {
893: String tooltip = getCategoryLabelToolTip(
894: tick.getCategory());
895: entities.add(new TickLabelEntity(bounds, tooltip,
896: null));
897: }
898: }
899: categoryIndex++;
900: }
901:
902: if (edge.equals(RectangleEdge.TOP)) {
903: double h = state.getMax();
904: state.cursorUp(h);
905: }
906: else if (edge.equals(RectangleEdge.BOTTOM)) {
907: double h = state.getMax();
908: state.cursorDown(h);
909: }
910: else if (edge == RectangleEdge.LEFT) {
911: double w = state.getMax();
912: state.cursorLeft(w);
913: }
914: else if (edge == RectangleEdge.RIGHT) {
915: double w = state.getMax();
916: state.cursorRight(w);
917: }
918: }
919: return state;
920: }
921:
922:
932: public List refreshTicks(Graphics2D g2,
933: AxisState state,
934: Rectangle2D dataArea,
935: RectangleEdge edge) {
936:
937: List ticks = new java.util.ArrayList();
938:
939:
940: if (dataArea.getHeight() <= 0.0 || dataArea.getWidth() < 0.0) {
941: return ticks;
942: }
943:
944: CategoryPlot plot = (CategoryPlot) getPlot();
945: List categories = plot.getCategories();
946: double max = 0.0;
947:
948: if (categories != null) {
949: CategoryLabelPosition position
950: = this.categoryLabelPositions.getLabelPosition(edge);
951: float r = this.maximumCategoryLabelWidthRatio;
952: if (r <= 0.0) {
953: r = position.getWidthRatio();
954: }
955:
956: float l = 0.0f;
957: if (position.getWidthType() == CategoryLabelWidthType.CATEGORY) {
958: l = (float) calculateCategorySize(categories.size(), dataArea,
959: edge);
960: }
961: else {
962: if (RectangleEdge.isLeftOrRight(edge)) {
963: l = (float) dataArea.getWidth();
964: }
965: else {
966: l = (float) dataArea.getHeight();
967: }
968: }
969: int categoryIndex = 0;
970: Iterator iterator = categories.iterator();
971: while (iterator.hasNext()) {
972: Comparable category = (Comparable) iterator.next();
973: TextBlock label = createLabel(category, l * r, edge, g2);
974: if (edge == RectangleEdge.TOP || edge == RectangleEdge.BOTTOM) {
975: max = Math.max(max,
976: calculateTextBlockHeight(label, position, g2));
977: }
978: else if (edge == RectangleEdge.LEFT
979: || edge == RectangleEdge.RIGHT) {
980: max = Math.max(max,
981: calculateTextBlockWidth(label, position, g2));
982: }
983: Tick tick = new CategoryTick(category, label,
984: position.getLabelAnchor(), position.getRotationAnchor(),
985: position.getAngle());
986: ticks.add(tick);
987: categoryIndex = categoryIndex + 1;
988: }
989: }
990: state.setMax(max);
991: return ticks;
992:
993: }
994:
995:
1005: protected TextBlock createLabel(Comparable category, float width,
1006: RectangleEdge edge, Graphics2D g2) {
1007: TextBlock label = TextUtilities.createTextBlock(
1008: category.toString(), getTickLabelFont(category),
1009: getTickLabelPaint(category), width, this.maximumCategoryLabelLines,
1010: new G2TextMeasurer(g2));
1011: return label;
1012: }
1013:
1014:
1023: protected double calculateTextBlockWidth(TextBlock block,
1024: CategoryLabelPosition position,
1025: Graphics2D g2) {
1026:
1027: RectangleInsets insets = getTickLabelInsets();
1028: Size2D size = block.calculateDimensions(g2);
1029: Rectangle2D box = new Rectangle2D.Double(
1030: 0.0, 0.0, size.getWidth(), size.getHeight()
1031: );
1032: Shape rotatedBox = ShapeUtilities.rotateShape(
1033: box, position.getAngle(), 0.0f, 0.0f
1034: );
1035: double w = rotatedBox.getBounds2D().getWidth()
1036: + insets.getTop() + insets.getBottom();
1037: return w;
1038:
1039: }
1040:
1041:
1050: protected double calculateTextBlockHeight(TextBlock block,
1051: CategoryLabelPosition position,
1052: Graphics2D g2) {
1053:
1054: RectangleInsets insets = getTickLabelInsets();
1055: Size2D size = block.calculateDimensions(g2);
1056: Rectangle2D box = new Rectangle2D.Double(
1057: 0.0, 0.0, size.getWidth(), size.getHeight()
1058: );
1059: Shape rotatedBox = ShapeUtilities.rotateShape(
1060: box, position.getAngle(), 0.0f, 0.0f
1061: );
1062: double h = rotatedBox.getBounds2D().getHeight()
1063: + insets.getTop() + insets.getBottom();
1064: return h;
1065:
1066: }
1067:
1068:
1076: public Object clone() throws CloneNotSupportedException {
1077: CategoryAxis clone = (CategoryAxis) super.clone();
1078: clone.tickLabelFontMap = new HashMap(this.tickLabelFontMap);
1079: clone.tickLabelPaintMap = new HashMap(this.tickLabelPaintMap);
1080: clone.categoryLabelToolTips = new HashMap(this.categoryLabelToolTips);
1081: return clone;
1082: }
1083:
1084:
1091: public boolean equals(Object obj) {
1092: if (obj == this) {
1093: return true;
1094: }
1095: if (!(obj instanceof CategoryAxis)) {
1096: return false;
1097: }
1098: if (!super.equals(obj)) {
1099: return false;
1100: }
1101: CategoryAxis that = (CategoryAxis) obj;
1102: if (that.lowerMargin != this.lowerMargin) {
1103: return false;
1104: }
1105: if (that.upperMargin != this.upperMargin) {
1106: return false;
1107: }
1108: if (that.categoryMargin != this.categoryMargin) {
1109: return false;
1110: }
1111: if (that.maximumCategoryLabelWidthRatio
1112: != this.maximumCategoryLabelWidthRatio) {
1113: return false;
1114: }
1115: if (that.categoryLabelPositionOffset
1116: != this.categoryLabelPositionOffset) {
1117: return false;
1118: }
1119: if (!ObjectUtilities.equal(that.categoryLabelPositions,
1120: this.categoryLabelPositions)) {
1121: return false;
1122: }
1123: if (!ObjectUtilities.equal(that.categoryLabelToolTips,
1124: this.categoryLabelToolTips)) {
1125: return false;
1126: }
1127: if (!ObjectUtilities.equal(this.tickLabelFontMap,
1128: that.tickLabelFontMap)) {
1129: return false;
1130: }
1131: if (!equalPaintMaps(this.tickLabelPaintMap, that.tickLabelPaintMap)) {
1132: return false;
1133: }
1134: return true;
1135: }
1136:
1137:
1142: public int hashCode() {
1143: if (getLabel() != null) {
1144: return getLabel().hashCode();
1145: }
1146: else {
1147: return 0;
1148: }
1149: }
1150:
1151:
1158: private void writeObject(ObjectOutputStream stream) throws IOException {
1159: stream.defaultWriteObject();
1160: writePaintMap(this.tickLabelPaintMap, stream);
1161: }
1162:
1163:
1171: private void readObject(ObjectInputStream stream)
1172: throws IOException, ClassNotFoundException {
1173: stream.defaultReadObject();
1174: this.tickLabelPaintMap = readPaintMap(stream);
1175: }
1176:
1177:
1190: private Map readPaintMap(ObjectInputStream in)
1191: throws IOException, ClassNotFoundException {
1192: boolean isNull = in.readBoolean();
1193: if (isNull) {
1194: return null;
1195: }
1196: Map result = new HashMap();
1197: int count = in.readInt();
1198: for (int i = 0; i < count; i++) {
1199: Comparable category = (Comparable) in.readObject();
1200: Paint paint = SerialUtilities.readPaint(in);
1201: result.put(category, paint);
1202: }
1203: return result;
1204: }
1205:
1206:
1217: private void writePaintMap(Map map, ObjectOutputStream out)
1218: throws IOException {
1219: if (map == null) {
1220: out.writeBoolean(true);
1221: }
1222: else {
1223: out.writeBoolean(false);
1224: Set keys = map.keySet();
1225: int count = keys.size();
1226: out.writeInt(count);
1227: Iterator iterator = keys.iterator();
1228: while (iterator.hasNext()) {
1229: Comparable key = (Comparable) iterator.next();
1230: out.writeObject(key);
1231: SerialUtilities.writePaint((Paint) map.get(key), out);
1232: }
1233: }
1234: }
1235:
1236:
1245: private boolean equalPaintMaps(Map map1, Map map2) {
1246: if (map1.size() != map2.size()) {
1247: return false;
1248: }
1249: Set keys = map1.keySet();
1250: Iterator iterator = keys.iterator();
1251: while (iterator.hasNext()) {
1252: Comparable key = (Comparable) iterator.next();
1253: Paint p1 = (Paint) map1.get(key);
1254: Paint p2 = (Paint) map2.get(key);
1255: if (!PaintUtilities.equal(p1, p2)) {
1256: return false;
1257: }
1258: }
1259: return true;
1260: }
1261:
1262: }