1
14 package demo.view.orgchart;
15
16 import java.awt.Color;
17 import java.awt.Component;
18 import java.awt.Dimension;
19 import java.awt.GradientPaint;
20 import java.awt.Graphics;
21 import java.awt.Graphics2D;
22 import java.awt.Insets;
23 import java.awt.Rectangle;
24 import java.awt.RenderingHints;
25 import java.awt.Shape;
26 import java.awt.RenderingHints.Key;
27 import java.awt.event.MouseEvent;
28 import java.awt.event.MouseWheelListener;
29 import java.awt.geom.AffineTransform;
30 import java.awt.geom.Ellipse2D;
31 import java.awt.geom.GeneralPath;
32 import java.awt.geom.Rectangle2D;
33 import java.beans.PropertyChangeEvent;
34 import java.beans.PropertyChangeListener;
35 import java.util.Map;
36
37 import javax.swing.Icon;
38
39 import demo.view.orgchart.OrgChartTreeModel.Employee;
40
41 import y.anim.AnimationFactory;
42 import y.anim.AnimationObject;
43 import y.anim.AnimationPlayer;
44 import y.base.DataProvider;
45 import y.base.Edge;
46 import y.base.Node;
47 import y.base.NodeMap;
48 import y.geom.OrientedRectangle;
49 import y.geom.YInsets;
50 import y.geom.YPoint;
51 import y.geom.YVector;
52 import y.layout.NormalizingGraphElementOrderStage;
53 import y.layout.Layouter;
54 import y.util.D;
55 import y.util.DataProviderAdapter;
56 import y.view.EdgeRealizer;
57 import y.view.GenericNodeRealizer;
58 import y.view.Graph2D;
59 import y.view.Graph2DSelectionEvent;
60 import y.view.Graph2DSelectionListener;
61 import y.view.Graph2DView;
62 import y.view.Graph2DViewMouseWheelZoomListener;
63 import y.view.HitInfo;
64 import y.view.LineType;
65 import y.view.MagnifierViewMode;
66 import y.view.NodeLabel;
67 import y.view.NodeRealizer;
68 import y.view.Overview;
69 import y.view.PolyLineEdgeRealizer;
70 import y.view.Scroller;
71 import y.view.ShapeNodePainter;
72 import y.view.ShapeNodeRealizer;
73 import y.view.SmartNodeLabelModel;
74 import y.view.TooltipMode;
75 import y.view.ViewAnimationFactory;
76 import y.view.ViewCoordDrawableAdapter;
77 import y.view.ViewMode;
78 import y.view.YLabel;
79 import y.view.GenericNodeRealizer.Painter;
80 import y.view.YRenderingHints;
81 import y.view.hierarchy.DefaultHierarchyGraphFactory;
82 import y.view.hierarchy.GroupNodeRealizer;
83
84
90 public class JOrgChart extends JTreeChart {
91
92
96 static final Color FILL_COLOR = new Color( 0xCCFFFF );
97 static final Color FILL_COLOR2 = new Color( 0x249AE7 );
98 static final Color LINE_COLOR = new Color( 0x249AE7 );
99
100 static final Color SELECTED_FILL_COLOR = Color.WHITE;
101 static final Color SELECTED_LINE_COLOR = Color.ORANGE;
102 static final Color SELECTED_FILL_COLOR2 = Color.ORANGE;
103
104 static final Color SELECTED_HOVER_FILL_COLOR = SELECTED_FILL_COLOR;
105 static final Color SELECTED_HOVER_LINE_COLOR = SELECTED_LINE_COLOR;
106 static final Color SELECTED_HOVER_FILL_COLOR2 = new Color( 0xFFEE55 );
107
108 static final Color HOVER_FILL_COLOR2 = new Color( 0x63CCEE );
109 static final Color HOVER_FILL_COLOR = FILL_COLOR;
110 static final Color HOVER_LINE_COLOR = LINE_COLOR;
111
112
113 static final Color EDGE_COLOR = new Color( 0x999999 );
114 static final Color GROUP_FILL_COLOR = new Color(231,219,182,100);
115
116
119 private NodeMap highlightMap;
120
121 public JOrgChart(OrgChartTreeModel model) {
122 super(model, createUserObjectDP(), createGroupIdDataProvider());
123
124 highlightMap = getGraph2D().createNodeMap();
125
126 getGraph2D().addGraph2DSelectionListener(new TreeChartSelectionListener());
127
128 setPaintDetailThreshold(0);
129 setAntialiasedPainting(true);
130
131
135
139 getCanvasComponent().addPropertyChangeListener(new PropertyChangeListener() {
140 public void propertyChange(PropertyChangeEvent evt) {
141 if("Zoom".equals(evt.getPropertyName())) {
142 double zoom = getZoom();
143 Object lodValue = null;
144 if(zoom >= 0.8) {
145 lodValue = LODRenderingHint.VALUE_LOD_HIGH;
146 }
147 else if(zoom < 0.8 && zoom >= 0.3) {
148 lodValue = LODRenderingHint.VALUE_LOD_MEDIUM;
149 }
150 else if(zoom < 0.3) {
151 lodValue = LODRenderingHint.VALUE_LOD_LOW;
152 }
153 getRenderingHints().put(LODRenderingHint.KEY_LOD, lodValue);
154 }
155 }
156 });
157
158 updateChart();
159 }
160
161
164 static class LODRenderingHint {
165 public static final Object VALUE_LOD_LOW = "LODRenderingHint#VALUE_LOD_LOW";
166 public static final Object VALUE_LOD_MEDIUM = "LODRenderingHint#VALUE_LOD_MEDIUM";
167 public static final Object VALUE_LOD_HIGH = "LODRenderingHint#VALUE_LOD_HIGH";
168 public static final Object VALUE_LOD_OVERVIEW = "LODRenderingHint#VALUE_LOD_OVERVIEW";
169
170 public static final Key KEY_LOD = new RenderingHints.Key(0) {
171 public boolean isCompatibleValue(Object val) {
172 return true; }
174 };
175 }
176
177
180 static DataProvider createUserObjectDP() {
181 return new DataProviderAdapter() {
182 public Object get(Object dataHolder) {
183 return dataHolder;
184 }
185 };
186 }
187
188
192 static DataProvider createGroupIdDataProvider() {
193 return new DataProviderAdapter() {
194 public Object get(Object dataHolder) {
195 return ((Employee)dataHolder).businessUnit;
196 }
197 };
198 }
199
200
204 protected void addMouseInteraction() {
205 super.addMouseInteraction();
206 TooltipMode tooltipMode = new TooltipMode() {
207
215 protected String getNodeTip(Node node) {
216 String tipText = null;
217 Object lod = view.getRenderingHints().get(LODRenderingHint.KEY_LOD);
218 if (lod == LODRenderingHint.VALUE_LOD_LOW || lod == LODRenderingHint.VALUE_LOD_MEDIUM) { if (getGraph2D().getHierarchyManager().isNormalNode(node)) {
220 Employee e = (Employee) ((JOrgChart) view).getUserObject(node);
221 tipText = "<html><b>" + e.name + "</b><br>" + e.position + "<br>Status " + e.status + "</html>";
222 }
223 }
224 return tipText;
225 }
226
227
234 protected String getNodeLabelTip(NodeLabel label) {
235 String tipText = null;
236 Object lod = view.getRenderingHints().get(LODRenderingHint.KEY_LOD);
237 if (lod == LODRenderingHint.VALUE_LOD_HIGH) {
238 NodeRealizer realizer = label.getRealizer();
239 if (realizer.labelCount() > 6 && label == realizer.getLabel(6)) {
240 Node node = label.getNode();
241 if (getGraph2D().getHierarchyManager().isNormalNode(node)) {
242 Employee e = (Employee) ((JOrgChart) view).getUserObject(node);
243 tipText = "Status " + e.status;
244 }
245 }
246 }
247 return tipText;
248 }
249 };
250 tooltipMode.setEdgeTipEnabled(false);
251 tooltipMode.setNodeLabelTipEnabled(true);
252 addViewMode(tooltipMode);
253 addViewMode(new MiddleClickMagnifierViewMode());
254 addViewMode(new RollOverViewMode());
255 }
256
257
260 protected JTreeChartViewMode createTreeChartViewMode() {
261 JTreeChartViewMode viewMode = super.createTreeChartViewMode();
262 Scroller scroller = viewMode.getScroller();
263 scroller.setScrollSpeedFactor(2.0);
264 scroller.setDrawable(new ScrollerDrawable(this,scroller));
265 return viewMode;
266 }
267
268
271 protected MouseWheelListener createMouseWheelListener() {
272 Graph2DViewMouseWheelZoomListener mwl = new Graph2DViewMouseWheelZoomListener();
273 mwl.setZoomIndicatorShowing(true);
274 mwl.setCenterZooming(false);
275 mwl.setMaximumZoom(4);
276 mwl.setLimitMinimumZoomByContentSize(true);
277 mwl.setZoomIndicatorColor(new Color(170, 160,125));
278 return mwl;
279 }
280
281
286 protected void setRealizerDefaults() {
287 PolyLineEdgeRealizer er = new PolyLineEdgeRealizer();
288 er.setSmoothedBends(true);
289 er.setLineColor(EDGE_COLOR);
290 er.setLineType(LineType.LINE_2);
291
292 getGraph2D().setDefaultEdgeRealizer(er);
294
295 GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
296
297 Painter painter = new EmployeePainter();
298 Map implementationsMap = factory.createDefaultConfigurationMap();
301 implementationsMap.put(GenericNodeRealizer.Painter.class, painter);
302
303 factory.addConfiguration("employee", implementationsMap);
304 GenericNodeRealizer nr = new GenericNodeRealizer();
305 nr.setFillColor(FILL_COLOR);
306 nr.setFillColor2(FILL_COLOR2);
307 nr.setLineColor(LINE_COLOR);
308 nr.setLineType(LineType.LINE_2);
309 nr.setSize(220,110);
310
311 nr.setConfiguration("employee");
312
313 getGraph2D().setDefaultNodeRealizer(nr);
315
316 DefaultHierarchyGraphFactory gf = (DefaultHierarchyGraphFactory) getGraph2D().getHierarchyManager().getGraphFactory();
317 CustomGroupNodeRealizer gnr = new CustomGroupNodeRealizer();
318 gnr.setConsiderNodeLabelSize(true);
319 gnr.setShapeType(ShapeNodeRealizer.ROUND_RECT);
320 gnr.setFillColor(GROUP_FILL_COLOR);
321 gnr.setLineType(LineType.LINE_1);
322 gnr.setLineColor(Color.DARK_GRAY);
323 gnr.getLabel().setBackgroundColor(new Color(102,204,255,200));
324 gnr.getLabel().setTextColor(new Color(31,104,163).darker());
325 gnr.getLabel().setFontSize(20);
326 gnr.getLabel().setAlignment(NodeLabel.ALIGN_LEFT);
327 gnr.getStateLabel().setVisible(false);
328
329 gf.setDefaultFolderNodeRealizer(gnr);
331 gf.setDefaultGroupNodeRealizer(gnr.createCopy());
332 }
333
334
337 protected void configureGroupRealizer(Node groupNode, Object groupId, boolean collapsed) {
338 GroupNodeRealizer nr = (GroupNodeRealizer) getGraph2D().getRealizer(groupNode);
339 nr.setGroupClosed(collapsed);
340 nr.setBorderInsets(new YInsets(0,0,0,0));
341 nr.getLabel().setText(groupId.toString());
342 }
343
344
349 protected void configureNodeRealizer(Node n) {
350 Employee employee = (Employee) getUserObject(n);
351
352 GenericNodeRealizer gnr = (GenericNodeRealizer) getGraph2D().getRealizer(n);
353 gnr.setUserData(employee);
354
355 if(gnr.labelCount() == 1) { NodeLabel label = gnr.getLabel();
358 label.setIcon(employee.icon);
359 SmartNodeLabelModel model = new SmartNodeLabelModel();
360 label.setLabelModel(model);
361 label.setModelParameter(model.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_TOP_LEFT));
362 label.setInsets(new Insets(2,2,2,2));
363
364 label = addTextLabel(gnr, employee.name, 65, 4, true);
366 label = addTextLabel(gnr, employee.position, 65, label.getOffsetY() + label.getHeight() + 4, true); label = addTextLabel(gnr, employee.email, 65, label.getOffsetY() + label.getHeight() + 4, true); label = addTextLabel(gnr, employee.phone, 65, label.getOffsetY() + label.getHeight() + 4, true); label = addTextLabel(gnr, employee.fax, 65, label.getOffsetY() + label.getHeight() + 4, true);
371 label = gnr.createNodeLabel();
373 gnr.addLabel(label);
374 label.setIcon(new StateIcon(employee.status));
375 model = new SmartNodeLabelModel();
376 label.setLabelModel(model);
377 label.setModelParameter(model.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_TOP_RIGHT));
378 label.setInsets(new Insets(2,2,2,2));
379
380 label = addTextLabel(gnr, employee.name,0,0, false);
382 model = new SmartNodeLabelModel();
383 label.setLabelModel(model);
384 label.setModelParameter(model.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_CENTER));
385 label.setFontSize(20);
386 label.setVisible(false);
387 }
388 }
389
390
394 protected void configureEdgeRealizer(Edge e) {
395 EdgeRealizer er = getGraph2D().getRealizer(e);
396 Employee target = (Employee) getUserObject(e.target());
397 if(target != null && "true".equals(target.assistant)) {
398 er.setLineType(LineType.DASHED_2);
399 }
400 super.configureEdgeRealizer(e);
401 }
402
403
406 NodeLabel addTextLabel(NodeRealizer nr, String text, double x, double y, boolean cropping) {
407 NodeLabel label = nr.createNodeLabel();
408 nr.addLabel(label);
409 label.setFontSize(11);
410 if(text == null) text = "";
411 label.setText(text);
412 SmartNodeLabelModel labelModel = new SmartNodeLabelModel();
413 label.setLabelModel(labelModel);
414 final double h = label.getHeight();
415 OrientedRectangle box = new OrientedRectangle(nr.getX() + x, nr.getY() + y + h, label.getWidth(), h);
416 label.setModelParameter(labelModel.createAlignedModelParameter(box, nr, SmartNodeLabelModel.ALIGNMENT_TOP_LEFT));
417
418 if(cropping) {
419 double height = label.getHeight();
420 label.setAutoSizePolicy(YLabel.AUTOSIZE_NONE);
421 label.setConfiguration("CroppingLabel");
422 label.setAlignment(YLabel.ALIGN_LEFT);
423 double width = nr.getWidth() - x;
424 label.setContentSize(width, height);
425 }
426 return label;
427 }
428
429
434 static class StateIcon implements Icon {
435
436 static final Color STATUS_UNAVAILABLE_COLOR = new Color(255,120,40);
437 static final Color STATUS_PRESENT_COLOR = new Color(25,205,44);
438 static final Color STATUS_TRAVEL_COLOR = new Color(221,175,233);
439 static final Color STATUS_UNAVAILABLE_COLOR2 = new Color(231,32,0);
440 static final Color STATUS_PRESENT_COLOR2 = new Color(19,157,33);
441 static final Color STATUS_TRAVEL_COLOR2 = new Color(137,44,160);
442
443 String state;
444 StateIcon(String state) {
445 this.state = state;
446 }
447
448 public int getIconHeight() {
449 return 24;
450 }
451
452 public int getIconWidth() {
453 return 24;
454 }
455
456 public void paintIcon(Component c, Graphics g, int x, int y) {
457 Graphics2D gfx = (Graphics2D) g;
458
459 Object lod = gfx.getRenderingHint(LODRenderingHint.KEY_LOD);
460
461 if(lod == LODRenderingHint.VALUE_LOD_MEDIUM) {
462 if("present".equals(state)) {
463 gfx.setColor(STATUS_PRESENT_COLOR);
464 }
465 else if("travel".equals(state)) {
466 gfx.setColor(STATUS_TRAVEL_COLOR);
467 }
468 else if("unavailable".equals(state)){
469 gfx.setColor(STATUS_UNAVAILABLE_COLOR);
470 }
471
472 Rectangle2D box = new Rectangle2D.Double(x,y,getIconWidth(), getIconHeight());
473 gfx.fill(box);
474 gfx.setColor(gfx.getColor().darker());
475 gfx.draw(box);
476 }
477 else if(lod == LODRenderingHint.VALUE_LOD_HIGH) {
478 Ellipse2D.Double circle = new Ellipse2D.Double(x,y,getIconWidth(), getIconHeight());
479 if("present".equals(state)) {
480 gfx.setColor(STATUS_PRESENT_COLOR2);
481 }
482 else if("travel".equals(state)) {
483 gfx.setColor(STATUS_TRAVEL_COLOR2);
484 }
485 else if("unavailable".equals(state)){
486 gfx.setColor(STATUS_UNAVAILABLE_COLOR2);
487 }
488 gfx.fill(circle);
489 double size = Math.min(getIconHeight(), getIconWidth());
490 double delta = size*0.12;
491 circle.setFrame(circle.x+delta, circle.y+delta, circle.width-2*delta, circle.height-2*delta);
492 gfx.setColor(Color.WHITE);
493 gfx.fill(circle);
494 if("present".equals(state)) {
495 gfx.setColor(STATUS_PRESENT_COLOR);
496 }
497 else if("travel".equals(state)) {
498 gfx.setColor(STATUS_TRAVEL_COLOR);
499 }
500 else if("unavailable".equals(state)){
501 gfx.setColor(STATUS_UNAVAILABLE_COLOR);
502 }
503 circle.setFrame(circle.x+delta, circle.y+delta, circle.width-2*delta, circle.height-2*delta);
504 gfx.fill(circle);
505 }
506 }
507 }
508
509
512 static class EmployeePainter extends ShapeNodePainter {
513
514 public EmployeePainter() {
515 setShapeType(ROUND_RECT);
516 }
517
518 public void paint(NodeRealizer context, Graphics2D gfx) {
519
520 if(!context.isVisible()) {
521 return;
522 }
523
524 GenericNodeRealizer gnr = (GenericNodeRealizer) context;
525 Employee employee = (Employee) gnr.getUserData();
526
527 Object lod = gfx.getRenderingHint(LODRenderingHint.KEY_LOD);
528
529 if(lod == LODRenderingHint.VALUE_LOD_OVERVIEW) {
530 Color ovc = null;
531 if("present".equals(employee.status)) {
532 ovc = new Color(19,157,33); } else if("travel".equals(employee.status)) {
534 ovc = new Color(137,44,160);
535 }
536 else {
537 ovc = Color.RED;
538 }
539 Rectangle2D rect = new Rectangle2D.Double(context.getX()+20, context.getY()+20, context.getWidth()-40, context.getHeight()-40);
540 gfx.setColor(ovc);
541 gfx.fill(rect);
542 gfx.setColor(Color.black);
543 gfx.draw(rect);
544 }
545 else if(lod == LODRenderingHint.VALUE_LOD_LOW || lod == LODRenderingHint.VALUE_LOD_MEDIUM) {
546 super.paintNode(context, gfx, true);
547
548 context.getLabel(6).paint(gfx);
550 NodeLabel label = context.getLabel(7);
551 label.setVisible(true);
552 label.paint(gfx);
553 label.setVisible(false);
554 }
555 else { super.paintNode(context, gfx, false);
557 context.paintText(gfx);
558 }
559 }
560
561 public void paintSloppy(NodeRealizer context, Graphics2D gfx) {
562 paint(context, gfx);
563 }
564
565 protected Color createSelectionColor(Color original) {
566 return original;
569 }
570
571
574 protected void paintFilledShape(NodeRealizer context, Graphics2D graphics, Shape shape) {
575 double x = context.getX();
576 double y = context.getY();
577 double width = context.getWidth();
578 double height = context.getHeight();
579
580 boolean selected = useSelectionStyle(context, graphics);
581 Color c1 = getFillColor(context, selected);
582
583 if (c1 != null && !context.isTransparent()) {
584 Color c2 = getFillColor2(context, selected);
585 if (c2 != null && useGradientStyle(graphics)) {
586 graphics.setPaint(new GradientPaint(
587 (float) (x + 0.5*width), (float) y, c1,
588 (float) (x + 0.5*width), (float) (y+height), c2));
589 } else {
590 graphics.setColor(c1);
591 }
592 graphics.fill(shape);
593
594 Shape clip = graphics.getClip();
595 graphics.clip(shape);
596 graphics.clip(new Rectangle2D.Double(x,y,width,0.4*height));
597 graphics.setColor(new Color(1.0f, 1.0f,1.0f, 0.3f));
598 graphics.fill(shape);
599 graphics.setClip(clip);
600 }
601 }
602
603 private static boolean useGradientStyle( final Graphics2D graphics ) {
604 return YRenderingHints.isGradientPaintingEnabled(graphics);
605 }
606
607 private static boolean useSelectionStyle(
608 final NodeRealizer context,
609 final Graphics2D graphics
610 ) {
611 return context.isSelected() &&
612 YRenderingHints.isSelectionPaintingEnabled(graphics);
613 }
614 }
615
616
619 static class CustomGroupNodeRealizer extends GroupNodeRealizer {
620 public CustomGroupNodeRealizer() {
621 super();
622 }
623 public CustomGroupNodeRealizer(NodeRealizer nr) {
624 super(nr);
625 }
626 public NodeRealizer createCopy(NodeRealizer nr) {
627 return new CustomGroupNodeRealizer(nr);
628 }
629 public boolean isSelected() {
630 return false;
631 }
632 }
633
634
639 static class ScrollerDrawable extends ViewCoordDrawableAdapter {
640 Scroller scroller;
641 public ScrollerDrawable(Graph2DView view, Scroller scroller) {
642 super(view, null);
643 this.scroller = scroller;
644 }
645
646 protected void paintViewCoordinateDrawable(Graphics2D gfx) {
647 gfx = (Graphics2D)gfx.create();
648 YVector dir = scroller.getScrollDirection();
649 YPoint p = scroller.getScrollStart();
650 p = new YPoint(view.toViewCoordX(p.x), view.toViewCoordY(p.y));
651 Ellipse2D circle = new Ellipse2D.Double(p.x-15, p.y-15,30,30);
652 gfx.setColor(new Color(204,204,204,100));
653 gfx.fill(circle);
654 gfx.setColor(new Color(100,100,100,100));
655 gfx.setStroke(LineType.LINE_1);
656 AffineTransform trans = new AffineTransform(dir.getX(), dir.getY(),-dir.getY(), dir.getX(),p.x,p.y);
657 GeneralPath arrow = new GeneralPath(GeneralPath.WIND_NON_ZERO,6);
658 arrow.moveTo(15,0);
659 arrow.lineTo(0,5);
660 arrow.lineTo(0,-5);
661 gfx.fill(trans.createTransformedShape(arrow));
662 gfx.setStroke(LineType.LINE_2);
663 gfx.draw(circle);
664 gfx.dispose();
665 }
666
667 protected Rectangle getViewCoordinateDrawableBounds() {
668 YPoint p = scroller.getScrollStart();
669 p = new YPoint(view.toViewCoordX(p.x), view.toViewCoordY(p.y));
670 return (new Rectangle2D.Double(p.x-20,p.y-20,40,40)).getBounds();
671 }
672 }
673
674
677 public Overview createOverview() {
678 Overview ov = super.createOverview();
679
680 ov.putClientProperty("Overview.PaintStyle", "Funky");
683 ov.putClientProperty("Overview.AllowZooming", Boolean.TRUE);
685 ov.putClientProperty("Overview.AllowKeyboardNavigation", Boolean.TRUE);
687 ov.putClientProperty("Overview.Inverse", Boolean.TRUE);
689 ov.setPreferredSize(new Dimension(200, 150));
690 ov.setMinimumSize(new Dimension(200, 150));
691 ov.getRenderingHints().put(LODRenderingHint.KEY_LOD, LODRenderingHint.VALUE_LOD_OVERVIEW);
692 return ov;
693 }
694
695 private void configureColors(
696 final NodeRealizer nr,
697 final boolean selected,
698 final boolean highlighted
699 ) {
700 if(highlighted) {
701 if(selected) {
702 nr.setFillColor(SELECTED_HOVER_FILL_COLOR);
703 nr.setFillColor2(SELECTED_HOVER_FILL_COLOR2);
704 nr.setLineColor(SELECTED_HOVER_LINE_COLOR);
705 } else { nr.setFillColor(HOVER_FILL_COLOR);
707 nr.setFillColor2(HOVER_FILL_COLOR2);
708 nr.setLineColor(HOVER_LINE_COLOR);
709 }
710 } else { if(selected) {
712 nr.setFillColor(SELECTED_FILL_COLOR);
713 nr.setFillColor2(SELECTED_FILL_COLOR2);
714 nr.setLineColor(SELECTED_LINE_COLOR);
715 } else { nr.setFillColor(FILL_COLOR);
717 nr.setFillColor2(FILL_COLOR2);
718 nr.setLineColor(LINE_COLOR);
719 }
720 }
721 }
722
723
727 static class MiddleClickMagnifierViewMode extends ViewMode {
728 MagnifierViewMode magnifierVM;
729 public MiddleClickMagnifierViewMode() {
730 magnifierVM = new MagnifierViewMode() {
731 public void mouseDraggedMiddle(double x, double y) {
732 mouseDraggedLeft(x, y);
733 }
734 protected Graph2DView createMagnifierView() {
735 Graph2DView view = super.createMagnifierView();
736 view.getRenderingHints().put(LODRenderingHint.KEY_LOD, LODRenderingHint.VALUE_LOD_HIGH);
737 return view;
738 }
739 };
740 magnifierVM.setMouseWheelEnabled(false);
741 }
742
743 public void mousePressedMiddle(double x, double y) {
744 double zoom = view.getZoom();
745 magnifierVM.setMagnifierZoomFactor(Math.max(1,1/zoom));
746 magnifierVM.setMagnifierRadius(200);
747 view.addViewMode(magnifierVM);
748 magnifierVM.mouseMoved(lastPressEvent);
749 view.updateView();
750 }
751
752 public void mouseReleasedMiddle(double x, double y) {
753 view.removeViewMode(magnifierVM);
754 }
755 }
756
757
761 private class RollOverViewMode extends ViewMode {
762
763
764 private static final int PREFERRED_DURATION = 200;
765
766
767 private Node lastHitNode;
768 private AnimationPlayer player;
769 private PropertyChangeListener pcl;
770 private MouseEvent lastRelevantMouseEvent;
771
772 public RollOverViewMode() {
773 }
774
775 public void activate(boolean b) {
776 super.activate(b);
777 if(b) {
778 player = new AnimationPlayer();
779 player.addAnimationListener(view);
780 player.setBlocking(false);
781 pcl = new CanvasPropertyChangeListener();
782 view.getCanvasComponent().addPropertyChangeListener(pcl);
783 } else if(pcl != null){
784 view.getCanvasComponent().removePropertyChangeListener(pcl);
785 }
786 }
787
788 public void mouseExited(MouseEvent e) {
789 lastRelevantMouseEvent = null;
790 if(lastHitNode != null) {
791 unmark(lastHitNode);
792 }
793 }
794
795 public void mouseDragged(MouseEvent e) {
796 lastRelevantMouseEvent = e;
797 super.mouseDragged(e);
798 }
799
800 public void mouseMoved(MouseEvent e) {
801 lastRelevantMouseEvent = e;
802 super.mouseMoved(e);
803 }
804
805
808 public void mouseMoved( final double x, final double y ) {
809 final HitInfo hi = getHitInfo(x, y);
810
811 if (hi.hasHitNodes()) {
812 final Node node = (Node) hi.hitNodes().current();
813 if (node != lastHitNode) {
814 unmark(lastHitNode);
815 }
816 JOrgChart treeView = (JOrgChart) view;
817 Object userObject = treeView.getUserObject(node);
818 if(userObject != null && !treeView.highlightMap.getBool(node)) {
819 mark(node);
820 lastHitNode = node;
821 }
822 } else {
823 unmark(lastHitNode);
824 lastHitNode = null;
825 }
826 }
827
828
831 protected HitInfo getHitInfo( final double x, final double y ) {
832 final HitInfo hi = new HitInfo(view, x, y, true, HitInfo.NODE);
833 setLastHitInfo(hi);
834 return hi;
835 }
836
837
841 protected void mark( final Node node ) {
842 JOrgChart treeView = (JOrgChart) view;
845 boolean highlighted = treeView.highlightMap.getBool(node);
846 Object userObject = treeView.getUserObject(node);
847
848 if(userObject != null && !highlighted) {
849 treeView.highlightMap.setBool(node, true);
850
851 final NodeRealizer nr = getGraph2D().getRealizer(node);
852 final NodeRealizer newTheme = nr.createCopy();
853 configureColors(newTheme, getGraph2D().isSelected(node), true);
854
855 ViewAnimationFactory animFac = new ViewAnimationFactory(view);
856 final AnimationObject ao = animFac.color(
857 nr,
858 newTheme.getFillColor(), newTheme.getFillColor2(), newTheme.getLineColor(),
859 ViewAnimationFactory.APPLY_EFFECT, PREFERRED_DURATION);
860
861 final AnimationObject eao = AnimationFactory.createEasedAnimation(ao);
862 player.animate(eao);
863 }
864 }
865
866 class CanvasPropertyChangeListener implements PropertyChangeListener {
867 public void propertyChange(PropertyChangeEvent evt) {
868 if(lastRelevantMouseEvent != null && ("Zoom".equals(evt.getPropertyName()) || "ViewPoint".equals(evt.getPropertyName()))) {
869 if(lastHitNode != null && getHitInfo(lastRelevantMouseEvent).getHitNode() != lastHitNode) {
870 unmark(lastHitNode);
871 lastHitNode = null;
872 }
873 else if(lastHitNode == null && lastRelevantMouseEvent != null) {
874 lastHitNode = getHitInfo(lastRelevantMouseEvent).getHitNode();
875 if(lastHitNode != null) {
876 mark(lastHitNode);
877 }
878 }
879 }
880 }
881 }
882
883
887 protected void unmark( final Node node ) {
888 if (node == null || node.getGraph() == null) {
889 player.stop();
890 return;
891 }
892 JOrgChart treeView = (JOrgChart) view;
893 Object userObject = null;
894 try {
895 userObject = treeView.getUserObject(node);
896 }
897 catch(Exception ex) {
898 D.bug(node);
899 }
900 if(userObject != null && treeView.highlightMap.getBool(node)) {
901 treeView.highlightMap.setBool(node, false);
902
903 player.stop();
904 configureColors(getGraph2D().getRealizer(node), getGraph2D().isSelected(node), false);
905 getGraph2D().updateViews();
906 }
907 }
908 }
909
910
914 class TreeChartSelectionListener implements Graph2DSelectionListener {
915 public void onGraph2DSelectionEvent(Graph2DSelectionEvent ev) {
916 if(ev.getSubject() instanceof Node) {
917 Node node = (Node) ev.getSubject();
918 Object userObject = getUserObject(node);
919 if(userObject != null) {
920 Graph2D graph = getGraph2D();
921 configureColors(getGraph2D().getRealizer(node), graph.isSelected(node), highlightMap.getBool(node));
922 graph.updateViews();
923 }
924 }
925 }
926 }
927
928
932 protected Layouter createLayouter() {
933 OrgChartLayouter layouter = new OrgChartLayouter();
934 Graph2D graph = getGraph2D();
935 DataProvider childLayoutDP = new DataProviderAdapter() {
936 public Object get(Object n) {
937 Employee employee = (Employee) getUserObject((Node)n);
938 if(employee != null) {
939 if("leftHanging".equals(employee.layout)) {
940 return OrgChartLayouter.CHILD_LAYOUT_LEFT_BELOW;
941 }
942 if("rightHanging".equals(employee.layout)) {
943 return OrgChartLayouter.CHILD_LAYOUT_RIGHT_BELOW;
944 }
945 if("bothHanging".equals(employee.layout)) {
946 return OrgChartLayouter.CHILD_LAYOUT_BELOW;
947 }
948 }
949 return OrgChartLayouter.CHILD_LAYOUT_SAME_LAYER;
950 }
951 };
952 graph.addDataProvider(OrgChartLayouter.CHILD_LAYOUT_DPKEY, childLayoutDP);
953
954 DataProvider assistantDP = new DataProviderAdapter() {
955 public boolean getBool(Object n) {
956 Employee employee = (Employee) getUserObject((Node)n);
957 return employee != null && "true".equals(employee.assistant);
958 }
959 };
960 graph.addDataProvider(OrgChartLayouter.ASSISTANT_DPKEY, assistantDP);
961
962 layouter.setDuplicateBendsOnSharedBus(true);
963
964 return new NormalizingGraphElementOrderStage(layouter);
965 }
966 }
967