1
28 package demo.view.orgchart;
29
30 import demo.view.DemoBase;
31 import demo.view.orgchart.OrgChartTreeModel.Employee;
32 import demo.view.orgchart.ViewModeFactory.JTreeChartEditMode;
33 import y.anim.AnimationFactory;
34 import y.anim.AnimationObject;
35 import y.anim.AnimationPlayer;
36 import y.base.DataProvider;
37 import y.base.Edge;
38 import y.base.Node;
39 import y.base.NodeMap;
40 import y.geom.OrientedRectangle;
41 import y.geom.YInsets;
42 import y.layout.Layouter;
43 import y.layout.NormalizingGraphElementOrderStage;
44 import y.util.D;
45 import y.util.DataProviderAdapter;
46 import y.view.AutoDragViewMode;
47 import y.view.EdgeRealizer;
48 import y.view.GenericNodeRealizer;
49 import y.view.GenericNodeRealizer.Painter;
50 import y.view.Graph2D;
51 import y.view.Graph2DSelectionEvent;
52 import y.view.Graph2DSelectionListener;
53 import y.view.Graph2DView;
54 import y.view.Graph2DViewMouseWheelZoomListener;
55 import y.view.HitInfo;
56 import y.view.LineType;
57 import y.view.MagnifierViewMode;
58 import y.view.NodeLabel;
59 import y.view.NodeRealizer;
60 import y.view.Overview;
61 import y.view.PolyLineEdgeRealizer;
62 import y.view.ShapeNodePainter;
63 import y.view.ShapeNodeRealizer;
64 import y.view.SmartNodeLabelModel;
65 import y.view.TooltipMode;
66 import y.view.ViewAnimationFactory;
67 import y.view.ViewMode;
68 import y.view.YLabel;
69 import y.view.YRenderingHints;
70 import y.view.hierarchy.DefaultHierarchyGraphFactory;
71 import y.view.hierarchy.GroupNodeRealizer;
72
73 import javax.swing.Icon;
74 import javax.swing.tree.TreeModel;
75 import java.awt.Color;
76 import java.awt.Component;
77 import java.awt.Dimension;
78 import java.awt.GradientPaint;
79 import java.awt.Graphics;
80 import java.awt.Graphics2D;
81 import java.awt.Insets;
82 import java.awt.RenderingHints;
83 import java.awt.RenderingHints.Key;
84 import java.awt.Shape;
85 import java.awt.event.MouseEvent;
86 import java.awt.event.MouseWheelListener;
87 import java.awt.geom.Ellipse2D;
88 import java.awt.geom.Rectangle2D;
89 import java.beans.PropertyChangeEvent;
90 import java.beans.PropertyChangeListener;
91 import java.util.Iterator;
92 import java.util.Map;
93
94
100 public class JOrgChart extends JTreeChart {
101
102
106 static final Color FILL_COLOR = new Color( 0xCCFFFF );
107 static final Color FILL_COLOR2 = new Color( 0x249AE7 );
108 static final Color LINE_COLOR = new Color( 0x249AE7 );
109
110 static final Color SELECTED_FILL_COLOR = Color.WHITE;
111 static final Color SELECTED_LINE_COLOR = Color.ORANGE;
112 static final Color SELECTED_FILL_COLOR2 = Color.ORANGE;
113
114 static final Color SELECTED_HOVER_FILL_COLOR = SELECTED_FILL_COLOR;
115 static final Color SELECTED_HOVER_LINE_COLOR = SELECTED_LINE_COLOR;
116 static final Color SELECTED_HOVER_FILL_COLOR2 = new Color( 0xFFEE55 );
117
118 static final Color HOVER_FILL_COLOR2 = new Color( 0x63CCEE );
119 static final Color HOVER_FILL_COLOR = FILL_COLOR;
120 static final Color HOVER_LINE_COLOR = LINE_COLOR;
121
122
123 static final Color EDGE_COLOR = new Color( 0x999999 );
124 static final Color GROUP_FILL_COLOR = new Color(231,219,182,100);
125
126
127
130 private final NodeMap highlightMap;
131
132 public JOrgChart(final OrgChartTreeModel model) {
133 super(model, createUserObjectDP(), createGroupIdDataProvider());
134
135 highlightMap = getGraph2D().createNodeMap();
136
137 getGraph2D().addGraph2DSelectionListener(new TreeChartSelectionListener());
138
139 setPaintDetailThreshold(0);
140 setAntialiasedPainting(true);
141
142
146
150 getCanvasComponent().addPropertyChangeListener(new PropertyChangeListener() {
151 public void propertyChange(final PropertyChangeEvent evt) {
152 if("Zoom".equals(evt.getPropertyName())) {
153 final double zoom = getZoom();
154 Object lodValue = null;
155 if(zoom >= 0.8) {
156 lodValue = LODRenderingHint.VALUE_LOD_HIGH;
157 }
158 else if(zoom < 0.8 && zoom >= 0.3) {
159 lodValue = LODRenderingHint.VALUE_LOD_MEDIUM;
160 }
161 else if(zoom < 0.3) {
162 lodValue = LODRenderingHint.VALUE_LOD_LOW;
163 }
164 getRenderingHints().put(LODRenderingHint.KEY_LOD, lodValue);
165 }
166 }
167 });
168
169 updateChart();
170 }
171
172
175 static class LODRenderingHint {
176 public static final Object VALUE_LOD_LOW = "LODRenderingHint#VALUE_LOD_LOW";
177 public static final Object VALUE_LOD_MEDIUM = "LODRenderingHint#VALUE_LOD_MEDIUM";
178 public static final Object VALUE_LOD_HIGH = "LODRenderingHint#VALUE_LOD_HIGH";
179 public static final Object VALUE_LOD_OVERVIEW = "LODRenderingHint#VALUE_LOD_OVERVIEW";
180
181 public static final Key KEY_LOD = new RenderingHints.Key(0) {
182 public boolean isCompatibleValue(final Object val) {
183 return true; }
185 };
186 }
187
188
191 static DataProvider createUserObjectDP() {
192 return new DataProviderAdapter() {
193 public Object get(final Object dataHolder) {
194 return dataHolder;
195 }
196 };
197 }
198
199
203 static DataProvider createGroupIdDataProvider() {
204 return new DataProviderAdapter() {
205 public Object get(final Object dataHolder) {
206 return ((Employee)dataHolder).businessUnit;
207 }
208 };
209 }
210
211
216 public void setModel( final TreeModel model ) {
217 final boolean oldEditable = isEditable();
219
220 super.setModel(model);
221
222 final boolean newEditable = isEditable();
224
225 updateMouseInteraction(oldEditable, newEditable);
226 }
227
228 public void setGroupViewEnabled( final boolean enabled ) {
229 final boolean oldEditable = isEditable();
231
232 super.setGroupViewEnabled(enabled);
233
234 final boolean newEditable = isEditable();
236
237 updateMouseInteraction(oldEditable, newEditable);
238 }
239
240 private void updateMouseInteraction(
241 final boolean oldEditable, final boolean newEditable
242 ) {
243 if (oldEditable != newEditable) {
244
246 final Iterator it = getViewModes();
247 if (it.hasNext()) {
248 final ViewMode masterMode = (ViewMode) it.next();
252 masterMode.setChild(createTreeChartViewMode(), null, null);
253 }
254 }
255 }
256
257
265 protected void addMouseInteraction() {
266 final ViewMode masterMode = new ViewMode();
269 addViewMode(masterMode);
270 masterMode.setChild(createTreeChartViewMode(), null, null);
271
272 addViewMode(new AutoDragViewMode());
273
274 final MouseWheelListener mwl = createMouseWheelListener();
275 if (mwl != null) {
276 getCanvasComponent().addMouseWheelListener(mwl);
277 }
278
279
280 final TooltipMode tooltipMode = new JOrgChartTooltipMode();
281 tooltipMode.setEdgeTipEnabled(false);
282 tooltipMode.setNodeLabelTipEnabled(true);
283 addViewMode(tooltipMode);
284 addViewMode(new MiddleClickMagnifierViewMode());
285 addViewMode(new RollOverViewMode());
286 }
287
288
292 protected ViewMode createTreeChartViewMode() {
293 if (isEditable()) {
294 return ViewModeFactory.newEditMode(this);
295 } else {
296 return ViewModeFactory.newNavigationMode(this);
297 }
298 }
299
300 private boolean isEditable() {
301 return !isGroupViewEnabled() &&
302 JTreeChartEditMode.isCompatibleModel(getModel());
303 }
304
305
308 protected MouseWheelListener createMouseWheelListener() {
309 final Graph2DViewMouseWheelZoomListener mwl = new Graph2DViewMouseWheelZoomListener();
310 mwl.setZoomIndicatorShowing(true);
311 mwl.setCenterZooming(false);
312 mwl.setMaximumZoom(4);
313 mwl.setLimitMinimumZoomByContentSize(true);
314 mwl.setZoomIndicatorColor(new Color(170, 160,125));
315 return mwl;
316 }
317
318
323 protected void setRealizerDefaults() {
324 final PolyLineEdgeRealizer er = new PolyLineEdgeRealizer();
325 er.setSmoothedBends(true);
326 er.setLineColor(EDGE_COLOR);
327 er.setLineType(LineType.LINE_2);
328
329 getGraph2D().setDefaultEdgeRealizer(er);
331
332 final GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
333
334 final Painter painter = new EmployeePainter();
335 final Map implementationsMap = factory.createDefaultConfigurationMap();
338 implementationsMap.put(GenericNodeRealizer.Painter.class, painter);
339
340 factory.addConfiguration("employee", implementationsMap);
341 final GenericNodeRealizer nr = new GenericNodeRealizer();
342 nr.setFillColor(FILL_COLOR);
343 nr.setFillColor2(FILL_COLOR2);
344 nr.setLineColor(LINE_COLOR);
345 nr.setLineType(LineType.LINE_2);
346 nr.setSize(220,110);
347
348 nr.setConfiguration("employee");
349
350 getGraph2D().setDefaultNodeRealizer(nr);
352
353 final DefaultHierarchyGraphFactory gf = (DefaultHierarchyGraphFactory) getGraph2D().getHierarchyManager().getGraphFactory();
354 final CustomGroupNodeRealizer gnr = new CustomGroupNodeRealizer();
355 gnr.setConsiderNodeLabelSize(true);
356 gnr.setShapeType(ShapeNodeRealizer.ROUND_RECT);
357 gnr.setFillColor(GROUP_FILL_COLOR);
358 gnr.setLineType(LineType.LINE_1);
359 gnr.setLineColor(Color.DARK_GRAY);
360 gnr.getLabel().setBackgroundColor(new Color(102,204,255,200));
361 gnr.getLabel().setTextColor(new Color(31,104,163).darker());
362 gnr.getLabel().setFontSize(20);
363 gnr.getLabel().setAlignment(NodeLabel.ALIGN_LEFT);
364 gnr.getStateLabel().setVisible(false);
365
366 gf.setDefaultFolderNodeRealizer(gnr);
368 gf.setDefaultGroupNodeRealizer(gnr.createCopy());
369 }
370
371
374 protected void configureGroupRealizer(final Node groupNode, final Object groupId, final boolean collapsed) {
375 final GroupNodeRealizer nr = (GroupNodeRealizer) getGraph2D().getRealizer(groupNode);
376 nr.setGroupClosed(collapsed);
377 nr.setBorderInsets(new YInsets(0,0,0,0));
378 nr.getLabel().setText(groupId.toString());
379 }
380
381
386 protected void configureNodeRealizer(final Node n) {
387 final Employee employee = (Employee) getUserObject(n);
388
389 final GenericNodeRealizer gnr = (GenericNodeRealizer) getGraph2D().getRealizer(n);
390 gnr.setUserData(employee);
391
392 if (gnr.labelCount() == 1) { NodeLabel label = gnr.getLabel();
395 label.setIcon(employee.icon);
396 SmartNodeLabelModel model = new SmartNodeLabelModel();
397 label.setLabelModel(model,
398 model.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_TOP_LEFT));
399 label.setInsets(new Insets(2,2,2,2));
400
401 label = addTextLabel(gnr, employee.name, 65, 4, true);
403 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); addTextLabel(gnr, employee.fax, 65, label.getOffsetY() + label.getHeight() + 4, true);
408 label = gnr.createNodeLabel();
410 gnr.addLabel(label);
411 label.setIcon(new StateIcon(employee.status));
412 model = new SmartNodeLabelModel();
413 label.setLabelModel(model,
414 model.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_TOP_RIGHT));
415 label.setInsets(new Insets(2,2,2,2));
416
417 label = addTextLabel(gnr, employee.name, 0, 0, false);
419 model = new SmartNodeLabelModel();
420 label.setLabelModel(model,
421 model.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_CENTER));
422 label.setFontSize(20);
423 label.setVisible(false);
424 } else { gnr.getLabel().setIcon(employee.icon);
426 gnr.getLabel(1).setText(employee.name);
427 gnr.getLabel(2).setText(employee.position);
428 gnr.getLabel(3).setText(employee.email);
429 gnr.getLabel(4).setText(employee.phone);
430 gnr.getLabel(5).setText(employee.fax);
431 gnr.getLabel(6).setIcon(new StateIcon(employee.status));
432 gnr.getLabel(7).setText(employee.name);
433 }
434
435 if (employee.vacant) {
436 gnr.getLabel().setIcon(null);
437 gnr.getLabel(1).setText("Vacant");
438 gnr.getLabel(6).setIcon(null);
439 gnr.getLabel(7).setText("Vacant");
440 }
441 }
442
443
447 protected void configureEdgeRealizer(final Edge e) {
448 final EdgeRealizer er = getGraph2D().getRealizer(e);
449 final Employee target = (Employee) getUserObject(e.target());
450 if(target != null && target.assistant) {
451 er.setLineType(LineType.DASHED_2);
452 }
453 super.configureEdgeRealizer(e);
454 }
455
456
459 NodeLabel addTextLabel(final NodeRealizer nr, String text, final double x, final double y, final boolean cropping) {
460 final NodeLabel label = nr.createNodeLabel();
461 nr.addLabel(label);
462 label.setFontSize(11);
463 if (text == null) {
464 text = "";
465 }
466 label.setText(text);
467 final double h = label.getHeight();
468 final OrientedRectangle box = new OrientedRectangle(nr.getX() + x, nr.getY() + y + h, label.getWidth(), h);
469 final SmartNodeLabelModel labelModel = new SmartNodeLabelModel();
470 label.setLabelModel(labelModel, labelModel.createAlignedModelParameter(
471 box, nr, SmartNodeLabelModel.ALIGNMENT_TOP_LEFT));
472
473 if (cropping) {
474 final boolean isEmpty = "".equals(text);
475 if (isEmpty) {
476 label.setText("000-0000");
477 }
478 final double height = label.getHeight();
479 label.setAutoSizePolicy(YLabel.AUTOSIZE_NONE);
480 label.setConfiguration("CroppingLabel");
481 label.setAlignment(YLabel.ALIGN_LEFT);
482 final double width = nr.getWidth() - x;
483 label.setContentSize(width, height);
484 if (isEmpty) {
485 label.setText("");
486 }
487 }
488 return label;
489 }
490
491
496 static class StateIcon implements Icon {
497
498 static final Color STATUS_UNAVAILABLE_COLOR = new Color(255,120,40);
499 static final Color STATUS_PRESENT_COLOR = new Color(25,205,44);
500 static final Color STATUS_TRAVEL_COLOR = new Color(221,175,233);
501 static final Color STATUS_UNAVAILABLE_COLOR2 = new Color(231,32,0);
502 static final Color STATUS_PRESENT_COLOR2 = new Color(19,157,33);
503 static final Color STATUS_TRAVEL_COLOR2 = new Color(137,44,160);
504
505 String state;
506 StateIcon(final String state) {
507 this.state = state;
508 }
509
510 public int getIconHeight() {
511 return 24;
512 }
513
514 public int getIconWidth() {
515 return 24;
516 }
517
518 public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
519 final Color c1;
520 final Color c2;
521 if ("present".equals(state)) {
522 c1 = STATUS_PRESENT_COLOR;
523 c2 = STATUS_PRESENT_COLOR2;
524 }
525 else if ("travel".equals(state)) {
526 c1 = STATUS_TRAVEL_COLOR;
527 c2 = STATUS_TRAVEL_COLOR2;
528 }
529 else if ("unavailable".equals(state)) {
530 c1 = STATUS_UNAVAILABLE_COLOR;
531 c2 = STATUS_UNAVAILABLE_COLOR2;
532 } else {
533 return;
534 }
535
536 final Graphics2D gfx = (Graphics2D) g;
537 final Object lod = gfx.getRenderingHint(LODRenderingHint.KEY_LOD);
538
539 if(lod == LODRenderingHint.VALUE_LOD_MEDIUM) {
540 final Rectangle2D box = new Rectangle2D.Double(x,y,getIconWidth(), getIconHeight());
541 gfx.setColor(c1);
542 gfx.fill(box);
543 gfx.setColor(c2);
544 gfx.draw(box);
545 }
546 else if(lod == LODRenderingHint.VALUE_LOD_HIGH) {
547 final Ellipse2D.Double circle = new Ellipse2D.Double(x,y,getIconWidth(), getIconHeight());
548 gfx.setColor(c2);
549 gfx.fill(circle);
550 final double size = Math.min(getIconHeight(), getIconWidth());
551 final double delta = size*0.12;
552 circle.setFrame(circle.x+delta, circle.y+delta, circle.width-2*delta, circle.height-2*delta);
553 gfx.setColor(Color.WHITE);
554 gfx.fill(circle);
555 gfx.setColor(c1);
556 circle.setFrame(circle.x+delta, circle.y+delta, circle.width-2*delta, circle.height-2*delta);
557 gfx.fill(circle);
558 }
559 }
560 }
561
562
565 static class EmployeePainter extends ShapeNodePainter {
566 static final Color COLOR_MARKER = new Color(255, 141, 31);
567 static final Color COLOR_OVERLAY = new Color(255, 255, 255, 77);
568
569 public EmployeePainter() {
570 setShapeType(ROUND_RECT);
571 }
572
573 public void paint(final NodeRealizer context, final Graphics2D gfx) {
574
575 if(!context.isVisible()) {
576 return;
577 }
578
579 final Employee employee = getEmployee(context);
580
581 final Object lod = gfx.getRenderingHint(LODRenderingHint.KEY_LOD);
582
583 if (lod == LODRenderingHint.VALUE_LOD_OVERVIEW) {
584 final Color ovc;
585 if (employee.vacant) {
586 ovc = Color.LIGHT_GRAY;
587 } else if ("present".equals(employee.status)) {
588 ovc = StateIcon.STATUS_PRESENT_COLOR2;
589 } else if("travel".equals(employee.status)) {
590 ovc = StateIcon.STATUS_TRAVEL_COLOR2;
591 } else {
592 ovc = StateIcon.STATUS_UNAVAILABLE_COLOR2;
593 }
594 final Rectangle2D rect = new Rectangle2D.Double(
595 context.getX() + 20, context.getY() + 20,
596 context.getWidth() - 40, context.getHeight() - 40);
597 gfx.setColor(ovc);
598 gfx.fill(rect);
599 gfx.setColor(Color.BLACK);
600 gfx.draw(rect);
601 }
602 else if (lod == LODRenderingHint.VALUE_LOD_LOW ||
603 lod == LODRenderingHint.VALUE_LOD_MEDIUM) {
604 paintMarker(context, gfx);
605 super.paintNode(context, gfx, true);
606
607 context.getLabel(6).paint(gfx);
609 final NodeLabel label = context.getLabel(7);
610 label.setVisible(true);
611 label.paint(gfx);
612 label.setVisible(false);
613 }
614 else { paintMarker(context, gfx);
616 super.paintNode(context, gfx, false);
617 context.paintText(gfx);
618 }
619 }
620
621 private void paintMarker( final NodeRealizer context, final Graphics2D gfx ) {
622 final Node node = context.getNode();
623 final DataProvider dp = node.getGraph().getDataProvider(MARKED_NODES_DPKEY);
624 if (dp != null && dp.getBool(node)) {
625 final int margin = 7;
626 gfx.setColor(COLOR_MARKER);
627 gfx.fillRect(
628 (int) (context.getX()- margin),
629 (int) (context.getY()- margin),
630 (int) context.getWidth() + 2*margin,
631 (int) context.getHeight()+ 2*margin);
632 }
633 }
634
635 public void paintSloppy(final NodeRealizer context, final Graphics2D gfx) {
636 paint(context, gfx);
637 }
638
639 protected Color createSelectionColor(final Color original) {
640 return original;
643 }
644
645 protected Color getFillColor( final NodeRealizer context, final boolean selected ) {
646 if (!selected && getEmployee(context).vacant) {
647 return Color.LIGHT_GRAY;
648 } else {
649 return super.getFillColor(context, selected);
650 }
651 }
652
653 protected Color getFillColor2( final NodeRealizer context, final boolean selected ) {
654 if (!selected && getEmployee(context).vacant) {
655 return null;
656 } else {
657 return super.getFillColor2(context, selected);
658 }
659 }
660
661 protected Color getLineColor( final NodeRealizer context, final boolean selected ) {
662 if (!selected && getEmployee(context).vacant) {
663 return Color.LIGHT_GRAY;
664 } else {
665 return super.getLineColor(context, selected);
666 }
667 }
668
669
672 protected void paintFilledShape(final NodeRealizer context, final Graphics2D graphics, final Shape shape) {
673 final double x = context.getX();
674 final double y = context.getY();
675 final double width = context.getWidth();
676 final double height = context.getHeight();
677
678 final boolean selected = useSelectionStyle(context, graphics);
679 final Color c1 = getFillColor(context, selected);
680
681 if (c1 != null && !context.isTransparent()) {
682 final Color c2 = getFillColor2(context, selected);
683 if (c2 != null && useGradientStyle(graphics)) {
684 graphics.setPaint(new GradientPaint(
685 (float) (x + 0.5*width), (float) y, c1,
686 (float) (x + 0.5*width), (float) (y+height), c2));
687 } else {
688 graphics.setColor(c1);
689 }
690 graphics.fill(shape);
691
692 final Shape clip = graphics.getClip();
693 graphics.clip(shape);
694 graphics.clip(new Rectangle2D.Double(x,y,width,0.4*height));
695 graphics.setColor(COLOR_OVERLAY);
696 graphics.fill(shape);
697 graphics.setClip(clip);
698 }
699 }
700
701 private static boolean useGradientStyle( final Graphics2D graphics ) {
702 return YRenderingHints.isGradientPaintingEnabled(graphics);
703 }
704
705 private static boolean useSelectionStyle(final NodeRealizer context, final Graphics2D graphics) {
706 return context.isSelected() &&
707 YRenderingHints.isSelectionPaintingEnabled(graphics);
708 }
709
710 private static Employee getEmployee( final NodeRealizer context ) {
711 final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
712 return (Employee) gnr.getUserData();
713 }
714 }
715
716
719 static class CustomGroupNodeRealizer extends GroupNodeRealizer {
720 public CustomGroupNodeRealizer() {
721 super();
722 }
723 public CustomGroupNodeRealizer(final NodeRealizer nr) {
724 super(nr);
725 }
726 public NodeRealizer createCopy(final NodeRealizer nr) {
727 return new CustomGroupNodeRealizer(nr);
728 }
729 public boolean isSelected() {
730 return false;
731 }
732 }
733
734
737 public Overview createOverview() {
738 final Overview ov = super.createOverview();
739
740 ov.putClientProperty("Overview.PaintStyle", "Funky");
743 ov.putClientProperty("Overview.AllowZooming", Boolean.TRUE);
745 ov.putClientProperty("Overview.AllowKeyboardNavigation", Boolean.TRUE);
747 ov.putClientProperty("Overview.Inverse", Boolean.TRUE);
749 ov.setPreferredSize(new Dimension(200, 150));
750 ov.setMinimumSize(new Dimension(200, 150));
751 ov.getRenderingHints().put(LODRenderingHint.KEY_LOD, LODRenderingHint.VALUE_LOD_OVERVIEW);
752 return ov;
753 }
754
755 private void configureColors(final NodeRealizer nr, final boolean selected, final boolean highlighted) {
756 if(highlighted) {
757 if(selected) {
758 nr.setFillColor(SELECTED_HOVER_FILL_COLOR);
759 nr.setFillColor2(SELECTED_HOVER_FILL_COLOR2);
760 nr.setLineColor(SELECTED_HOVER_LINE_COLOR);
761 } else { nr.setFillColor(HOVER_FILL_COLOR);
763 nr.setFillColor2(HOVER_FILL_COLOR2);
764 nr.setLineColor(HOVER_LINE_COLOR);
765 }
766 } else { if(selected) {
768 nr.setFillColor(SELECTED_FILL_COLOR);
769 nr.setFillColor2(SELECTED_FILL_COLOR2);
770 nr.setLineColor(SELECTED_LINE_COLOR);
771 } else { nr.setFillColor(FILL_COLOR);
773 nr.setFillColor2(FILL_COLOR2);
774 nr.setLineColor(LINE_COLOR);
775 }
776 }
777 }
778
779
783 static class MiddleClickMagnifierViewMode extends ViewMode {
784 final MagnifierViewMode magnifierVM;
785 public MiddleClickMagnifierViewMode() {
786 magnifierVM = new MagnifierViewMode() {
787 public void mouseDraggedMiddle(final double x, final double y) {
788 mouseDraggedLeft(x, y);
789 }
790 protected Graph2DView createMagnifierView() {
791 final Graph2DView view = super.createMagnifierView();
792 view.getRenderingHints().put(LODRenderingHint.KEY_LOD, LODRenderingHint.VALUE_LOD_HIGH);
793 return view;
794 }
795 };
796 magnifierVM.setMouseWheelEnabled(false);
797 }
798
799 public void mousePressedMiddle(final double x, final double y) {
800 final double zoom = view.getZoom();
801 magnifierVM.setMagnifierZoomFactor(Math.max(1,1/zoom));
802 magnifierVM.setMagnifierRadius(200);
803 view.addViewMode(magnifierVM);
804 magnifierVM.mouseMoved(lastPressEvent);
805 view.updateView();
806 }
807
808 public void mouseReleasedMiddle(final double x, final double y) {
809 view.removeViewMode(magnifierVM);
810 }
811 }
812
813
814
817 private static class JOrgChartTooltipMode extends TooltipMode {
818
823 public void mouseMoved( final double x, final double y ) {
824 for (Iterator it = view.getDrawables().iterator(); it.hasNext();) {
825 final Object drawable = it.next();
826 if (drawable instanceof HoverButton) {
827 final String text = ((HoverButton) drawable).getToolTipText(x, y);
828 if (text != null) {
829 view.setToolTipText(text);
830 return;
831 }
832 }
833 }
834
835 super.mouseMoved(x, y);
836 }
837
838
848 protected String getNodeTip(final Node node) {
849 final Object lod = getLevelOfDetail();
850 if (lod == LODRenderingHint.VALUE_LOD_LOW ||
851 lod == LODRenderingHint.VALUE_LOD_MEDIUM) { if (getGraph2D().getHierarchyManager().isNormalNode(node)) {
853 final Employee e = getEmployee(node);
854 if (!e.vacant) {
855 return "<html><b>" + e.name + "</b><br>" + e.position + "<br>Status " + e.status + "</html>";
856 }
857 }
858 }
859 return null;
860 }
861
862
872 protected String getNodeLabelTip(final NodeLabel label) {
873 final Object lod = getLevelOfDetail();
874 if (lod == LODRenderingHint.VALUE_LOD_HIGH) {
875 final NodeRealizer realizer = label.getRealizer();
876 if (realizer.labelCount() > 6 && label == realizer.getLabel(6)) {
877 final Node node = label.getNode();
878 if (getGraph2D().getHierarchyManager().isNormalNode(node)) {
879 final Employee e = getEmployee(node);
880 return "Status " + e.status;
881 }
882 }
883 }
884 return null;
885 }
886
887
893 private Employee getEmployee( final Node node ) {
894 return (Employee) ((JTreeChart) view).getUserObject(node);
895 }
896
897 private Object getLevelOfDetail() {
898 return view.getRenderingHints().get(LODRenderingHint.KEY_LOD);
899 }
900 }
901
902
906 private class RollOverViewMode extends ViewMode {
907
908
909 private static final int PREFERRED_DURATION = 200;
910
911
912 private Node lastHitNode;
913 private AnimationPlayer player;
914 private PropertyChangeListener pcl;
915 private MouseEvent lastRelevantMouseEvent;
916
917 public void activate(final boolean activate) {
918 super.activate(activate);
919 if(activate) {
920 player = new AnimationPlayer();
921 player.addAnimationListener(view);
922 player.setBlocking(false);
923 pcl = new CanvasPropertyChangeListener();
924 view.getCanvasComponent().addPropertyChangeListener(pcl);
925 } else if(pcl != null){
926 view.getCanvasComponent().removePropertyChangeListener(pcl);
927 }
928 }
929
930 public void mouseExited(final MouseEvent e) {
931 lastRelevantMouseEvent = null;
932 if(lastHitNode != null) {
933 unmark(lastHitNode);
934 }
935 }
936
937 public void mouseDragged(final MouseEvent e) {
938 lastRelevantMouseEvent = e;
939 super.mouseDragged(e);
940 }
941
942 public void mouseMoved(final MouseEvent e) {
943 lastRelevantMouseEvent = e;
944 super.mouseMoved(e);
945 }
946
947
950 public void mouseMoved( final double x, final double y ) {
951 final HitInfo hi = getHitInfo(x, y);
952
953 if (hi.hasHitNodes()) {
954 final Node node = (Node) hi.hitNodes().current();
955 if (node != lastHitNode) {
956 unmark(lastHitNode);
957 }
958 final JOrgChart treeView = (JOrgChart) view;
959 final Object userObject = treeView.getUserObject(node);
960 if(userObject != null && !treeView.highlightMap.getBool(node)) {
961 mark(node);
962 lastHitNode = node;
963 }
964 } else {
965 unmark(lastHitNode);
966 lastHitNode = null;
967 }
968 }
969
970
973 protected HitInfo getHitInfo( final double x, final double y ) {
974 final HitInfo hi = DemoBase.checkNodeHit(view, x, y);
975 setLastHitInfo(hi);
976 return hi;
977 }
978
979
983 protected void mark( final Node node ) {
984 final JOrgChart treeView = (JOrgChart) view;
987 final boolean highlighted = treeView.highlightMap.getBool(node);
988 final Object userObject = treeView.getUserObject(node);
989
990 if(userObject != null && !highlighted) {
991 treeView.highlightMap.setBool(node, true);
992
993 final NodeRealizer nr = getGraph2D().getRealizer(node);
994 final NodeRealizer newTheme = nr.createCopy();
995 configureColors(newTheme, getGraph2D().isSelected(node), true);
996
997 final ViewAnimationFactory animFac = new ViewAnimationFactory(view);
998 final AnimationObject ao = animFac.color(
999 nr,
1000 newTheme.getFillColor(), newTheme.getFillColor2(), newTheme.getLineColor(),
1001 ViewAnimationFactory.APPLY_EFFECT, PREFERRED_DURATION);
1002
1003 final AnimationObject eao = AnimationFactory.createEasedAnimation(ao);
1004 player.animate(eao);
1005 }
1006 }
1007
1008 class CanvasPropertyChangeListener implements PropertyChangeListener {
1009 public void propertyChange(final PropertyChangeEvent evt) {
1010 if(lastRelevantMouseEvent != null && ("Zoom".equals(evt.getPropertyName()) || "ViewPoint".equals(evt.getPropertyName()))) {
1011 if(lastHitNode != null && getHitInfo(lastRelevantMouseEvent).getHitNode() != lastHitNode) {
1012 unmark(lastHitNode);
1013 lastHitNode = null;
1014 }
1015 else if(lastHitNode == null && lastRelevantMouseEvent != null) {
1016 lastHitNode = getHitInfo(lastRelevantMouseEvent).getHitNode();
1017 if(lastHitNode != null) {
1018 mark(lastHitNode);
1019 }
1020 }
1021 }
1022 }
1023 }
1024
1025
1029 protected void unmark( final Node node ) {
1030 if (node == null || node.getGraph() == null) {
1031 player.stop();
1032 return;
1033 }
1034 final JOrgChart treeView = (JOrgChart) view;
1035 Object userObject = null;
1036 try {
1037 userObject = treeView.getUserObject(node);
1038 }
1039 catch(Exception ex) {
1040 D.bug(node);
1041 }
1042 if(userObject != null && treeView.highlightMap.getBool(node)) {
1043 treeView.highlightMap.setBool(node, false);
1044
1045 player.stop();
1046 configureColors(getGraph2D().getRealizer(node), getGraph2D().isSelected(node), false);
1047 getGraph2D().updateViews();
1048 }
1049 }
1050 }
1051
1052
1056 class TreeChartSelectionListener implements Graph2DSelectionListener {
1057 public void onGraph2DSelectionEvent(final Graph2DSelectionEvent ev) {
1058 if(ev.getSubject() instanceof Node) {
1059 final Node node = (Node) ev.getSubject();
1060 final Object userObject = getUserObject(node);
1061 if(userObject != null) {
1062 final Graph2D graph = getGraph2D();
1063 configureColors(getGraph2D().getRealizer(node), graph.isSelected(node), highlightMap.getBool(node));
1064 graph.updateViews();
1065 }
1066 }
1067 }
1068 }
1069
1070
1074 protected Layouter createLayouter() {
1075 final OrgChartLayouter layouter = new OrgChartLayouter();
1076 final Graph2D graph = getGraph2D();
1077 final DataProvider childLayoutDP = new DataProviderAdapter() {
1078 public Object get(final Object n) {
1079 final Employee employee = (Employee) getUserObject((Node)n);
1080 if(employee != null) {
1081 if("leftHanging".equals(employee.layout)) {
1082 return OrgChartLayouter.CHILD_LAYOUT_LEFT_BELOW;
1083 }
1084 if("rightHanging".equals(employee.layout)) {
1085 return OrgChartLayouter.CHILD_LAYOUT_RIGHT_BELOW;
1086 }
1087 if("bothHanging".equals(employee.layout)) {
1088 return OrgChartLayouter.CHILD_LAYOUT_BELOW;
1089 }
1090 }
1091 return OrgChartLayouter.CHILD_LAYOUT_SAME_LAYER;
1092 }
1093 };
1094 graph.addDataProvider(OrgChartLayouter.CHILD_LAYOUT_DPKEY, childLayoutDP);
1095
1096 final DataProvider assistantDP = new DataProviderAdapter() {
1097 public boolean getBool(final Object n) {
1098 final Employee employee = (Employee) getUserObject((Node)n);
1099 return employee != null && employee.assistant;
1100 }
1101 };
1102 graph.addDataProvider(OrgChartLayouter.ASSISTANT_DPKEY, assistantDP);
1103
1104 layouter.setDuplicateBendsOnSharedBus(true);
1105
1106 return new NormalizingGraphElementOrderStage(layouter);
1107 }
1108}
1109