1
28 package demo.view.orgchart;
29
30 import demo.view.DemoDefaults;
31 import demo.view.orgchart.OrgChartTreeModel.Employee;
32 import org.xml.sax.InputSource;
33 import y.base.Node;
34 import y.io.SuffixFileFilter;
35 import y.view.Graph2D;
36 import y.view.Graph2DSelectionEvent;
37 import y.view.Graph2DSelectionListener;
38 import y.view.Overview;
39
40 import javax.swing.AbstractAction;
41 import javax.swing.Action;
42 import javax.swing.BorderFactory;
43 import javax.swing.Box;
44 import javax.swing.BoxLayout;
45 import javax.swing.ButtonGroup;
46 import javax.swing.DefaultCellEditor;
47 import javax.swing.Icon;
48 import javax.swing.JButton;
49 import javax.swing.JCheckBox;
50 import javax.swing.JComboBox;
51 import javax.swing.JComponent;
52 import javax.swing.JEditorPane;
53 import javax.swing.JFileChooser;
54 import javax.swing.JFrame;
55 import javax.swing.JLabel;
56 import javax.swing.JMenu;
57 import javax.swing.JMenuBar;
58 import javax.swing.JPanel;
59 import javax.swing.JRadioButton;
60 import javax.swing.JRootPane;
61 import javax.swing.JScrollPane;
62 import javax.swing.JSeparator;
63 import javax.swing.JSplitPane;
64 import javax.swing.JTable;
65 import javax.swing.JTree;
66 import javax.swing.SwingConstants;
67 import javax.swing.event.ChangeEvent;
68 import javax.swing.event.ChangeListener;
69 import javax.swing.event.TableModelEvent;
70 import javax.swing.event.TableModelListener;
71 import javax.swing.event.TreeSelectionEvent;
72 import javax.swing.event.TreeSelectionListener;
73 import javax.swing.table.DefaultTableModel;
74 import javax.swing.table.TableCellEditor;
75 import javax.swing.table.TableCellRenderer;
76 import javax.swing.table.TableModel;
77 import javax.swing.tree.DefaultTreeCellRenderer;
78 import javax.swing.tree.DefaultTreeModel;
79 import javax.swing.tree.DefaultTreeSelectionModel;
80 import javax.swing.tree.TreeModel;
81 import javax.swing.tree.TreeNode;
82 import javax.swing.tree.TreePath;
83 import javax.swing.tree.TreeSelectionModel;
84 import java.awt.BorderLayout;
85 import java.awt.Color;
86 import java.awt.Component;
87 import java.awt.Dimension;
88 import java.awt.EventQueue;
89 import java.awt.FlowLayout;
90 import java.awt.Font;
91 import java.awt.event.ActionEvent;
92 import java.io.File;
93 import java.io.FileInputStream;
94 import java.io.IOException;
95 import java.io.InputStream;
96 import java.net.URL;
97
98
124 public class OrgChartDemo {
125
126 private JOrgChart orgChart;
127 private JTable propertiesTable;
128 private JTree tree;
129 private String helpFile;
130
131 public OrgChartDemo() {
132 this(null);
133 }
134
135 public OrgChartDemo(final String helpFile) {
136 this.helpFile = helpFile;
137 }
138
139
142 public void addContentTo( final JRootPane rootPane ) {
143 final JPanel contentPane = new JPanel(new BorderLayout());
144
145 final OrgChartTreeModel model = readOrgChart(getResource("resources/orgchartmodel.xml"));
146 if (model != null) {
147 final Box leftPanel = new Box(BoxLayout.Y_AXIS);
148
149 orgChart = createOrgChart(model);
150 orgChart.setFitContentOnResize(true);
151
152 final Overview overview = orgChart.createOverview();
153 leftPanel.add(createTitledPanel(overview, "Overview"));
154
155 tree = createStructureView(model);
156 final JComponent viewOptions = createViewOptionsPanel();
157 leftPanel.add(viewOptions, BorderLayout.NORTH);
158 leftPanel.add(createTitledPanel(new JScrollPane(tree),"Structure View"));
159
160 propertiesTable = createPropertiesTable();
161 final JScrollPane scrollPane = new JScrollPane(propertiesTable);
162 scrollPane.setPreferredSize(new Dimension(200, 180));
163 leftPanel.add(createTitledPanel(scrollPane,"Properties"));
164
165 orgChart.getGraph2D().addGraph2DSelectionListener(new OrgChartSelectionUpdater());
167 tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionUpdater());
169
171 contentPane.setLayout(new BorderLayout());
172 final JSplitPane splitPane;
173 if (helpFile != null) {
174 contentPane.add(leftPanel, BorderLayout.WEST);
175 final JComponent helpPane = createHelpPane(getResource(helpFile));
176 helpPane.setMinimumSize(new Dimension(200, 10));
177
178 splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
179 createTitledPanel(orgChart, "Organization Chart"),
180 createTitledPanel(helpPane, "Help"));
181 splitPane.setOneTouchExpandable(true);
182
183 splitPane.setResizeWeight(1);
184
185 contentPane.add(splitPane, BorderLayout.CENTER);
186 } else {
187 final Box panel = new Box(BoxLayout.X_AXIS);
188 panel.add(leftPanel);
189 panel.add(new JSeparator(SwingConstants.VERTICAL));
190 contentPane.add(panel, BorderLayout.WEST);
191 contentPane.add(createTitledPanel(orgChart, "Organization Chart"), BorderLayout.CENTER);
192 }
193 } else {
194 contentPane.setPreferredSize(new Dimension(320, 24));
195 contentPane.add(new JLabel("Could not create Organization Chart.", JLabel.CENTER));
196 }
197
198 rootPane.setContentPane(contentPane);
199 final JMenuBar menu = new JMenuBar();
200 final JMenu file = new JMenu("File");
201 menu.add(file);
202 file.add(createLoadAction());
203 file.add(createSaveAction());
204 file.addSeparator();
205 file.add(createExitAction());
206 rootPane.setJMenuBar(menu);
207 }
208
209 private Action createExitAction() {
210 return new AbstractAction("Exit") {
211 public void actionPerformed(final ActionEvent e) {
212 System.exit(0);
213 }
214 };
215 }
216
217 private Action createSaveAction() {
218 return new AbstractAction("Save") {
219 public void actionPerformed(final ActionEvent e) {
220 final JFileChooser fileChooser = new JFileChooser();
221 fileChooser.setFileFilter(new SuffixFileFilter("xml", "XML File"));
222 fileChooser.setAcceptAllFileFilterUsed(false);
223 if (fileChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
224 final OrgChartTreeModel.OrgChartWriter writer = new OrgChartTreeModel.OrgChartWriter();
225 writer.write(fileChooser.getSelectedFile(),(Employee) orgChart.getTreeNode(orgChart.getRootNode()));
226 }
227 }
228 };
229 }
230
231 private Action createLoadAction() {
232 return new AbstractAction("Load") {
233 public void actionPerformed(final ActionEvent e) {
234 final JFileChooser fileChooser = new JFileChooser();
235 fileChooser.setDialogTitle("Open Org Chart");
236 fileChooser.setFileFilter(new SuffixFileFilter("xml","XML File"));
237 fileChooser.setAcceptAllFileFilterUsed(false);
238 if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
239 final OrgChartTreeModel orgChartTreeModel = readOrgChart(fileChooser.getSelectedFile());
240 orgChart.setModel(orgChartTreeModel);
241 orgChart.updateChart();
242 tree.setModel(orgChartTreeModel);
243 for (int i = 0; i < tree.getRowCount(); i++) {
244 tree.expandRow(i);
245 }
246 }
247 }
248 };
249 }
250
251
252 private URL getResource( final String name ) {
253 return demo.view.DemoBase.getResource(getClass(), name);
254 }
255
256
259 private void start() {
260 final JFrame frame = new JFrame("yFiles Organization Chart Demo");
261 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
262 frame.setIconImage(demo.view.DemoBase.getFrameIcon());
263 addContentTo(frame.getRootPane());
264 frame.pack();
265 frame.setVisible(true);
266 orgChart.requestFocus();
267 }
268
269
272 JComponent createHelpPane(final URL helpURL) {
273 try {
274 final JEditorPane editorPane = new JEditorPane(helpURL);
275 editorPane.setEditable(false);
276 editorPane.setPreferredSize(new Dimension(250, 250));
277 return new JScrollPane(editorPane);
278 } catch (IOException e) {
279 e.printStackTrace();
280 }
281 return null;
282 }
283
284
287 OrgChartTreeModel readOrgChart(final URL orgChartURL) {
288 OrgChartTreeModel model = null;
289 try {
290 final InputStream stream = orgChartURL.openStream();
291 try {
292 model = OrgChartTreeModel.create(new InputSource(stream));
293 } finally {
294 stream.close();
295 }
296 } catch(IOException ioException) {
297 System.err.println("Failed to read from " + orgChartURL);
298 ioException.printStackTrace();
299 }
300 return model;
301 }
302
303
306 OrgChartTreeModel readOrgChart(final File orgChartFile) {
307 OrgChartTreeModel model = null;
308 try {
309 final InputStream stream = new FileInputStream(orgChartFile);
310 try {
311 model = OrgChartTreeModel.create(new InputSource(stream));
312 } finally {
313 stream.close();
314 }
315 } catch(IOException ioException) {
316 System.err.println("Failed to read from " + orgChartFile.getAbsolutePath());
317 ioException.printStackTrace();
318 }
319 return model;
320 }
321
322
325 JOrgChart createOrgChart(final OrgChartTreeModel model) {
326 final JOrgChart orgChart = new JOrgChart(model);
327 orgChart.setPreferredSize(new Dimension(720, 750));
328 addGlassPaneComponents(orgChart);
329 return orgChart;
330 }
331
332
335 JTree createStructureView(final TreeModel model) {
336 final JTree tree = new JTree(model);
337 tree.setCellRenderer(new DefaultTreeCellRenderer() {
338 public Component getTreeCellRendererComponent(final JTree tree, Object value,final boolean sel,
339 final boolean expanded, final boolean leaf,final int row, final boolean hasFocus) {
340 if(value instanceof Employee) {
341 final Employee employee = (Employee)value;
342 value = employee.name;
343 }
344 return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
345 }
346 });
347
348 for(int i = 0; i < tree.getRowCount(); i++) {
349 tree.expandPath(tree.getPathForRow(i));
350 }
351
352 return tree;
353 }
354
355
358 JTable createPropertiesTable() {
359 final DefaultTableModel tm = new DefaultTableModel();
360 tm.addColumn("", new Object[]{"Name", "Position", "Phone", "Fax", "Email", "Business Unit", "Status","Assistant"});
361 tm.addColumn("", new Object[]{"", "", "", "", "" , "" , "",Boolean.FALSE});
362 return new JTable(tm) {
363
364 private final JComboBox statusBox = new JComboBox();
365 {
366 statusBox.addItem("unavailable");
367 statusBox.addItem("present");
368 statusBox.addItem("travel");
369 }
370
371 public boolean isCellEditable(final int row, final int column) {
372 return row != 5 && column == 1;
373 }
374 public TableCellRenderer getCellRenderer(final int row, final int column) {
375 if (row == 7 && column == 1) {
376 return getDefaultRenderer(Boolean.class);
377 } else {
378 return super.getCellRenderer(row, column);
379 }
380 }
381 public TableCellEditor getCellEditor(final int row, final int column) {
382 if (row == 6 && column == 1) {
383 return new DefaultCellEditor(statusBox);
384 } else if (row == 7 && column == 1) {
385 return getDefaultEditor(Boolean.class);
386 } else {
387 return super.getCellEditor(row,column);
388 }
389 }
390 };
391 }
392
393
396 void updatePropertiesTable(final Employee e) {
397 final DefaultTableModel tm = (DefaultTableModel) propertiesTable.getModel();
398 final TableModelListener[] tml = tm.getTableModelListeners();
399 for(int i = 0; i < tml.length-1; i++) {
400 tm.removeTableModelListener(tml[i]);
401 }
402 tm.setValueAt(e.name, 0, 1);
403 tm.setValueAt(e.position, 1, 1);
404 tm.setValueAt(e.phone, 2, 1);
405 tm.setValueAt(e.fax, 3, 1);
406 tm.setValueAt(e.email, 4, 1);
407 tm.setValueAt(e.businessUnit, 5, 1);
408 tm.setValueAt(e.status, 6, 1);
409 tm.setValueAt((e.assistant) ? Boolean.TRUE : Boolean.FALSE, 7, 1);
410 final boolean status = !e.vacant;
411 propertiesTable.setEnabled(status);
412 orgChart.updateView();
413 tm.addTableModelListener(new TableModelListener() {
414 public void tableChanged(final TableModelEvent event) {
415 final TableModel tableModel = (TableModel) event.getSource();
416 switch (event.getFirstRow()) {
417 case 0:
418 e.name = (String) tableModel.getValueAt(0, 1);
419 break;
420 case 1:
421 e.position = (String) tableModel.getValueAt(1, 1);
422 break;
423 case 2:
424 e.phone = (String) tableModel.getValueAt(2,1);
425 break;
426 case 3:
427 e.fax = (String) tableModel.getValueAt(3, 1);
428 break;
429 case 4:
430 e.email = (String) tableModel.getValueAt(4, 1);
431 break;
432 case 5:
433 e.businessUnit = (String) tableModel.getValueAt(5, 1);
434 break;
435 case 6:
436 e.status = (String) tableModel.getValueAt(6, 1);
437 break;
438 case 7:
439 e.assistant = ((Boolean) tableModel.getValueAt(7,1)).booleanValue();
440 orgChart.layoutGraph(true);
441 break;
442 }
443 orgChart.configureNodeRealizer(orgChart.getNodeForUserObject(e));
444 orgChart.getGraph2D().updateViews();
445 }
446 });
447 }
448
449
452 JPanel createViewOptionsPanel() {
453 final JPanel panel = new JPanel();
454 panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
455 final JRadioButton button1 = new JRadioButton(new AbstractAction("Global View") {
456 public void actionPerformed(final ActionEvent e) {
457 orgChart.showGlobalHierarchy();
458 }
459 });
460 button1.setSelected(true);
461
462 final JRadioButton button2 = new JRadioButton(new AbstractAction("Local View") {
463 public void actionPerformed(final ActionEvent e) {
464 orgChart.showLocalHierarchy(null);
465 }
466 });
467
468 final ButtonGroup bg = new ButtonGroup();
469 bg.add(button1);
470 bg.add(button2);
471 panel.add(button1);
472 panel.add(button2);
473
474 final JCheckBox checkBox = new JCheckBox(new AbstractAction("Show Colleagues") {
475 public void actionPerformed(final ActionEvent e) {
476 final boolean result = ((JCheckBox)e.getSource()).isSelected();
477 if(result != orgChart.isSiblingViewEnabled()) {
478 orgChart.setSiblingViewEnabled(result);
479 orgChart.showLocalHierarchy(null);
480 }
481 }
482 });
483 checkBox.setEnabled(false);
484 panel.add(checkBox);
485
486 final JCheckBox checkBox2 = new JCheckBox(new AbstractAction("Show Business Units") {
487 public void actionPerformed(final ActionEvent e) {
488 final boolean result = ((JCheckBox)e.getSource()).isSelected();
489 if(result != orgChart.isGroupViewEnabled()) {
490 orgChart.setGroupViewEnabled(result);
491 orgChart.updateChart();
492 }
493 }
494 });
495 panel.add(checkBox2);
496
497 button2.addChangeListener(new ChangeListener() {
498 public void stateChanged(final ChangeEvent e) {
499 checkBox.setEnabled(button2.isSelected());
500 }
501 });
502
503 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
504
505 return createTitledPanel(panel, "View Options");
506
507 }
508
509
512 private void addGlassPaneComponents(final JOrgChart orgChart ) {
513 final JPanel glassPane = orgChart.getGlassPane();
514 glassPane.setLayout(new BorderLayout());
515
516 final JPanel bar = new JPanel(new FlowLayout(FlowLayout.LEFT,5,0));
517 bar.setOpaque(false);
518 bar.setBorder(BorderFactory.createEmptyBorder(20,15,0,0));
519
520 final Action zoomIn = orgChart.createZoomInAction();
521 zoomIn.putValue(AbstractAction.SMALL_ICON, getIconResource("resource/zoomIn.png"));
522 zoomIn.putValue(AbstractAction.SHORT_DESCRIPTION, "Zoom into Chart");
523 bar.add(createButton(zoomIn));
524
525 final Action zoomOut = orgChart.createZoomOutAction();
526 zoomOut.putValue(AbstractAction.SMALL_ICON, getIconResource("resource/zoomOut.png"));
527 zoomOut.putValue(AbstractAction.SHORT_DESCRIPTION, "Zoom out of Chart");
528 bar.add(createButton(zoomOut));
529
530 final Action fitContent = orgChart.createFitContentAction();
531 fitContent.putValue(AbstractAction.SMALL_ICON, getIconResource("resource/zoomFit.png"));
532 fitContent.putValue(AbstractAction.SHORT_DESCRIPTION, "Fit Chart into View");
533 bar.add(createButton(fitContent));
534
535 glassPane.add(bar, BorderLayout.NORTH);
536 }
537
538 private Icon getIconResource( final String name ) {
539 return demo.view.DemoBase.getIconResource(name);
540 }
541
542
545 private JButton createButton(final Action action) {
546 final JButton button = new JButton(action);
547 button.setBackground(Color.WHITE);
548 return button;
549 }
550
551
552
555 class TreeSelectionUpdater implements TreeSelectionListener {
556 public void valueChanged(final TreeSelectionEvent e) {
557 final TreePath path = e.getPath();
558 final Employee employee = (Employee) path.getLastPathComponent();
559 Node node = orgChart.getNodeForUserObject(employee);
560
561 if(orgChart.isLocalViewEnabled() && (node == null || node.getGraph() == null)) {
562 orgChart.showLocalHierarchy(employee);
563 node = orgChart.getNodeForUserObject(employee);
564 }
565
566 if(node != null) {
567 if(e.isAddedPath()) {
568 final Graph2D graph2D = orgChart.getGraph2D();
569 if(!graph2D.isSelected(node)) {
570 graph2D.unselectAll();
571 graph2D.setSelected(node, e.isAddedPath());
572 orgChart.focusNode(node);
573 }
574 }
575 }
576 }
577 }
578
579
582 class OrgChartSelectionUpdater implements Graph2DSelectionListener {
583 public void onGraph2DSelectionEvent(final Graph2DSelectionEvent e) {
584 if(e.getSubject() instanceof Node) {
585 final Node node = (Node) e.getSubject();
586 final Employee p = (Employee) orgChart.getUserObject(node);
587 if(p != null) {
588 syncTreeSelection(node);
589 if(orgChart.getGraph2D().isSelected(node)) {
590 updatePropertiesTable(p);
591 }
592 }
593 }
594 }
595
596 void syncTreeSelection(final Node node) {
597
598 final DefaultTreeSelectionModel smodel = (DefaultTreeSelectionModel) tree.getSelectionModel();
599 smodel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
600
601 final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
602 final TreeNode treeNode = (TreeNode) orgChart.getTreeNode(node);
603 final TreeNode[] pathToRoot = model.getPathToRoot(treeNode);
604 final TreePath path = new TreePath(pathToRoot);
605
606 if(orgChart.getGraph2D().isSelected(node)) {
607 smodel.addSelectionPath(path);
608 } else {
609 smodel.removeSelectionPath(path);
610 }
611 tree.scrollPathToVisible(path);
612 }
613 }
614
615
618 public JPanel createTitledPanel(final JComponent content, final String title) {
619 final JPanel panel = new JPanel();
620 final JLabel label = new JLabel(title);
621 label.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
622 label.setBackground(new Color(240,240,240));
623 label.setOpaque(true);
624 label.setForeground(Color.DARK_GRAY);
625 label.setFont(label.getFont().deriveFont(Font.BOLD));
626 label.setFont(label.getFont().deriveFont(13.0f));
627 panel.setLayout(new BorderLayout());
628 panel.add(label, BorderLayout.NORTH);
629 panel.add(content, BorderLayout.CENTER);
630 return panel;
631 }
632
633
636 public static void main(final String[] args) {
637 EventQueue.invokeLater(new Runnable() {
638 public void run() {
639 DemoDefaults.initLnF();
640 (new OrgChartDemo("resources/orgcharthelp.html")).start();
641 }
642 });
643 }
644 }
645