$darkmode
DENOPTIM
CuttingRulesSelectionDialog.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2022 Marco Foscato <marco.foscato@uib.no>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package denoptim.gui;
20
21import java.awt.BorderLayout;
22import java.awt.Color;
23import java.awt.Component;
24import java.awt.Cursor;
25import java.awt.Desktop;
26import java.awt.Dimension;
27import java.awt.FlowLayout;
28import java.awt.event.ActionEvent;
29import java.awt.event.ActionListener;
30import java.awt.event.FocusEvent;
31import java.awt.event.FocusListener;
32import java.awt.event.InputEvent;
33import java.awt.event.MouseAdapter;
34import java.awt.event.MouseEvent;
35import java.io.File;
36import java.io.IOException;
37import java.net.URI;
38import java.net.URISyntaxException;
39import java.util.ArrayList;
40import java.util.Arrays;
41import java.util.List;
42import java.util.Vector;
43
44import javax.swing.BoxLayout;
45import javax.swing.ButtonGroup;
46import javax.swing.JButton;
47import javax.swing.JComponent;
48import javax.swing.JLabel;
49import javax.swing.JOptionPane;
50import javax.swing.JPanel;
51import javax.swing.JRadioButton;
52import javax.swing.JScrollPane;
53import javax.swing.JSeparator;
54import javax.swing.JSplitPane;
55import javax.swing.JTable;
56import javax.swing.JTextField;
57import javax.swing.UIManager;
58import javax.swing.table.DefaultTableModel;
59
60import org.apache.batik.swing.JSVGCanvas;
61import org.apache.batik.swing.gvt.AbstractImageZoomInteractor;
62import org.apache.batik.swing.gvt.AbstractPanInteractor;
63import org.apache.batik.swing.gvt.AbstractResetTransformInteractor;
64
65import denoptim.exception.DENOPTIMException;
66import denoptim.files.FileAndFormat;
67import denoptim.files.FileFormat;
68import denoptim.files.FileUtils;
69import denoptim.io.DenoptimIO;
70import denoptim.programs.fragmenter.CuttingRule;
71import denoptim.programs.fragmenter.FragmenterParameters;
72import denoptim.utils.GeneralUtils;
73
74
75
85{
86
90 private static final long serialVersionUID = 1L;
91
96 protected JPanel centralPanel = new JPanel(new BorderLayout());
97
98 private JRadioButton rdbUseDefault;
99 private JRadioButton rdbUseCustom;
100
101 private DefaultTableModel defaultRulesTabModel;
102 private DefaultTableModel customRulesTabModel;
103
107 protected File lastUsedCutRulFile = null;
108
112 private File nextWrittenCutRulFile = null;
113
117 protected final int preferredHeight =
118 (int) (new JTextField()).getPreferredSize().getHeight();
119
123 protected final Dimension strFieldSize = new Dimension(200, preferredHeight);
124
128 protected JTextField txtLinearity;
129
133 protected List<CuttingRule> chosenOnes;
134
139
140
141//-----------------------------------------------------------------------------
142
147 public CuttingRulesSelectionDialog(List<CuttingRule> defaultCuttingRules,
148 List<CuttingRule> customCuttingRules, boolean preselectDefault,
149 Component refForPlacement, FragmenterParameters settings)
150 {
151 super(refForPlacement);
152 this.frgParams = settings;
153 setTitle("Choose Cutting Rules");
154
155 rdbUseDefault = new JRadioButton("Use default cutting rules.");
156 rdbUseCustom = new JRadioButton(
157 "Use the following curtomized cutting rules.");
158
159 if (preselectDefault)
160 {
161 rdbUseDefault.setSelected(true);
162 rdbUseCustom.setSelected(false);
163 } else {
164 rdbUseDefault.setSelected(false);
165 rdbUseCustom.setSelected(true);
166 }
167 ButtonGroup rdbGroup = new ButtonGroup();
168 rdbGroup.add(rdbUseDefault);
169 rdbGroup.add(rdbUseCustom);
170
171 defaultRulesTabModel = new DefaultTableModel();
172 defaultRulesTabModel.setColumnCount(7);
173 String column_names[]= {"<html><b>Rule Name</b></html>",
174 "<html><b>Order of Use</b></html>",
175 "<html><b>SMARTS Atom 1</b></html>",
176 "<html><b>SMARTS Bond 1-2</b></html>",
177 "<html><b>SMARTS Atom 2</b></html>",
178 "<html><b>Options</b></html>"};
179 defaultRulesTabModel.setColumnIdentifiers(column_names);
180 JTable defaultRulesTable = new JTable(defaultRulesTabModel);
181 try
182 {
184 } catch (DENOPTIMException e2)
185 {
186 e2.printStackTrace();
187 nextWrittenCutRulFile = new File("edited_cuttingrules");
188 }
189 defaultRulesTable.setToolTipText("<html>"
190 + "Double click to edit any entry. <br>"
191 + "Edited lists are saved in '"
192 + nextWrittenCutRulFile.getAbsolutePath() + "'</html>");
193 defaultRulesTable.putClientProperty("terminateEditOnFocusLost",
194 Boolean.TRUE);
195 defaultRulesTable.addFocusListener(new FocusListener() {
196
197 @Override
198 public void focusGained(FocusEvent e)
199 {
200 rdbUseDefault.setSelected(true);
201 }
202
203 @Override
204 public void focusLost(FocusEvent e) {}
205 });
206 for (CuttingRule cr : defaultCuttingRules)
207 {
208 String[] values = new String[6];
209 values[0] = cr.getName();
210 values[1] = String.valueOf(cr.getPriority());
211 values[2] = cr.getSMARTSAtom0();
212 values[3] = cr.getSMARTSBnd();
213 values[4] = cr.getSMARTSAtom1();
214 StringBuilder sb = new StringBuilder();
215 cr.getOptions().stream().forEach(s -> sb.append(" " + s));
216 values[5] = sb.toString();
217 defaultRulesTabModel.addRow(values);
218 }
219 JScrollPane defaultRulesScrollPane = new JScrollPane(defaultRulesTable);
220 defaultRulesTable.getTableHeader().setPreferredSize(
221 new Dimension(defaultRulesScrollPane.getWidth(), 40));
222
223 String[] emptyRow = new String[] {
224 "double click to edit...","","","","",""};
225
226 JButton btnAddDefaultRule = new JButton("Add Rule");
227 btnAddDefaultRule.addActionListener(new ActionListener() {
228
229 @Override
230 public void actionPerformed(ActionEvent e)
231 {
232 defaultRulesTabModel.addRow(emptyRow);
233 }
234 });
235 JButton btnRemoveDefaultRule = new JButton("Remove Selected");
236 btnRemoveDefaultRule.addActionListener(new ActionListener() {
237
238 @Override
239 public void actionPerformed(ActionEvent e)
240 {
241 if (defaultRulesTable.getRowCount() > 0)
242 {
243 if (defaultRulesTable.getSelectedRowCount() > 0)
244 {
245 int selectedRowIds[] =
246 defaultRulesTable.getSelectedRows();
247 Arrays.sort(selectedRowIds);
248 for (int i=(selectedRowIds.length-1); i>-1; i--)
249 {
250 defaultRulesTabModel.removeRow(
251 selectedRowIds[i]);
252 }
253 }
254 }
255 }
256 });
257 JButton btnViewSelectedDefaultRule = new SMARTSVisualizationButton(
258 defaultRulesTable, defaultRulesTabModel);
259
260 customRulesTabModel = new DefaultTableModel();
261 customRulesTabModel.setColumnCount(6);
262 customRulesTabModel.setColumnIdentifiers(column_names);
263 @SuppressWarnings("serial")
264 JTable customRulesTable = new JTable(customRulesTabModel) {
265 @Override
266 public Dimension getPreferredScrollableViewportSize() {
267 return new Dimension(super.getPreferredSize().width,
268 getRowHeight() * getRowCount());
269 }
270 };;
271 customRulesTable.setToolTipText("<html>"
272 + "Double click to edit any entry. <br>"
273 + "Edited lists are saved in '"
274 + nextWrittenCutRulFile.getAbsolutePath() + "'</html>");
275 customRulesTable.putClientProperty("terminateEditOnFocusLost",
276 Boolean.TRUE);
277 customRulesTable.addFocusListener(new FocusListener() {
278
279 @Override
280 public void focusGained(FocusEvent e)
281 {
282 rdbUseCustom.setSelected(true);
283 }
284
285 @Override
286 public void focusLost(FocusEvent e) {}
287 });
288 buildCustomRulesTable(customCuttingRules, emptyRow);
289
290 JButton btnAddCustomRule = new JButton("Add Rule");
291 btnAddCustomRule.addActionListener(new ActionListener() {
292
293 @Override
294 public void actionPerformed(ActionEvent e)
295 {
296 customRulesTabModel.addRow(emptyRow);
297 }
298 });
299 JButton btnRemoveCustomRule = new JButton("Remove Selected");
300 btnRemoveCustomRule.addActionListener(new ActionListener() {
301
302 @Override
303 public void actionPerformed(ActionEvent e)
304 {
305 if (customRulesTable.getRowCount() > 0)
306 {
307 if (customRulesTable.getSelectedRowCount() > 0)
308 {
309 int selectedRowIds[] =
310 customRulesTable.getSelectedRows();
311 Arrays.sort(selectedRowIds);
312 for (int i=(selectedRowIds.length-1); i>-1; i--)
313 {
314 customRulesTabModel.removeRow(
315 selectedRowIds[i]);
316 }
317 }
318 }
319 }
320 });
321 JButton btnViewSelectedCustomRule = new SMARTSVisualizationButton(
322 customRulesTable, customRulesTabModel);
323 JButton btnImportRules = new JButton("Import Rules...");
324 btnImportRules.addActionListener(new ActionListener() {
325
326 @Override
327 public void actionPerformed(ActionEvent e)
328 {
329 customCuttingRules.clear();
330 File cutRulFile = GUIFileOpener.pickFile(btnImportRules);
331 try
332 {
333 DenoptimIO.readCuttingRules(cutRulFile, customCuttingRules);
334 lastUsedCutRulFile = cutRulFile;
335 } catch (DENOPTIMException e1)
336 {
337 JOptionPane.showMessageDialog(btnImportRules,String.format(
338 "<html><body width='%1s'"
339 + "Could not read cutting rules from '"
340 + cutRulFile.getAbsolutePath() + "'. Hint: "
341 + e1.getMessage() + "</html>", 400),
342 "Error",
343 JOptionPane.ERROR_MESSAGE,
344 UIManager.getIcon("OptionPane.errorIcon"));
345 return;
346 }
347 buildCustomRulesTable(customCuttingRules, emptyRow);
348 rdbUseCustom.setSelected(true);
349 pack();
350 }
351 });
352
353
354 JButton btnSaveRules = new JButton("Save Rules...");
355 btnSaveRules.addActionListener(new ActionListener() {
356
357 @Override
358 public void actionPerformed(ActionEvent e)
359 {
360 List<CuttingRule> rules = new ArrayList<CuttingRule>();
361 if (customRulesTabModel.getRowCount() > 0)
362 {
363 for (int i=0; i<customRulesTabModel.getRowCount(); i++)
364 {
365 Vector rowdat = customRulesTabModel.getDataVector()
366 .elementAt(i);
367 try
368 {
369 String optsStr = (String) rowdat.elementAt(5);
370 rules.add(new CuttingRule(
371 (String) rowdat.elementAt(0),
372 (String) rowdat.elementAt(2),
373 (String) rowdat.elementAt(4),
374 (String) rowdat.elementAt(3),
375 Integer.valueOf((String) rowdat.elementAt(1)),
376 new ArrayList<String>(
377 Arrays.asList(optsStr.split("\\s+")))));
378 } catch (Exception ecr)
379 {
380 JOptionPane.showMessageDialog(btnSaveRules,
381 String.format("<html><body width='%1s'>"
382 + "Could not create cutting rule "
383 + "from these"
384 + "values: "
385 + rowdat.elementAt(i)
386 + ". Hint: " + ecr.getMessage()
387 + ". Skipping this line!</html>",
388 400),
389 "Error",
390 JOptionPane.PLAIN_MESSAGE,
391 UIManager.getIcon("OptionPane.errorIcon"));
392 continue;
393 }
394 String name = (String) customRulesTabModel
395 .getValueAt(i, 0);
396 System.out.println("Name: "+name);
397 }
398 }
399
400 FileAndFormat fileAndFormat =
402 if (fileAndFormat == null)
403 {
404 return;
405 }
406 try
407 {
408 DenoptimIO.writeCuttingRules(fileAndFormat.file, rules);
409 FileUtils.addToRecentFiles(fileAndFormat.file,
411 }
412 catch (Exception ex)
413 {
414 ex.printStackTrace();
415 JOptionPane.showMessageDialog(btnSaveRules,
416 "Could not write to '" + fileAndFormat.file + "'! "
417 + "Hint: "+ex.getMessage(),
418 "Error",
419 JOptionPane.PLAIN_MESSAGE,
420 UIManager.getIcon("OptionPane.errorIcon"));
421 return;
422 }
423 FileUtils.addToRecentFiles(fileAndFormat.file,
424 fileAndFormat.format);
425 }
426 });
427
428
429 JScrollPane customRulesScrollPane = new JScrollPane(customRulesTable);
430 customRulesTable.getTableHeader().setPreferredSize(
431 new Dimension(customRulesScrollPane.getWidth(), 40));
432
433
434 JPanel pnlButtonsDefaultRules = new JPanel(new FlowLayout(FlowLayout.LEFT));
435 pnlButtonsDefaultRules.add(btnAddDefaultRule);
436 pnlButtonsDefaultRules.add(btnRemoveDefaultRule);
437 pnlButtonsDefaultRules.add(btnViewSelectedDefaultRule);
438
439 JPanel headerDefaultBlock = new JPanel(new BorderLayout());
440 headerDefaultBlock.add(rdbUseDefault, BorderLayout.WEST);
441 headerDefaultBlock.add(pnlButtonsDefaultRules, BorderLayout.CENTER);
442
443 JPanel defaultRulesPanel = new JPanel(new BorderLayout());
444 defaultRulesPanel.add(headerDefaultBlock, BorderLayout.NORTH);
445 defaultRulesPanel.add(defaultRulesScrollPane, BorderLayout.CENTER);
446
447
448 JPanel pnlButtonsCustomRules = new JPanel(new FlowLayout(FlowLayout.LEFT));
449 pnlButtonsCustomRules.add(btnAddCustomRule);
450 pnlButtonsCustomRules.add(btnRemoveCustomRule);
451 pnlButtonsCustomRules.add(btnViewSelectedCustomRule);
452 pnlButtonsCustomRules.add(btnImportRules);
453 pnlButtonsCustomRules.add(btnSaveRules);
454
455 JPanel headerCustomBlock = new JPanel(new BorderLayout());
456 headerCustomBlock.add(rdbUseCustom, BorderLayout.WEST);
457 headerCustomBlock.add(pnlButtonsCustomRules, BorderLayout.CENTER);
458
459 JPanel customRulesPanel = new JPanel(new BorderLayout());
460 customRulesPanel.add(headerCustomBlock, BorderLayout.NORTH);
461 customRulesPanel.add(customRulesScrollPane, BorderLayout.CENTER);
462
463
464 JSplitPane masterPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
465 masterPane.setTopComponent(defaultRulesPanel);
466 masterPane.setBottomComponent(customRulesPanel);
467
468 // This is a further level of embedding created so that we can add stuff
469 // in addition to what is already in the masterPane
470 centralPanel.setLayout(new BoxLayout(centralPanel,
471 BoxLayout.Y_AXIS));
472 appendToCentralPanel(masterPane);
473
475
476 appendToCentralPanel(new JSeparator());
477
478 String toolTipLinearity = String.format("<html><body width='%1s'>"
479 + "Defines the max bond angle before considering the bond "
480 + "angle close to linear and, thus, adding a "
481 + "linearity-breaking dummy atom. Setting a value larger than "
482 + "180 prevents addition of any linearity-breaking dummy atom."
483 + "</html>", 400);
484 JPanel lineLinearity = new JPanel(new FlowLayout(FlowLayout.LEFT));
485 JLabel lblLinearity = new JLabel(
486 "Non-linearity limit for bond angles (DEG): ");
487 lblLinearity.setToolTipText(toolTipLinearity);
489 "###.#",
491 txtLinearity.setPreferredSize(strFieldSize);
492 txtLinearity.setToolTipText(toolTipLinearity);
493 lineLinearity.setToolTipText(toolTipLinearity);
494 lineLinearity.add(lblLinearity);
495 lineLinearity.add(txtLinearity);
496 appendToCentralPanel(lineLinearity);
497
498
499 btnDone.setText("Start Fragmentation");
500 btnDone.setToolTipText(String.format("<html><body width='%1s'>"
501 + "Uses the selected rules to produce fragments.</html>",400));
502
503 // NB: Assumption: 1 action listener inherited from superclass.
504 // We want to remove it because we need to acquire full control over
505 // when the modal panel has to be closed.
506 btnDone.removeActionListener(btnDone.getActionListeners()[0]);
507 btnDone.addActionListener(new ActionListener() {
508 @Override
509 public void actionPerformed(ActionEvent e)
510 {
511 DefaultTableModel chosenTab = defaultRulesTabModel;
512 if (rdbUseCustom.isSelected())
513 chosenTab = customRulesTabModel;
514
515 boolean setOfCuttingRulesHasBeenModified = false;
516
517 chosenOnes = new ArrayList<CuttingRule>();
518 for (int iRow=0; iRow<chosenTab.getRowCount(); iRow++)
519 {
520 String[] values = new String[5];
521 for (int iCol=0; iCol<5; iCol++)
522 {
523 values[iCol] = chosenTab.getValueAt(iRow,iCol)
524 .toString().trim();
525 }
526 ArrayList<String> opts = new ArrayList<String>();
527 if (!chosenTab.getValueAt(iRow,5).toString().trim().isBlank())
528 opts.addAll(Arrays.asList(chosenTab.getValueAt(iRow,5)
529 .toString().trim().split("\\s+")));
530
531 int prioIdx = 0;
532 try {
533 prioIdx = Integer.parseInt(values[1]);
534 } catch (Throwable t)
535 {
536 JOptionPane.showMessageDialog(btnDone,String.format(
537 "<html><body width='%1s'>"
538 + "Could not convert string '" + values[1]
539 + "' into an integer. Ignoring row " + iRow
540 + " in table of custom cutting rules.</html>",
541 400),
542 "Error",
543 JOptionPane.ERROR_MESSAGE,
544 UIManager.getIcon("OptionPane.errorIcon"));
545 continue;
546 }
547
548 CuttingRule newCuttingRule = new CuttingRule(values[0],
549 values[2], values[4], values[3], prioIdx, opts);
550 chosenOnes.add(newCuttingRule);
551
552 // Verify introduction of differences
553 if (!setOfCuttingRulesHasBeenModified)
554 {
555 boolean fromDefault = false;
556 if (defaultCuttingRules.size() > iRow)
557 {
558 fromDefault = defaultCuttingRules.get(iRow).equals(
559 newCuttingRule);
560 }
561 boolean fromCustom = false;
562 if (customCuttingRules.size() > iRow)
563 {
564 fromCustom = customCuttingRules.get(iRow).equals(
565 newCuttingRule);
566 }
567 if (!fromDefault && !fromCustom)
568 {
569 setOfCuttingRulesHasBeenModified = true;
570 }
571 }
572 }
573
574 // Verify shortening of the list of rules (case not covered above)
575 if (chosenOnes.size() != defaultCuttingRules.size()
576 && chosenOnes.size() != customCuttingRules.size())
577 {
578 setOfCuttingRulesHasBeenModified = true;
579 }
580
581 //Store a copy of the modified/customized rules
582 if (setOfCuttingRulesHasBeenModified)
583 {
584 try
585 {
588 chosenOnes);
591 } catch (DENOPTIMException e1)
592 {
593 e1.printStackTrace();
594 }
595 }
596
597 saveResults();
598
599 close();
600 }
601 });
602 getRootPane().setDefaultButton(btnDone);
603
604 this.btnCanc.setToolTipText("Exit without running fragmentation.");
605 }
606
607//-----------------------------------------------------------------------------
608
609 protected void saveResults()
610 {
612 if (lastUsedCutRulFile!=null)
613 {
615 lastUsedCutRulFile.getAbsolutePath());
616 }
619 Double.parseDouble(txtLinearity.getText()));
620 }
621
622//-----------------------------------------------------------------------------
623
628 protected void appendToCentralPanel(JComponent panel)
629 {
630 panel.setAlignmentX(Component.CENTER_ALIGNMENT);
631 centralPanel.add(panel);
632 }
633
634//-----------------------------------------------------------------------------
635
641 @SuppressWarnings("serial")
642 private class SMARTSVisualizationButton extends JButton
643 {
647 private Component refToThis;
648
649 private String templateURL = "https://smarts.plus/smartsview/"
650 + "download_rest?smarts="
651 + "SMARTS;"
652 + "filetype=svg;"
653 + "vmode=0;"
654 + "textdesc=1;"
655 + "depsymbols=1;"
656 + "smartsheading=0"; //makes text size too small for long SMARTS
657
658 public SMARTSVisualizationButton(JTable table,
659 DefaultTableModel tabModel)
660 {
661 super("Visualize Selected...");
662 refToThis = this;
663 addActionListener(new ActionListener() {
664
665 @Override
666 public void actionPerformed(ActionEvent e)
667 {
668 if (table.getRowCount()==0
669 || table.getSelectedRowCount()==0)
670 {
671 JOptionPane.showMessageDialog(refToThis,
672 "No SMARTS selected.",
673 "Visualization of SMARTS",
674 JOptionPane.PLAIN_MESSAGE);
675 return;
676 }
677
678 JPanel masterPanel = new JPanel();
679 masterPanel.setLayout(new BoxLayout(masterPanel,
680 BoxLayout.PAGE_AXIS));
681
682 int selectedRowIds[] = table.getSelectedRows();
683 Arrays.sort(selectedRowIds);
684 for (int i=0; i<selectedRowIds.length; i++)
685 {
686 String smarts = tabModel.getValueAt(
687 selectedRowIds[i],2).toString()
688 + tabModel.getValueAt(
689 selectedRowIds[i],3).toString()
690 + tabModel.getValueAt(
691 selectedRowIds[i],4).toString();
692
693 smarts = escapeCharactersForSMARTSViewer(smarts);
694 String url = templateURL.replace("SMARTS", smarts);
695
696 JPanel header = new JPanel(new FlowLayout(FlowLayout.LEFT));
697 header.add(new JLabel(tabModel.getValueAt(
698 selectedRowIds[i],0).toString() + " - "));
699
700 JLabel link = new JLabel("Download SVG");
701 link.setForeground(Color.BLUE.darker());
702 link.setCursor(Cursor.getPredefinedCursor(
703 Cursor.HAND_CURSOR));
704 link.addMouseListener(new MouseAdapter() {
705
706 @Override
707 public void mouseClicked(MouseEvent e) {
708 try {
709 Desktop.getDesktop().browse(new URI(url));
710 } catch (IOException | URISyntaxException e1) {
711 e1.printStackTrace();
712 }
713 }
714 });
715 header.add(link);
716
717 // This is a trick to set the minimal size of the frame
718 header.add(new JLabel(" "
719 + " "));
720
721 masterPanel.add(header);
722
723 MyJSVGCanvas svgCanvas = new MyJSVGCanvas();
724 svgCanvas.setURI(url);
725 masterPanel.add(svgCanvas);
726 }
727 GUIModalDialog dialog = new GUIModalDialog(refToThis,true);
728 dialog.addToCentralPane(masterPanel);
729 dialog.btnCanc.setVisible(false);
730 dialog.btnExtra.setText("?");
731 dialog.btnExtra.addActionListener(new ActionListener() {
732
733 @Override
734 public void actionPerformed(ActionEvent e)
735 {
736 JOptionPane.showMessageDialog(dialog.btnExtra,
737 String.format("<html><body width='%1s'>"
738 + "<p>Visual representations of SMARTS are depicted by the "
739 + "SMARTSview service offered "
740 + "by the ZBH - Center for Bioinformatics of the "
741 + "University of Hamburg (visit https://smarts.plus/).</p>"
742 + "<br><ul>"
743 + "<li>Use the 'Download SVG' button to download the "
744 + "figure.</li>"
745 + "<li>Pan the image in any direction by dragging the mouse "
746 + "(left button).</li>"
747 + "<li>Zoom in/out by holding the SHIFT key while dragging "
748 + "down-/up-wards.</li></ul></html>", 400),
749 "Visualization of SMARTS - Instructions",
750 JOptionPane.PLAIN_MESSAGE);
751 return;
752 }
753 });
754 dialog.showDialog();
755 }
756 });
757 }
758 }
759
760//-----------------------------------------------------------------------------
761
767 private class MyJSVGCanvas extends JSVGCanvas
768 {
772 private static final long serialVersionUID = 1L;
773
775 {
776 super();
777
778 // To change the interaction modes. First, disable the defaults
779 setEnableZoomInteractor(false);
780 setEnableImageZoomInteractor(false);
781 setEnablePanInteractor(false);
782 setEnableRotateInteractor(false);
783 setEnableResetTransformInteractor(false);
784
785 // Override the disabled default interactors that are still saved
786 // as fields.
787
788 // Then, we add our own interpreters of the mouse+key input
789
793 zoomInteractor = null;
794
798 imageZoomInteractor = new AbstractImageZoomInteractor() {
799 public boolean startInteraction(InputEvent ie) {
800 int mods = ie.getModifiersEx();
801 return
802 ie.getID() == MouseEvent.MOUSE_PRESSED &&
803 (mods & InputEvent.BUTTON1_DOWN_MASK) != 0 &&
804 (mods & InputEvent.SHIFT_DOWN_MASK) != 0;
805 }
806 };
807
811 panInteractor = new AbstractPanInteractor() {
812 public boolean startInteraction(InputEvent ie) {
813 int mods = ie.getModifiersEx();
814 return
815 ie.getID() == MouseEvent.MOUSE_PRESSED &&
816 (mods & InputEvent.BUTTON1_DOWN_MASK) != 0;
817 }
818
823 @Override
824 public void mouseExited(MouseEvent e) {}
825 };
826
830 rotateInteractor = null;
831
835 resetTransformInteractor = new AbstractResetTransformInteractor() {
836 public boolean startInteraction(InputEvent ie) {
837 int mods = ie.getModifiersEx();
838 return
839 ie.getID() == MouseEvent.MOUSE_PRESSED &&
840 (mods & InputEvent.CTRL_DOWN_MASK) != 0;
841 }
842 };
843 // Finally, enable the desired interactors. It is crucial to do this
844 // in the right order because the interactors are added to a List
845 // that retains the order and the events are interpreted so that
846 // the first interactor that returns true from startInteraction
847 // does the action, the others are not tested. Therefore, pan
848 // interactor, which has the less restrictive mask, must go last.
849 setEnableImageZoomInteractor(true);
850 setEnableResetTransformInteractor(true);
851 setEnablePanInteractor(true);
852 }
853 }
854
855//-----------------------------------------------------------------------------
856
861 private String escapeCharactersForSMARTSViewer(String smarts)
862 {
863 String escapedSmarts = smarts;
864 escapedSmarts = escapedSmarts.replaceAll("%", "%25");
865 escapedSmarts = escapedSmarts.replaceAll("&", "%26");
866 escapedSmarts = escapedSmarts.replaceAll("\\+", "%2B");
867 escapedSmarts = escapedSmarts.replaceAll("#", "%23");
868 escapedSmarts = escapedSmarts.replaceAll(";", "%3B");
869
870 return escapedSmarts;
871 }
872
873//-----------------------------------------------------------------------------
874
875 private void buildCustomRulesTable(List<CuttingRule> customCuttingRules,
876 String[] emptyRow)
877 {
878 for (int iRow=(customRulesTabModel.getRowCount()-1); iRow>-1; iRow--)
879 {
880 customRulesTabModel.removeRow(iRow);
881 }
882 if (customCuttingRules.size()==0)
883 {
884 customRulesTabModel.addRow(emptyRow);
885 } else {
886 for (CuttingRule cr : customCuttingRules)
887 {
888 String[] values = new String[6];
889 values[0] = cr.getName();
890 values[1] = String.valueOf(cr.getPriority());
891 values[2] = cr.getSMARTSAtom0();
892 values[3] = cr.getSMARTSBnd();
893 values[4] = cr.getSMARTSAtom1();
894 StringBuilder sb = new StringBuilder();
895 cr.getOptions().stream().forEach(s -> sb.append(" " + s));
896 values[5] = sb.toString();
897 customRulesTabModel.addRow(values);
898 }
899 }
900 }
901
902//-----------------------------------------------------------------------------
903
905 {
906 File parent = new File(GUIPreferences.tmpSpace);
907 return FileUtils.getAvailableFileName(parent, "cuttingRules");
908 }
909
910//-----------------------------------------------------------------------------
911
912}
A file with a conventional representation of its format.
static File getAvailableFileName(File parent, String baseName)
Define a filename that can be used, i.e., is still available, because no other file with the same pat...
Definition: FileUtils.java:729
static void addToRecentFiles(String fileName, FileFormat ff)
Appends an entry to the list of recent files.
Definition: FileUtils.java:67
Special canvas that overrides the set interpretation of mouse+key input to achieve a simplified zoom/...
A button that opens a modal dialog displaying the PNGs with a visual representation of SMARTS queries...
A modal dialog to define parameters for fragmentation and fragment filtering.
List< CuttingRule > chosenOnes
Chosen set of rules.
FragmenterParameters frgParams
Parameter storage were we store parameters.
final int preferredHeight
Default text field height.
File nextWrittenCutRulFile
The file where we will save next edited list of cutting rules.
JTextField txtLinearity
User-controlled definition of the linearity limit.
CuttingRulesSelectionDialog(List< CuttingRule > defaultCuttingRules, List< CuttingRule > customCuttingRules, boolean preselectDefault, Component refForPlacement, FragmenterParameters settings)
Constructor.
void appendToCentralPanel(JComponent panel)
Method to append a panel to the bottom of the central panel.
File lastUsedCutRulFile
The file where we last saved cutting rules different from the default.
String escapeCharactersForSMARTSViewer(String smarts)
Escaping some characters as explained in https://smarts.plus/rest.
final Dimension strFieldSize
Default sizes for mid-long text.
JPanel centralPanel
The panel in the central part of the dialog.
void buildCustomRulesTable(List< CuttingRule > customCuttingRules, String[] emptyRow)
File opener for DENOPTIM GUI.
static File pickFile(Component parent)
GUI component to provide pathname where to save stuff.
static FileAndFormat pickFileForSavingCuttingRules(Component parent)
JButton btnCanc
The button that is used to close the dialog without processing any input.
void addToCentralPane(JComponent comp)
Adds a component to the central part of this dialog frame.
JButton btnExtra
The button that can be used for any action that does not close the dialog.
JButton btnDone
The button that is used to launch the processing of the data given to the open dialog,...
Object result
The result to be returned once the dialog is closed.
Object showDialog()
Shows the dialog and restrains the modality to it, until the dialog gets closed.
GUIModalDialog(Component refForPlacement)
Constructor.
void close()
Closes the dialog window.
The collection of tunable preferences.
static String tmpSpace
Readable/writable space for tmp files.
Utility methods for input/output.
static void readCuttingRules(BufferedReader reader, List< CuttingRule > cutRules, String source)
Read cutting rules from a stream.
static void writeCuttingRules(File file, List< CuttingRule > cutRules)
Writes a formatted text file that collects cutting rule.
A cutting rule with three SMARTS queries (atom 1, bond, atom2) and options.
Parameters controlling execution of the fragmenter.
void setCuttingRules(List< CuttingRule > cuttingRules)
Assigns the cutting rules loaded from the input.
void setLinearAngleLimit(double linearAngleLimit)
Sets the upper limit for an angle before it is treated as "flat" angle, i.e., close enough to 180 DEG...
void setCuttingRulesFilePathname(String pathname)
Assigns the pathname to the cutting rules file.
static String getEnglishFormattedDecimal(String pattern, int decimals, double value)
Formats a decimal number using the given pattern but with English format as for separators.
File formats identified by DENOPTIM.
Definition: FileFormat.java:32