1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package fr.ens.transcriptome.doelan.gui;
23
24 import java.awt.BorderLayout;
25 import java.awt.Component;
26 import java.awt.Container;
27 import java.awt.GridLayout;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.awt.event.KeyEvent;
31 import java.awt.event.MouseEvent;
32 import java.awt.event.MouseListener;
33 import java.util.ArrayList;
34 import java.util.HashSet;
35 import java.util.Set;
36
37 import javax.swing.AbstractAction;
38 import javax.swing.JButton;
39 import javax.swing.JDialog;
40 import javax.swing.JLabel;
41 import javax.swing.JOptionPane;
42 import javax.swing.JPanel;
43 import javax.swing.JPopupMenu;
44 import javax.swing.JScrollPane;
45 import javax.swing.JTable;
46 import javax.swing.SwingConstants;
47 import javax.swing.event.TableModelEvent;
48 import javax.swing.event.TableModelListener;
49 import javax.swing.table.JTableHeader;
50 import javax.swing.table.TableCellRenderer;
51 import javax.swing.table.TableColumn;
52 import javax.swing.table.TableColumnModel;
53 import javax.swing.table.TableModel;
54
55 import fr.ens.transcriptome.doelan.Core;
56 import fr.ens.transcriptome.doelan.Defaults;
57 import fr.ens.transcriptome.doelan.DoelanException;
58 import fr.ens.transcriptome.doelan.DoelanRegistery;
59 import fr.ens.transcriptome.doelan.algorithms.QualityTest;
60 import fr.ens.transcriptome.doelan.data.QualityTestSuiteURL;
61 import fr.ens.transcriptome.nividic.platform.PlatformException;
62 import fr.ens.transcriptome.nividic.platform.module.AboutModule;
63 import fr.ens.transcriptome.nividic.platform.module.Module;
64 import fr.ens.transcriptome.nividic.platform.module.ModuleLocation;
65 import fr.ens.transcriptome.nividic.platform.module.ModuleManager;
66 import fr.ens.transcriptome.nividic.platform.module.ModuleQuery;
67 import fr.ens.transcriptome.nividic.platform.workflow.Algorithm;
68 import fr.ens.transcriptome.nividic.platform.workflow.WorkflowElement;
69 import fr.ens.transcriptome.nividic.util.SystemUtils;
70 import fr.ens.transcriptome.nividic.util.gui.AboutModuleWidget;
71 import fr.ens.transcriptome.nividic.util.gui.BrowserWidget;
72 import fr.ens.transcriptome.nividic.util.gui.ExternalBrowserLinkListener;
73
74 /***
75 * @author Laurent Jourdren
76 * @author Christian Kaufhold swing@chka.de
77 */
78 public class TestSuitePanel extends JPanel implements TableModelListener {
79
80
81
82
83 private QualityTestSuiteTableModel model;
84 private JTable table;
85 private QualityTestSuiteURL url;
86 private JButton saveButton = new JButton("Save Test suite");
87 private JButton startButton = new JButton("Start Test suite");
88 private static final String tableTipText = "Right click or double click to modify the test suite.";
89 private JLabel label = new JLabel(tableTipText, SwingConstants.RIGHT);
90
91 private static final int DOCUMENTATION_DIALOG_WIDTH = 700;
92 private static final int DOCUMENTATION_DIALOG_HEIGHT = 500;
93
94 private void saveTestSuite() {
95
96 int response = JOptionPane.showConfirmDialog(table,
97 new String[] {"Save changes ?"}, "Save", JOptionPane.YES_NO_OPTION,
98 JOptionPane.WARNING_MESSAGE);
99
100 if (response == JOptionPane.YES_OPTION) {
101
102 try {
103 Core.getCore().saveWorkflow(getUrl());
104 } catch (DoelanException e2) {
105 JOptionPane.showMessageDialog(table, "Error while writing the file : "
106 + e2.getMessage());
107 }
108
109 }
110 }
111
112 private ModuleLocation[] getAvailableModules() {
113
114 ModuleLocation[] modules = model.getAvailableModules();
115
116 Set instanciedModules = new HashSet();
117
118 WorkflowElement[] elements = model.getWorkflow().getElements();
119
120 for (int i = 0; i < elements.length; i++) {
121
122 Algorithm algo = elements[i].getAlgorithm();
123
124 if (algo != null && algo instanceof QualityTest && algo instanceof Module)
125 instanciedModules.add(algo.getClass().getName());
126
127 }
128
129 ArrayList availableModules = new ArrayList();
130
131 for (int i = 0; i < modules.length; i++) {
132
133 Module m = ModuleManager.getManager().loadModule(modules[i]);
134
135 if (m instanceof QualityTest) {
136 QualityTest qt = (QualityTest) m;
137
138 if (qt.isAddable()
139 && qt.isShowable()
140 && (qt.isUniqueInstance() ? !instanciedModules.contains(qt
141 .getClass().getName()) : true))
142 availableModules.add(modules[i]);
143
144 }
145 }
146
147 ModuleLocation[] result = new ModuleLocation[availableModules.size()];
148 for (int i = 0; i < availableModules.size(); i++) {
149 result[i] = (ModuleLocation) availableModules.get(i);
150 }
151
152 return result;
153 }
154
155 /***
156 * This class is used to handle mouse events on a TableWidgetObject.
157 * @author Laurent Jourdren
158 */
159 class JTableButtonMouseListener implements MouseListener {
160
161 private JTable table;
162 private EditParametersWidget editParameter;
163 private NewWorkflowElementWidget addAlgo;
164 final QualityTestSuiteTableModel ts = model;
165
166 private void forwardEventToButton(final MouseEvent e) {
167
168 if (DoelanRegistery.isAppletMode()
169 || (e.getButton() != MouseEvent.BUTTON3 && !(e.getClickCount() == 2 && e
170 .getButton() == MouseEvent.BUTTON1)))
171
172 return;
173
174 final TableColumnModel columnModel = this.table.getColumnModel();
175 final int column = columnModel.getColumnIndexAtX(e.getX());
176 final int row = e.getY() / this.table.getRowHeight();
177
178
179
180 if (row >= this.table.getRowCount() || row < 0
181 || column >= this.table.getColumnCount() || column < 0)
182 return;
183
184 final QualityTest t;
185
186 t = (QualityTest) model.getAlgorithmAt(row);
187
188 final int posX = e.getX();
189 final int posY = e.getY();
190
191 final JPopupMenu menu = new JPopupMenu();
192
193
194 AbstractAction modifyAction = new AbstractAction("Modify the parameters") {
195 public void actionPerformed(final ActionEvent e) {
196 if (editParameter != null) {
197 editParameter.close();
198 }
199 editParameter = new EditParametersWidget(t);
200 editParameter.setLocation(posX, posY);
201
202 editParameter.edit();
203 }
204 };
205
206 menu.add(modifyAction);
207 if (!t.isModifiable())
208 modifyAction.setEnabled(false);
209
210 menu.addSeparator();
211
212
213 menu.add(new AbstractAction("Add a test") {
214 public void actionPerformed(final ActionEvent e) {
215 if (addAlgo != null) {
216 addAlgo.close();
217 }
218 addAlgo = new NewWorkflowElementWidget(getAvailableModules());
219 addAlgo.setLocation(posX, posY);
220 addAlgo.setTitle("Add a new test");
221 addAlgo.setModal(true);
222 addAlgo.show();
223
224 if (addAlgo.isOk()) {
225
226 if (addAlgo.getIdentifier() == null
227 || "".equals(addAlgo.getIdentifier())
228 || ts.getWorkflow().contains(addAlgo.getIdentifier())) {
229 JOptionPane.showMessageDialog(table, "Invalid dentifier");
230 } else {
231 WorkflowElement wfe = ts.getWorkflowElementAt(row);
232 WorkflowElement newWfe = new WorkflowElement(addAlgo
233 .getIdentifier());
234 newWfe.setModuleQuery(new ModuleQuery(addAlgo
235 .getModuleLocationSelected()));
236 try {
237
238 ts.getWorkflow().insertAfter(wfe, newWfe);
239 ts.getWorkflow().activate();
240
241 } catch (PlatformException e1) {
242 JOptionPane.showMessageDialog(table,
243 "Error while adding the new element: " + e1.getMessage());
244 e1.printStackTrace();
245
246 }
247
248 }
249
250 }
251
252 }
253 });
254
255
256 AbstractAction removeAction = new AbstractAction("Remove this test") {
257 public void actionPerformed(final ActionEvent e) {
258 final int response = JOptionPane.showConfirmDialog(table,
259 "Remove this test ?");
260
261 if (response == JOptionPane.YES_OPTION) {
262 WorkflowElement wfe = ts.getWorkflowElementAt(row);
263 if (wfe != null)
264 try {
265 ts.getWorkflow().removeElementAndJoinPreviousAndNextElements(
266 wfe);
267 } catch (PlatformException e1) {
268 JOptionPane.showMessageDialog(table, e1.getMessage());
269 }
270 }
271
272 }
273 };
274
275 menu.add(removeAction);
276 if (!t.isDeletable())
277 removeAction.setEnabled(false);
278
279
280
281
282
283
284
285 menu.addSeparator();
286
287 AbstractAction documentationAction = new AbstractAction(
288 "Test documentation") {
289
290 public void actionPerformed(final ActionEvent e) {
291
292 WorkflowElement wfe = ts.getWorkflowElementAt(row);
293 Algorithm a = wfe.getAlgorithm();
294
295 if (a instanceof Module) {
296
297 AboutModule am = ((Module) a).aboutModule();
298
299 final JDialog dialog = new JDialog();
300 dialog.setTitle(am.getName() + " documentation");
301
302 String doc;
303 if (am.getHTMLDocumentation() == null) {
304 StringBuffer sb = new StringBuffer();
305 sb.append("<html><body>");
306 sb.append("<h1>Information</h1>");
307 sb.append("<p>No documentation is available for this module</p>");
308
309 if (am.getWebsite() != null) {
310 sb
311 .append("<p>Perhaps more information is available on the <a href=\"");
312 sb.append(am.getWebsite());
313 sb.append("\">website</a> of the test.</p>");
314 }
315
316 sb.append("<br><hr><a href='");
317 sb.append(DoelanRegistery.getAppURL());
318 sb.append("'>");
319 sb.append(Defaults.APP_NAME);
320 sb.append("</a> ");
321 sb.append(DoelanRegistery.getAppVersion());
322 sb.append(", Copyright " + DoelanRegistery.getCopyrightDate()
323 + " " + "<a href=\"" + DoelanRegistery.getOrganizationURL()
324 + "\">" + DoelanRegistery.getOrganizationName() + "</a>.\n");
325 sb.append("<!-- PRINT COMMAND HERE -->");
326 sb.append("</body></html>");
327
328 doc = sb.toString();
329
330 } else
331 doc = am.getHTMLDocumentation();
332
333 final Container pane = dialog.getContentPane();
334 pane.setLayout(new BorderLayout());
335
336 BrowserWidget browser = new BrowserWidget(doc);
337
338 browser.setHyperLinkListener(new ExternalBrowserLinkListener());
339
340 JScrollPane jsp = new JScrollPane(browser.getComponent());
341 jsp
342 .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
343 pane.add(jsp, BorderLayout.CENTER);
344
345 JButton closeButton = new JButton("Close");
346 closeButton.addActionListener(new ActionListener() {
347
348 public void actionPerformed(final ActionEvent e) {
349 dialog.setVisible(false);
350 }
351 });
352
353 pane.add(closeButton, BorderLayout.SOUTH);
354
355 dialog.setSize(DOCUMENTATION_DIALOG_WIDTH,
356 DOCUMENTATION_DIALOG_HEIGHT);
357 dialog.setModal(true);
358 dialog.setVisible(true);
359
360 } else
361 JOptionPane.showMessageDialog(table, "This test is not a module");
362
363 }
364
365 };
366
367 menu.add(documentationAction);
368
369 AbstractAction aboutAction = new AbstractAction("About test") {
370
371 public void actionPerformed(final ActionEvent e) {
372
373 WorkflowElement wfe = ts.getWorkflowElementAt(row);
374 Algorithm a = wfe.getAlgorithm();
375
376 if (a instanceof Module) {
377
378 AboutModule am = ((Module) a).aboutModule();
379
380 final JDialog dialog = new JDialog();
381 dialog.setTitle("About " + am.getName());
382
383 Container infoPanel = dialog.getContentPane();
384
385 infoPanel.setLayout(new BorderLayout());
386 infoPanel.add(new AboutModuleWidget(am), BorderLayout.CENTER);
387
388 JButton closeButton = new JButton("Close");
389 infoPanel.add(closeButton, BorderLayout.SOUTH);
390 closeButton.addActionListener(new ActionListener() {
391
392 public void actionPerformed(final ActionEvent e) {
393 dialog.setVisible(false);
394 }
395 });
396
397 dialog.pack();
398 dialog.setModal(true);
399 dialog.setResizable(true);
400 dialog.setVisible(true);
401
402 } else
403 JOptionPane.showMessageDialog(table, "This test is not a module");
404
405 }
406
407 };
408
409 menu.add(aboutAction);
410
411 menu.show(table.getComponentAt(e.getX(), e.getY()), e.getX(), e.getY());
412
413 }
414
415 public JTableButtonMouseListener(final JTable table) {
416 this.table = table;
417 }
418
419 public void mouseClicked(final MouseEvent e) {
420 forwardEventToButton(e);
421 }
422
423 public void mouseEntered(final MouseEvent e) {
424
425 }
426
427 public void mouseExited(final MouseEvent e) {
428
429 }
430
431 public void mousePressed(final MouseEvent e) {
432
433 }
434
435 public void mouseReleased(final MouseEvent e) {
436
437 }
438
439 }
440
441
442
443
444
445 /***
446 * Get the url of the test suite
447 * @return Returns the url
448 */
449 public QualityTestSuiteURL getUrl() {
450 return url;
451 }
452
453
454
455
456
457 /***
458 * Set the url of the test suite
459 * @param url The url to set
460 */
461 public void setUrl(final QualityTestSuiteURL url) {
462 this.url = url;
463 }
464
465 /***
466 * Enable the start button.
467 * @param enable true if the start button must be enabled
468 */
469 public void setStartButtonEnable(final boolean enable) {
470 this.startButton.setEnabled(enable);
471 }
472
473
474
475
476
477 /***
478 * Clear the result column.
479 */
480 public void clearResults() {
481 if (getModel() == null)
482 return;
483 getModel().clearResults();
484
485 int size = getModel().getRowCount();
486 for (int i = 0; i < size; i++) {
487 getModel().fireTableCellUpdated(i, 3);
488 getModel().fireTableCellUpdated(i, 2);
489 }
490 }
491
492
493
494
495
496 /***
497 * Public constructor.
498 */
499 public TestSuitePanel() {
500 super();
501
502 this.saveButton.setToolTipText(tableTipText);
503 this.startButton.setToolTipText(tableTipText);
504
505 if (!SystemUtils.isMacOsX()) {
506 this.saveButton.setMnemonic(KeyEvent.VK_V);
507 this.startButton.setMnemonic(KeyEvent.VK_S);
508 }
509
510
511 setLayout(new BorderLayout());
512 this.model = new QualityTestSuiteTableModel();
513
514 this.model.addTableModelListener(this);
515
516 this.table = new JTable(model) {
517
518
519 public String getToolTipText(MouseEvent e) {
520 java.awt.Point p = e.getPoint();
521 int rowIndex = rowAtPoint(p);
522 int colIndex = columnAtPoint(p);
523 int realColumnIndex = convertColumnIndexToModel(colIndex);
524
525 if (realColumnIndex == 1) {
526
527 QualityTestSuiteTableModel model = (QualityTestSuiteTableModel) getModel();
528
529 return model.getTip(rowIndex);
530 }
531
532 return null;
533 }
534 };
535 this.table
536 .setToolTipText("Right click or double click to modify the test suite.");
537 this.table.addMouseListener(new JTableButtonMouseListener(this.table));
538 JScrollPane sPane = new JScrollPane(this.table);
539
540
541 add(sPane, BorderLayout.CENTER);
542 JPanel southPanel = new JPanel(new BorderLayout());
543 JPanel buttonsPanel = new JPanel();
544
545 if (!DoelanRegistery.isAppletMode()) {
546
547 buttonsPanel.add(startButton);
548 startButton.addActionListener(new ActionListener() {
549
550 public void actionPerformed(ActionEvent e) {
551 Core.getCore().getMainTab().start();
552 }
553
554 });
555
556 saveButton.setEnabled(false);
557 saveButton.addActionListener(new ActionListener() {
558
559 public void actionPerformed(ActionEvent e) {
560 saveTestSuite();
561 }
562
563 });
564
565 buttonsPanel.add(saveButton);
566
567 }
568
569 southPanel.add(buttonsPanel, BorderLayout.WEST);
570 southPanel.add(label, BorderLayout.EAST);
571
572 add(southPanel, BorderLayout.SOUTH);
573
574 if (!DoelanRegistery.isAppletMode())
575 sPane.addMouseListener(new MouseListener() {
576
577
578 private NewWorkflowElementWidget addAlgo;
579 final QualityTestSuiteTableModel ts = model;
580
581 private void forwardEventToButton(final MouseEvent e) {
582
583 if (ts.getWorkflow() == null) {
584 JOptionPane.showMessageDialog(table,
585 "You must create or load a test suite");
586 return;
587 }
588 if (model.getRowCount() != 0)
589 return;
590
591 final JPopupMenu menu = new JPopupMenu();
592 final int posX = e.getX();
593 final int posY = e.getY();
594
595 menu.add(new AbstractAction("Add a test") {
596 public void actionPerformed(final ActionEvent e) {
597
598 menu.setVisible(false);
599 if (addAlgo != null) {
600 addAlgo.close();
601 }
602
603 addAlgo = new NewWorkflowElementWidget(getAvailableModules());
604 addAlgo.setTitle("Add a new test");
605 addAlgo.setModal(true);
606 addAlgo.setLocation(posX, posY);
607 addAlgo.show();
608
609 if (addAlgo.isOk()) {
610
611 if (addAlgo.getIdentifier() == null
612 || "".equals(addAlgo.getIdentifier())
613 || ts.getWorkflow().contains(addAlgo.getIdentifier())) {
614 JOptionPane.showMessageDialog(table, "Invalid dentifier");
615 } else {
616 WorkflowElement wfe = ts.getWorkflow().getElement(
617 Core.LOAD_ALGORITHM);
618 if (wfe == null) {
619 JOptionPane.showMessageDialog(table,
620 "Can't find load data algorithm");
621 return;
622 }
623
624 WorkflowElement newWfe = new WorkflowElement(addAlgo
625 .getIdentifier());
626 newWfe.setModuleQuery(new ModuleQuery(addAlgo
627 .getModuleLocationSelected()));
628 try {
629
630 ts.getWorkflow().insertAfter(wfe, newWfe);
631 ts.getWorkflow().activate();
632
633 } catch (PlatformException e1) {
634 JOptionPane.showMessageDialog(table,
635 "Error while adding the new element: "
636 + e1.getMessage());
637 }
638
639 }
640 }
641 }
642 });
643 menu.show(table, posX, posY);
644 }
645
646 public void mouseClicked(final MouseEvent e) {
647 forwardEventToButton(e);
648 }
649
650 public void mouseEntered(final MouseEvent e) {
651
652 }
653
654 public void mouseExited(final MouseEvent e) {
655
656 }
657
658 public void mousePressed(final MouseEvent e) {
659
660 }
661
662 public void mouseReleased(final MouseEvent e) {
663
664 }
665
666 });
667
668 }
669
670 /***
671 * Calculate the number of column to display.
672 * @param table Table object
673 */
674 public static void calcColumnWidths(final JTable table) {
675
676 JTableHeader header = table.getTableHeader();
677
678 TableCellRenderer defaultHeaderRenderer = null;
679
680 if (header != null)
681 defaultHeaderRenderer = header.getDefaultRenderer();
682
683 TableColumnModel columns = table.getColumnModel();
684 TableModel data = table.getModel();
685
686 int margin = columns.getColumnMargin();
687
688
689 int rowCount = data.getRowCount();
690
691 int totalWidth = 0;
692
693 for (int i = columns.getColumnCount() - 1; i >= 0; --i) {
694 TableColumn column = columns.getColumn(i);
695
696 int columnIndex = column.getModelIndex();
697
698 int width = -1;
699
700 TableCellRenderer h = column.getHeaderRenderer();
701
702 if (h == null)
703 h = defaultHeaderRenderer;
704
705
706 if (h != null) {
707 Component c = h.getTableCellRendererComponent(table, column
708 .getHeaderValue(), false, false, -1, i);
709
710 width = c.getPreferredSize().width;
711 }
712
713 for (int row = rowCount - 1; row >= 0; --row) {
714 TableCellRenderer r = table.getCellRenderer(row, i);
715
716 Component c = r.getTableCellRendererComponent(table, data.getValueAt(
717 row, columnIndex), false, false, row, i);
718
719 width = Math.max(width, c.getPreferredSize().width);
720 }
721
722 if (width >= 0)
723 column.setPreferredWidth(width + margin);
724
725
726
727
728
729 totalWidth += column.getPreferredWidth();
730 }
731
732
733
734
735
736
737
738
739
740
741
742
743
744 }
745
746 /***
747 * Get the model of the table
748 * @return Returns the model
749 */
750 public QualityTestSuiteTableModel getModel() {
751 return model;
752 }
753
754 /***
755 * This method is call when the table has been changed.
756 * @param e the event
757 */
758 public void tableChanged(final TableModelEvent e) {
759 calcColumnWidths(this.table);
760 if (getModel().getRowCount() == 0)
761 this.saveButton.setEnabled(false);
762 else
763 this.saveButton.setEnabled(true);
764 }
765
766 }