$darkmode
DENOPTIM
GUIVertexInspector.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2020 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.Dimension;
26import java.awt.event.ActionEvent;
27import java.awt.event.ActionListener;
28import java.beans.PropertyChangeEvent;
29import java.beans.PropertyChangeListener;
30import java.io.BufferedReader;
31import java.io.File;
32import java.io.InputStreamReader;
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.HashSet;
36import java.util.List;
37import java.util.Map;
38import java.util.Set;
39import java.util.concurrent.atomic.AtomicInteger;
40
41import javax.swing.BoxLayout;
42import javax.swing.DefaultListModel;
43import javax.swing.GroupLayout;
44import javax.swing.JButton;
45import javax.swing.JComponent;
46import javax.swing.JLabel;
47import javax.swing.JList;
48import javax.swing.JOptionPane;
49import javax.swing.JPanel;
50import javax.swing.JScrollPane;
51import javax.swing.JSeparator;
52import javax.swing.JSpinner;
53import javax.swing.JSpinner.DefaultEditor;
54import javax.swing.ListSelectionModel;
55import javax.swing.SpinnerNumberModel;
56import javax.swing.SwingConstants;
57import javax.swing.UIManager;
58import javax.swing.event.ChangeEvent;
59import javax.swing.event.ChangeListener;
60import javax.swing.table.DefaultTableModel;
61import javax.vecmath.Point3d;
62
63import org.openscience.cdk.interfaces.IAtom;
64import org.openscience.cdk.interfaces.IAtomContainer;
65import org.openscience.cdk.interfaces.IBond;
66
67import denoptim.constants.DENOPTIMConstants;
68import denoptim.exception.DENOPTIMException;
69import denoptim.files.FileAndFormat;
70import denoptim.files.FileUtils;
71import denoptim.fragmenter.FragmenterTools;
72import denoptim.graph.APClass;
73import denoptim.graph.AttachmentPoint;
74import denoptim.graph.DGraph;
75import denoptim.graph.Edge.BondType;
76import denoptim.graph.EmptyVertex;
77import denoptim.graph.Fragment;
78import denoptim.graph.Vertex;
79import denoptim.graph.Vertex.BBType;
80import denoptim.io.DenoptimIO;
81import denoptim.programs.fragmenter.CuttingRule;
82import denoptim.programs.fragmenter.FragmenterParameters;
83import denoptim.utils.DummyAtomHandler;
84import denoptim.utils.MoleculeUtils;
85
86
95public class GUIVertexInspector extends GUICardPanel
96{
100 private static final long serialVersionUID = 912850110991449553L;
101
105 public static AtomicInteger prepVrtxTabUID = new AtomicInteger(1);
106
110 private ArrayList<Vertex> verticesLibrary = new ArrayList<Vertex>();
111
115 private Vertex vertex;
116
120 private int currVrtxIdx = 0;
121
125 private boolean unsavedChanges = false;
126
128 private JPanel ctrlPane;
129 private JPanel navigPanel;
130 private JPanel navigPanel2;
131 private JPanel navigPanel3;
132
133 private JButton btnAddVrtx;
134 private JButton btnDelVrtx;
135
136 private JButton btnOpenVrtxs;
137
138 private JSpinner navigSpinner;
139 private JLabel totalVrtxsLabel;
142
143 private JPanel pnlImportStruct;
144 private JButton btnOpenMol;
145 private JButton btnOpenSMILES;
146
147 private JPanel pnlEmptFrag;
148 private JButton btnEmptFrag;
149
150 private JPanel pnlAtmToAP;
151 private JButton btnAtmToAP;
152
153 private JPanel pnlBondToAPPair;
154 private JButton btnBondToAPPair;
155
156 private JPanel pnlTmplBasedChop;
157 private JButton btnTmplBldChop;
158
159 private JPanel pnlChop;
160 private JButton btnChop;
161
162 private JPanel pnlDelSel;
163 private JButton btnDelSel;
164
165 private JPanel pnlSaveEdits;
166 private JButton btnSaveEdits;
167
168
169//-----------------------------------------------------------------------------
170
175 {
176 super(mainPanel, "Vertex Inspector #" + prepVrtxTabUID.getAndIncrement());
177 super.setLayout(new BorderLayout());
178 initialize();
179 }
180
181//-----------------------------------------------------------------------------
182
186 private void initialize() {
187
188 // BorderLayout is needed to allow dynamic resizing!
189 this.setLayout(new BorderLayout());
190
191 // This card structure includes center, east and south panels:
192 // - (Center) molecular/graph viewer and APs
193 // - (East) vertex controls
194 // - (South) general controls (load, save, close)
195
196 // The viewer with Jmol and APtable
197 vertexViewer = new VertexViewPanel(true);
198 vertexViewer.addPropertyChangeListener(
200 new PropertyChangeListener() {
201 @Override
202 public void propertyChange(PropertyChangeEvent evt) {
204 }
205 });
206 this.add(vertexViewer,BorderLayout.CENTER);
207
208 // General panel on the right: it containing all controls
209 ctrlPane = new JPanel();
210 ctrlPane.setVisible(true);
211 ctrlPane.setLayout(new BoxLayout(ctrlPane, SwingConstants.VERTICAL));
212 ctrlPane.add(new JSeparator());
213
214 // NB: avoid GroupLayout because it interferes with Jmol viewer and causes exception
215
216 // Controls to navigate the list of vertices
217 navigPanel = new JPanel();
218 navigPanel2 = new JPanel();
219 navigPanel3 = new JPanel();
220 JLabel navigationLabel1 = new JLabel("Vertex # ");
221 JLabel navigationLabel2 = new JLabel("Current library size: ");
222 totalVrtxsLabel = new JLabel("0");
223
224 navigSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 0, 1));
225 navigSpinner.setToolTipText("Move to vertex number # in the currently loaded library.");
226 navigSpinner.setPreferredSize(new Dimension(75,20));
227 navigSpinner.addChangeListener(vrtxSpinnerListener);
228 navigPanel.add(navigationLabel1);
230 ctrlPane.add(navigPanel);
231
232 navigPanel2.add(navigationLabel2);
235
236 btnAddVrtx = new JButton("Add");
237 btnAddVrtx.setToolTipText("Append vertices taken from a file.");
238 btnAddVrtx.addActionListener(new ActionListener() {
239 public void actionPerformed(ActionEvent e) {
240 File inFile = GUIFileOpener.pickFile(btnAddVrtx);
241 if (inFile == null || inFile.getAbsolutePath().equals(""))
242 {
243 return;
244 }
245
246 ArrayList<Vertex> vrtxLib = new ArrayList<>();
247 try {
248 vrtxLib = DenoptimIO.readVertexes(inFile, BBType.FRAGMENT);
249 } catch (Exception e1) {
250 e1.printStackTrace();
251 JOptionPane.showMessageDialog(btnAddVrtx,
252 "<html>Could not read building blocks from file"
253 + "<br>'" + inFile + "'"
254 + "<br>Hint on cause: " + e1.getMessage()
255 +"</html>",
256 "Error",
257 JOptionPane.ERROR_MESSAGE,
258 UIManager.getIcon("OptionPane.errorIcon"));
259 return;
260 }
261
262 if (vrtxLib.size() == 0)
263 {
264 JOptionPane.showMessageDialog(btnAddVrtx,
265 "<html>No building blocks in file"
266 + "<br>'" + inFile + "'</html>",
267 "Error",
268 JOptionPane.ERROR_MESSAGE,
269 UIManager.getIcon("OptionPane.errorIcon"));
270 return;
271 }
272
273 if (vrtxLib.size() == 1)
274 {
275 importVertices(vrtxLib);
276 return;
277 }
278
279 String[] options = new String[]{"All",
280 "Selected",
281 "Cancel"};
282 String txt = "<html><body width='%1s'>Do you want to "
283 + "append all building blocks or only selected ones?"
284 + "</html>";
285 int res = JOptionPane.showOptionDialog(btnAddVrtx,
286 String.format(txt,200),
287 "Append Building Blocks",
288 JOptionPane.DEFAULT_OPTION,
289 JOptionPane.QUESTION_MESSAGE,
290 UIManager.getIcon("OptionPane.warningIcon"),
291 options,
292 options[0]);
293
294 if (res == 2)
295 {
296 return;
297 }
298
299 switch (res)
300 {
301 case 0:
302 importVertices(vrtxLib);
303 break;
304
305 case 1:
306 ArrayList<Vertex> selectedVrtxs =
307 new ArrayList<Vertex>();
308 GUIVertexSelector vrtxSelector = new GUIVertexSelector(
309 btnAddVrtx,true);
310 vrtxSelector.setRequireApSelection(false);
311 vrtxSelector.load(vrtxLib, 0);
312 Object selected = vrtxSelector.showDialog();
313
314 if (selected != null)
315 {
316 @SuppressWarnings("unchecked")
317 ArrayList<ArrayList<Integer>> selList =
318 (ArrayList<ArrayList<Integer>>) selected;
319 for (ArrayList<Integer> pair : selList)
320 {
321 selectedVrtxs.add(vrtxLib.get(pair.get(0)));
322 }
323 }
324 importVertices(selectedVrtxs);
325 break;
326
327 default:
328 return;
329 }
330 }
331 });
332 btnDelVrtx = new JButton("Remove");
333 btnDelVrtx.setToolTipText("Remove the present building block from the "
334 + "library.");
335 btnDelVrtx.addActionListener(new ActionListener() {
336 public void actionPerformed(ActionEvent e) {
337 try {
339 } catch (DENOPTIMException e1) {
340 System.out.println("Exception while removing the current "
341 + "building block:");
342 e1.printStackTrace();
343 }
344 }
345 });
349
350 ctrlPane.add(new JSeparator());
351
352 pnlImportStruct = new JPanel();
353 GroupLayout lyoImportStructure = new GroupLayout(pnlImportStruct);
354 JLabel lblImportStruct = new JLabel("Import a structure from");
355 btnOpenMol = new JButton("File");
356 btnOpenMol.setToolTipText("Imports a chemical system"
357 + " from file.");
358 btnOpenMol.addActionListener(new ActionListener() {
359 public void actionPerformed(ActionEvent e) {
360 File inFile = GUIFileOpener.pickFile(btnOpenMol);
361 if (inFile == null || inFile.getAbsolutePath().equals(""))
362 {
363 return;
364 }
366 }
367 });
368
369 // the '+' is to prevent search/replace of the string
370 btnOpenSMILES = new JButton("SMI"+"LES");
371 btnOpenSMILES.setToolTipText("<html>Imports chemical system"
372 + " from SMILES string.<br>The conversion of SMILES "
373 + "to 3D structure requires"
374 + "<br> an internet connection.</html>");
375 btnOpenSMILES.addActionListener(new ActionListener() {
376 public void actionPerformed(ActionEvent e) {
377 String smiles = JOptionPane.showInputDialog(btnOpenSMILES,
378 "Please input SMILES: ");
379 if (smiles != null && !smiles.trim().equals(""))
380 {
382 }
383 }
384 });
385
386 pnlImportStruct.setLayout(lyoImportStructure);
387 lyoImportStructure.setAutoCreateGaps(true);
388 lyoImportStructure.setAutoCreateContainerGaps(true);
389 lyoImportStructure.setHorizontalGroup(lyoImportStructure.createParallelGroup(
390 GroupLayout.Alignment.CENTER)
391 .addComponent(lblImportStruct)
392 .addGroup(lyoImportStructure.createSequentialGroup()
393 .addComponent(btnOpenMol)
394 .addComponent(btnOpenSMILES)));
395 lyoImportStructure.setVerticalGroup(lyoImportStructure.createSequentialGroup()
396 .addComponent(lblImportStruct)
397 .addGroup(lyoImportStructure.createParallelGroup()
398 .addComponent(btnOpenMol)
399 .addComponent(btnOpenSMILES)));
401
402 ctrlPane.add(new JSeparator());
403
404 pnlEmptFrag = new JPanel();
405 btnEmptFrag = new JButton("Create Empty Vertex");
406 btnEmptFrag.setToolTipText("<html>Creates an empty vertex:<br>a vertex "
407 + "that contains no molecular structure.<html>");
408 btnEmptFrag.addActionListener(new ActionListener() {
409 public void actionPerformed(ActionEvent e) {
410 GUIEmptyVertexMaker makeEmptyVertexDialog =
412 makeEmptyVertexDialog.pack();
413 Object ev = makeEmptyVertexDialog.showDialog();
414 if (ev == null)
415 {
416 return;
417 }
418 ArrayList<Vertex> lst = new ArrayList<Vertex>(1);
419 lst.add((EmptyVertex) ev);
420 GUIVertexSelector fragSelector = new GUIVertexSelector(
421 btnEmptFrag,false);
422 fragSelector.load(lst, 0);
423 fragSelector.btnDone.setText("Confirm");
424 fragSelector.ctrlPane.setVisible(false);
425 fragSelector.setRequireApSelection(false);
426 Object selected = fragSelector.showDialog();
427 if (selected == null)
428 {
429 return;
430 }
431 importVertices(lst);
432 }
433 });
436
437 ctrlPane.add(new JSeparator());
438
439 pnlAtmToAP = new JPanel();
440 btnAtmToAP = new JButton("Atom to AP");
441 btnAtmToAP.setToolTipText("<html>Replaces the selected atoms with "
442 + "attachment points.<br>Click on atoms to select"
443 + " them. Click again to unselect.<br>"
444 + "<br><b>WARNING:</b> this action cannot be undone!<html>");
445 btnAtmToAP.addActionListener(new ActionListener() {
446 public void actionPerformed(ActionEvent e) {
448
449 ArrayList<IAtom> selectedAtms =
451
452 if (selectedAtms.size() == 0)
453 {
454 JOptionPane.showMessageDialog(btnAtmToAP,
455 "<html>No atom selected! Click on atoms to select"
456 + " them.<br>Click again to unselect.</html>",
457 "Error",
458 JOptionPane.ERROR_MESSAGE,
459 UIManager.getIcon("OptionPane.errorIcon"));
460 return;
461 }
462 else
463 {
464 List<APClass> selectedAPCs = choseOrCreateNewAPClass(
465 btnAtmToAP, true);
466
467 //The size of the list is either 0 or 1
468 if (selectedAPCs.size() == 0)
469 {
470 // We have pressed cancel or closed the dialog, so abandon
471 return;
472 }
473 String apClass = selectedAPCs.get(0).toString();
474
475 ArrayList<IAtom> failed = new ArrayList<IAtom>();
476 for (IAtom atm : selectedAtms)
477 {
478 if (!convertAtomToAP(atm, apClass))
479 {
480 failed.add(atm);
481 }
482 }
483 for (IAtom atm : failed)
484 {
485 selectedAtms.remove(atm);
486 }
487 if (selectedAtms.size() == 0)
488 {
489 return;
490 }
491
492 removeAtoms(selectedAtms);
493
495
496 unsavedChanges = true;
498 }
499 }
500 });
502 ctrlPane.add(pnlAtmToAP);
503
504 pnlBondToAPPair = new JPanel();
505 String bndToApLabel = "Bond to AP Pair";
506 btnBondToAPPair = new JButton(bndToApLabel);
507 btnBondToAPPair.setToolTipText("<html>Replaces bonds with "
508 + "pairs of attachment points. "
509 + "</br>Click on this button to start the selection of atoms that define the bonds to break."
510 + "<br><b>WARNING:</b> this action cannot be undone!<html>");
511 btnBondToAPPair.addActionListener(new ActionListener() {
512 public void actionPerformed(ActionEvent e) {
514
515 GUIAtomSelectionDialog firstAtomSelectionDialog = new GUIAtomSelectionDialog(
516 btnAtmToAP, vertex, null, 2, 1);
517 Object firstSelected = firstAtomSelectionDialog.showDialog();
518 if (firstSelected == null)
519 {
520 return;
521 }
522 List<IAtom> firstSelAtoms = (List<IAtom>) firstSelected;
523
524 GUIAtomSelectionDialog secondAtomSelectionDialog = new GUIAtomSelectionDialog(
525 btnAtmToAP, vertex, firstSelAtoms, 2, 2);
526 Object secondSelected = secondAtomSelectionDialog.showDialog();
527 if (secondSelected == null)
528 {
529 return;
530 }
531 List<IAtom> secondSelAtoms = (List<IAtom>) secondSelected;
532
533 List<List<List<IAtom>>> atomPairs = new ArrayList<>();
534 if (firstSelAtoms.size() == secondSelAtoms.size())
535 {
536 // Assume 2-center bonds
537 for (int i = 0; i < firstSelAtoms.size(); i++)
538 {
539 if (firstSelAtoms.get(i).getBond(secondSelAtoms.get(i)) == null)
540 {
541 String[] options = new String[]{"Ignore bonds", "Cancel"};
542 String txt = "<html>Atom "
543 + MoleculeUtils.getAtomRef(firstSelAtoms.get(i), vertex.getIAtomContainer())
544 + " is not bound to "
545 + MoleculeUtils.getAtomRef(secondSelAtoms.get(i), vertex.getIAtomContainer())
546 + ". Proceed the creation of AP pairs irrespective of the bonds?</html>";
547 int answer = JOptionPane.showOptionDialog(btnBondToAPPair,
548 String.format(txt,200),
549 "Ignore bonds?",
550 JOptionPane.DEFAULT_OPTION,
551 JOptionPane.QUESTION_MESSAGE,
552 UIManager.getIcon("OptionPane.warningIcon"),
553 options,
554 options[1]);
555 if (answer == 1)
556 {
557 return;
558 }
559 }
560 atomPairs.add(Arrays.asList(Arrays.asList(firstSelAtoms.get(i)),
561 Arrays.asList(secondSelAtoms.get(i))));
562 }
563 } else {
564 String[] options = new String[]{"Multihaptic bond",
565 "Multidentate bonds",
566 "Cancel"};
567 String txt = "<html>Unequal number of atoms in the two sets. Bonds may "
568 + "be treated as:<ul>"
569 + "<li> multihapto bond (create a single AP pair)</li>"
570 + "<li> multiple multidentate bonds (create multiple AP pairs)</li>"
571 + "</ul>"
572 + "<br>How to threat the selected atoms?</html>";
573 int answer = JOptionPane.showOptionDialog(btnBondToAPPair,
574 String.format(txt,200),
575 "Multihaptic or Multidentate?",
576 JOptionPane.DEFAULT_OPTION,
577 JOptionPane.QUESTION_MESSAGE,
578 UIManager.getIcon("OptionPane.warningIcon"),
579 options,
580 options[2]);
581
582 if (answer == 0)
583 {
584 // Assume multihapto bonds
585 if (firstSelAtoms.size() < secondSelAtoms.size())
586 {
587 Set<IAtom> assignedSecondAtoms = new HashSet<>();
588 for (int i = 0; i < firstSelAtoms.size(); i++)
589 {
590 IAtom firstAtom = firstSelAtoms.get(i);
591 List<IAtom> secondAtomsConnectedToFirstAtom = new ArrayList<>();
592 for (int j = 0; j < secondSelAtoms.size(); j++)
593 {
594 IAtom secondAtom = secondSelAtoms.get(j);
595 if (firstAtom.getBond(secondAtom) != null)
596 {
597 if (i>0 && assignedSecondAtoms.contains(secondSelAtoms.get(j)))
598 {
599 JOptionPane.showMessageDialog(btnBondToAPPair,
600 "<html>Atom "
602 + " is bound to "
604 + " but is already assigned to another atom. "
605 + "<br>Aborting: you'll have to break bonds involving "
607 + " one at the time.</html>",
608 "Error",
609 JOptionPane.ERROR_MESSAGE,
610 UIManager.getIcon("OptionPane.errorIcon"));
611 return;
612 }
613 assignedSecondAtoms.add(secondAtom);
614 secondAtomsConnectedToFirstAtom.add(secondAtom);
615 }
616 }
617 if (secondAtomsConnectedToFirstAtom.size() == 0)
618 {
619 JOptionPane.showMessageDialog(btnBondToAPPair,
620 "<html>No atoms in the second set is connected to atom "
622 + ". Aborting.</html>",
623 "Error",
624 JOptionPane.ERROR_MESSAGE,
625 UIManager.getIcon("OptionPane.errorIcon"));
626 return;
627 }
628 atomPairs.add(Arrays.asList(Arrays.asList(firstAtom), secondAtomsConnectedToFirstAtom));
629 }
630 } else {
631 Set<IAtom> assignedFirstAtoms = new HashSet<>();
632 for (int i = 0; i < secondSelAtoms.size(); i++)
633 {
634 IAtom secondAtom = secondSelAtoms.get(i);
635 List<IAtom> firstAtomsConnectedToSecondAtom = new ArrayList<>();
636 for (int j = 0; j < firstSelAtoms.size(); j++)
637 {
638 IAtom firstAtom = firstSelAtoms.get(j);
639 if (firstAtom.getBond(secondAtom) != null)
640 {
641 if (i>0 && assignedFirstAtoms.contains(firstSelAtoms.get(j)))
642 {
643 JOptionPane.showMessageDialog(btnBondToAPPair,
644 "<html>Atom "
646 + " is bound to "
648 + " but is already assigned to another atom. "
649 + "<br>Aborting: you'll have to break bonds involving "
651 + " one at the time.</html>",
652 "Error",
653 JOptionPane.ERROR_MESSAGE,
654 UIManager.getIcon("OptionPane.errorIcon"));
655 return;
656 }
657 assignedFirstAtoms.add(firstAtom);
658 firstAtomsConnectedToSecondAtom.add(firstAtom);
659 }
660 }
661 if (firstAtomsConnectedToSecondAtom.size() == 0)
662 {
663 JOptionPane.showMessageDialog(btnBondToAPPair,
664 "<html>No atoms in the second set is connected to atom "
666 + ". Aborting.</html>",
667 "Error",
668 JOptionPane.ERROR_MESSAGE,
669 UIManager.getIcon("OptionPane.errorIcon"));
670 return;
671 }
672 atomPairs.add(Arrays.asList(firstAtomsConnectedToSecondAtom, Arrays.asList(secondAtom)));
673 }
674 }
675 } else if (answer == 1) {
676 // Assume multiple multidentate bonds
677 for (IAtom firstAtom : firstSelAtoms)
678 {
679 for (IAtom secondAtom : secondSelAtoms)
680 {
681 if (firstAtom.getBond(secondAtom) != null)
682 {
683 atomPairs.add(Arrays.asList(Arrays.asList(firstAtom), Arrays.asList(secondAtom)));
684 }
685 }
686 }
687 } else {
688 return;
689 }
690 }
691
692 List<List<APClass>> apClasses = new ArrayList<>();
693 List<APClass> selectedAPCs = choseOrCreateNewAPClass(
694 btnBondToAPPair, true, "APClass on 1st set of atoms");
695 if (selectedAPCs.size() == 0)
696 {
697 return;
698 }
699 APClass apc0 = selectedAPCs.get(0);
700
701 selectedAPCs = choseOrCreateNewAPClass(
702 btnBondToAPPair, true, "APClass on 2nd set of atoms");
703 if (selectedAPCs.size() == 0)
704 {
705 return;
706 }
707 APClass apc1 = selectedAPCs.get(0);
708 for (int i = 0; i < atomPairs.size(); i++)
709 {
710 apClasses.add(Arrays.asList(apc0, apc1));
711 }
712
713 // Get default parameters
715
716 // Now chop the structure to produce fragments
717 List<Vertex> fragments;
718 try
719 {
720 fragments = FragmenterTools.fragmentation(
722 atomPairs,
723 apClasses);
724 } catch (Throwable t)
725 {
726 JOptionPane.showMessageDialog(btnChop,String.format(
727 "<html><body width='%1s'"
728 + "Could not complete fragmentation. Hint: "
729 + t.getMessage() + "</html>", 400),
730 "Error",
731 JOptionPane.ERROR_MESSAGE,
732 UIManager.getIcon("OptionPane.errorIcon"));
733 return;
734 }
735
736 // Add linearity-breaking dummy atoms
737 for (Vertex frag : fragments)
738 {
740 settings.getLinearAngleLimit());
741 }
742
743 // Signal no result obtained
744 if (fragments.size() < 1 || (fragments.size() == 1 &&
745 ((Fragment)fragments.get(0)).isIsomorphicTo(vertex)))
746 {
747 JOptionPane.showMessageDialog(btnAddVrtx,
748 "<html>Fragmentation produced no fragments!</html>",
749 "Error",
750 JOptionPane.WARNING_MESSAGE,
751 UIManager.getIcon("OptionPane.warningIcon"));
752 return;
753 }
754
755 // The resulting fragments are loaded into the viewer, without
756 // removing the original structure.
757
758 String[] options = new String[]{"All",
759 "Select",
760 "Cancel"};
761 String txt = "<html><body width='%1s'>Fragmentation produced "
762 + fragments.size() + " fragments. Do you want to "
763 + "append all or select some?"
764 + "</html>";
765 int answer = JOptionPane.showOptionDialog(btnAddVrtx,
766 String.format(txt,200),
767 "Append Building Blocks",
768 JOptionPane.DEFAULT_OPTION,
769 JOptionPane.QUESTION_MESSAGE,
770 UIManager.getIcon("OptionPane.warningIcon"),
771 options,
772 options[0]);
773
774 if (answer == 2)
775 {
776 return;
777 }
778
779 switch (answer)
780 {
781 case 0:
782 importVertices(fragments);
783 break;
784
785 case 1:
786 List<Vertex> selectedVrtxs =
787 new ArrayList<Vertex>();
788 GUIVertexSelector vrtxSelector = new GUIVertexSelector(
789 btnAddVrtx,true);
790 vrtxSelector.setRequireApSelection(false);
791 vrtxSelector.load(fragments, 0);
792 Object selected = vrtxSelector.showDialog();
793
794 if (selected != null)
795 {
796 @SuppressWarnings("unchecked")
797 List<ArrayList<Integer>> selList =
798 (ArrayList<ArrayList<Integer>>) selected;
799 for (ArrayList<Integer> pair : selList)
800 {
801 selectedVrtxs.add(fragments.get(pair.get(0)));
802 }
803 }
804 importVertices(selectedVrtxs);
805 break;
806
807 default:
808 return;
809 }
810 }
811 });
814
815 pnlChop = new JPanel();
816 btnChop = new JButton("Chop Structure");
817 btnChop.setToolTipText(String.format("<html><body width='%1s'>"
818 + "Applies cutting rules on "
819 + "the current structure to generate fragments.</html>", 400));
820 btnChop.addActionListener(new ActionListener() {
821 public void actionPerformed(ActionEvent event) {
823 if (vertex==null
824 || vertex.getIAtomContainer().getBondCount() == 0)
825 {
826 JOptionPane.showMessageDialog(btnChop,
827 "<html>System contains 0 bonds. "
828 + "Nothing to chop.</html>",
829 "Error",
830 JOptionPane.ERROR_MESSAGE,
831 UIManager.getIcon("OptionPane.errorIcon"));
832 return;
833 }
834
836 boolean result = dialogToDefineCuttingRules(
837 settings,
838 this.getClass().getClassLoader(),
839 btnChop,
840 false);
841 if (!result)
842 return;
843
844 String pathnameLastUsedCutRules =
846 if (pathnameLastUsedCutRules != null
847 && !pathnameLastUsedCutRules.isBlank())
848 {
849 GUIPreferences.lastCutRulesFile =
850 new File(pathnameLastUsedCutRules);
851 }
852
853 // Now chop the structure to produce fragments
854 List<Vertex> fragments;
855 try
856 {
857 fragments = FragmenterTools.fragmentation(
859 settings.getCuttingRules(),
860 settings.getLogger());
861 } catch (DENOPTIMException e)
862 {
863 JOptionPane.showMessageDialog(btnChop,String.format(
864 "<html><body width='%1s'"
865 + "Could not complete fragmentation. Hint: "
866 + e.getMessage() + "</html>", 400),
867 "Error",
868 JOptionPane.ERROR_MESSAGE,
869 UIManager.getIcon("OptionPane.errorIcon"));
870 return;
871 }
872
873 // Add linearity-breaking dummy atoms
874 for (Vertex frag : fragments)
875 {
877 settings.getLinearAngleLimit());
878 }
879
880 // Signal no result obtained
881 if (fragments.size() < 1 || (fragments.size() == 1 &&
882 ((Fragment)fragments.get(0)).isIsomorphicTo(vertex)))
883 {
884 JOptionPane.showMessageDialog(btnAddVrtx,
885 "<html>Fragmentation produced no fragments!</html>",
886 "Error",
887 JOptionPane.WARNING_MESSAGE,
888 UIManager.getIcon("OptionPane.warningIcon"));
889 return;
890 }
891
892 // The resulting fragments are loaded into the viewer, without
893 // removing the original structure.
894
895 String[] options = new String[]{"All",
896 "Select",
897 "Cancel"};
898 String txt = "<html><body width='%1s'>Fragmentation produced "
899 + fragments.size() + " fragments. Do you want to "
900 + "append all or select some?"
901 + "</html>";
902 int answer = JOptionPane.showOptionDialog(btnAddVrtx,
903 String.format(txt,200),
904 "Append Building Blocks",
905 JOptionPane.DEFAULT_OPTION,
906 JOptionPane.QUESTION_MESSAGE,
907 UIManager.getIcon("OptionPane.warningIcon"),
908 options,
909 options[0]);
910
911 if (answer == 2)
912 {
913 return;
914 }
915
916 switch (answer)
917 {
918 case 0:
919 importVertices(fragments);
920 break;
921
922 case 1:
923 List<Vertex> selectedVrtxs =
924 new ArrayList<Vertex>();
925 GUIVertexSelector vrtxSelector = new GUIVertexSelector(
926 btnAddVrtx,true);
927 vrtxSelector.setRequireApSelection(false);
928 vrtxSelector.load(fragments, 0);
929 Object selected = vrtxSelector.showDialog();
930
931 if (selected != null)
932 {
933 @SuppressWarnings("unchecked")
934 List<ArrayList<Integer>> selList =
935 (ArrayList<ArrayList<Integer>>) selected;
936 for (ArrayList<Integer> pair : selList)
937 {
938 selectedVrtxs.add(fragments.get(pair.get(0)));
939 }
940 }
941 importVertices(selectedVrtxs);
942 break;
943
944 default:
945 return;
946 }
947 }
948 });
949 pnlChop.add(btnChop);
950 ctrlPane.add(pnlChop);
951
952 pnlTmplBasedChop = new JPanel();
953 btnTmplBldChop = new JButton("Chop by Template");
954 btnTmplBldChop.setToolTipText(String.format("<html><body width='%1s'>"
955 + "Chops the current structure according to a given graph template expected to be a substructure of the current structure.</html>", 400));
956 btnTmplBldChop.addActionListener(new ActionListener() {
957 public void actionPerformed(ActionEvent event) {
958 // NB: we call it vertex because we are in the vertex viewer, but it is a structure that may not be a vertex.
960 if (vertex==null)
961 {
962 return;
963 }
964
966 if (inFile == null || inFile.getAbsolutePath().equals(""))
967 {
968 return;
969 }
970
971 List<DGraph> fragmentationTmpls = new ArrayList<>();
972 try
973 {
974 fragmentationTmpls = DenoptimIO.readDENOPTIMGraphsFromFile(inFile);
975 } catch (Throwable e)
976 {
977 JOptionPane.showMessageDialog(btnTmplBldChop,String.format(
978 "<html><body width='%1s'"
979 + "Could not read template file. Hint: "
980 + e.getMessage() + "</html>", 400),
981 "Error",
982 JOptionPane.ERROR_MESSAGE,
983 UIManager.getIcon("OptionPane.errorIcon"));
984 return;
985 }
986
987 if (fragmentationTmpls.size() == 0)
988 {
989 JOptionPane.showMessageDialog(btnTmplBldChop,
990 "<html>No graphs found in file '"
991 + inFile + "'.</html>",
992 "Error",
993 JOptionPane.ERROR_MESSAGE,
994 UIManager.getIcon("OptionPane.errorIcon"));
995 return;
996 }
997
999 settings.setFragmentationTmpls(fragmentationTmpls);
1000
1001 // Now chop the structure to produce fragments
1002 List<Vertex> fragments;
1003 try
1004 {
1006 settings.getFragmentationTmpls(),
1007 settings.getMaxBufferShellSize(),
1008 settings.getRandomizer(),
1009 settings.getLogger());
1010 } catch (DENOPTIMException e)
1011 {
1012 JOptionPane.showMessageDialog(btnChop,String.format(
1013 "<html><body width='%1s'"
1014 + "Could not complete fragmentation. Hint: "
1015 + e.getMessage() + "</html>", 400),
1016 "Error",
1017 JOptionPane.ERROR_MESSAGE,
1018 UIManager.getIcon("OptionPane.errorIcon"));
1019 return;
1020 }
1021
1022 // Add linearity-breaking dummy atoms
1023 for (Vertex frag : fragments)
1024 {
1026 settings.getLinearAngleLimit());
1027 }
1028
1029 // Signal no result obtained
1030 if (fragments.size() < 1 || (fragments.size() == 1 &&
1031 ((Fragment)fragments.get(0)).isIsomorphicTo(vertex)))
1032 {
1033 JOptionPane.showMessageDialog(btnAddVrtx,
1034 "<html>Fragmentation produced no fragments!</html>",
1035 "Error",
1036 JOptionPane.WARNING_MESSAGE,
1037 UIManager.getIcon("OptionPane.warningIcon"));
1038 return;
1039 }
1040
1041 // The resulting fragments are loaded into the viewer, without
1042 // removing the original structure.
1043
1044 String[] options = new String[]{"All",
1045 "Select",
1046 "Cancel"};
1047 String txt = "<html><body width='%1s'>Fragmentation produced "
1048 + fragments.size() + " fragments. Do you want to "
1049 + "append all or select some?"
1050 + "</html>";
1051 int answer = JOptionPane.showOptionDialog(btnAddVrtx,
1052 String.format(txt,200),
1053 "Append Building Blocks",
1054 JOptionPane.DEFAULT_OPTION,
1055 JOptionPane.QUESTION_MESSAGE,
1056 UIManager.getIcon("OptionPane.warningIcon"),
1057 options,
1058 options[0]);
1059
1060 if (answer == 2)
1061 {
1062 return;
1063 }
1064
1065 switch (answer)
1066 {
1067 case 0:
1068 importVertices(fragments);
1069 break;
1070
1071 case 1:
1072 List<Vertex> selectedVrtxs =
1073 new ArrayList<Vertex>();
1074 GUIVertexSelector vrtxSelector = new GUIVertexSelector(
1075 btnAddVrtx,true);
1076 vrtxSelector.setRequireApSelection(false);
1077 vrtxSelector.load(fragments, 0);
1078 Object selected = vrtxSelector.showDialog();
1079
1080 if (selected != null)
1081 {
1082 @SuppressWarnings("unchecked")
1083 List<ArrayList<Integer>> selList =
1084 (ArrayList<ArrayList<Integer>>) selected;
1085 for (ArrayList<Integer> pair : selList)
1086 {
1087 selectedVrtxs.add(fragments.get(pair.get(0)));
1088 }
1089 }
1090 importVertices(selectedVrtxs);
1091 break;
1092
1093 default:
1094 return;
1095 }
1096 }
1097 });
1100
1101 pnlDelSel = new JPanel();
1102 btnDelSel = new JButton("Remove Atoms");
1103 btnDelSel.setToolTipText("<html>Removes all selected atoms from the "
1104 + "system.<br><br><b>WARNING:</b> this action cannot be "
1105 + "undone!");
1106 btnDelSel.addActionListener(new ActionListener() {
1107 public void actionPerformed(ActionEvent e) {
1108 ArrayList<IAtom> selectedAtms =
1110
1111 if (selectedAtms.size() == 0)
1112 {
1113 JOptionPane.showMessageDialog(btnDelSel,
1114 "<html>No atom selected! Click on atoms to select"
1115 + " them.<br>Click again to unselect.</html>",
1116 "Error",
1117 JOptionPane.ERROR_MESSAGE,
1118 UIManager.getIcon("OptionPane.errorIcon"));
1119 return;
1120 }
1121 else
1122 {
1123 removeAtoms(selectedAtms);
1124
1126
1127 unsavedChanges = true;
1129 }
1130 }
1131 });
1132 pnlDelSel.add(btnDelSel);
1133 ctrlPane.add(pnlDelSel);
1134
1135 ctrlPane.add(new JSeparator());
1136
1137 pnlSaveEdits = new JPanel();
1138 btnSaveEdits = new JButton("Save Changes");
1139 //btnSaveEdits.setForeground(Color.RED);
1140 btnSaveEdits.setEnabled(true);
1141 btnSaveEdits.setToolTipText("<html>Save the current system replacing"
1142 + " <br>the original one in the loaded library.</html>");
1143 btnSaveEdits.addActionListener(new ActionListener() {
1144 public void actionPerformed(ActionEvent e) {
1146 }
1147 });
1150 this.add(ctrlPane, BorderLayout.EAST);
1151
1152
1153 // Panel with buttons to the bottom of the frame
1154 ButtonsBar commandsPane = new ButtonsBar();
1155 super.add(commandsPane, BorderLayout.SOUTH);
1156
1157 btnOpenVrtxs = new JButton("Load Library of Building Blocks");
1158 btnOpenVrtxs.setToolTipText("Reads building blocks or structures from "
1159 + "file.");
1160 btnOpenVrtxs.addActionListener(new ActionListener() {
1161 public void actionPerformed(ActionEvent e) {
1162 File inFile = GUIFileOpener.pickFile(btnOpenVrtxs);
1163 if (inFile == null || inFile.getAbsolutePath().equals(""))
1164 {
1165 return;
1166 }
1167 ArrayList<Vertex> vrtxLib = new ArrayList<>();
1168 try {
1169 vrtxLib = DenoptimIO.readVertexes(inFile, BBType.FRAGMENT);
1170 } catch (Exception e1) {
1171 e1.printStackTrace();
1172 JOptionPane.showMessageDialog(btnAddVrtx,
1173 "<html>Could not read building blocks from file"
1174 + "<br>'" + inFile + "'"
1175 + "<br>Hint on cause: " + e1.getMessage()
1176 +"</html>",
1177 "Error",
1178 JOptionPane.ERROR_MESSAGE,
1179 UIManager.getIcon("OptionPane.errorIcon"));
1180 return;
1181 }
1182
1183 if (vrtxLib.size() == 0)
1184 {
1185 JOptionPane.showMessageDialog(btnAddVrtx,
1186 "<html>No building blocks in file"
1187 + "<br>'" + inFile + "'</html>",
1188 "Error",
1189 JOptionPane.ERROR_MESSAGE,
1190 UIManager.getIcon("OptionPane.errorIcon"));
1191 return;
1192 }
1193 importVertices(vrtxLib);
1194 }
1195 });
1196 commandsPane.add(btnOpenVrtxs);
1197
1198 JButton btnSaveVrtxs = new JButton("Save Library of Building Blocks");
1199 btnSaveVrtxs.setToolTipText("Write all building blocks to a file.");
1200 btnSaveVrtxs.addActionListener(new ActionListener() {
1201 public void actionPerformed(ActionEvent e) {
1202 FileAndFormat fileAndFormat =
1204 if (fileAndFormat == null)
1205 {
1206 return;
1207 }
1208 File outFile = fileAndFormat.file;
1209 try
1210 {
1211 // The writing method may change the extension. So we need
1212 // to get the return value.
1213 outFile = DenoptimIO.writeVertexesToFile(outFile,
1214 fileAndFormat.format,
1216 }
1217 catch (Exception ex)
1218 {
1219 ex.printStackTrace();
1220 JOptionPane.showMessageDialog(btnSaveVrtxs,
1221 "Could not write to '" + outFile + "'! "
1222 + "Hint: "+ex.getMessage(),
1223 "Error",
1224 JOptionPane.PLAIN_MESSAGE,
1225 UIManager.getIcon("OptionPane.errorIcon"));
1226 return;
1227 }
1228 navigSpinner.setModel(new SpinnerNumberModel(currVrtxIdx+1, 1,
1229 verticesLibrary.size(), 1));
1231 unsavedChanges = false;
1232 FileUtils.addToRecentFiles(outFile, fileAndFormat.format);
1233 }
1234 });
1235 commandsPane.add(btnSaveVrtxs);
1236
1237 JButton btnCanc = new JButton("Close Tab");
1238 btnCanc.setToolTipText("Closes this tab.");
1239 btnCanc.addActionListener(new removeCardActionListener(this));
1240 commandsPane.add(btnCanc);
1241
1242 JButton btnHelp = new JButton("?");
1243 btnHelp.setToolTipText("<html>Hover over the buttons and fields "
1244 + "to get a tip.</html>");
1245 btnHelp.addActionListener(new ActionListener() {
1246 public void actionPerformed(ActionEvent e) {
1247 String txt = "<html><body width='%1s'>"
1248 + "<p>This tab allows to create, inspect, and edit "
1249 + "building blocks and "
1250 + "three-dimensional molecular fragments.</p>"
1251 + "<p>New fragments can be created starting from any "
1252 + "chemical structure that can be loaded from file or "
1253 + "generated from SMILES (SMILES-to-3D conversion "
1254 + "requires an Internet connection).</p>"
1255 + "<p>Any terminal atom (i.e., atoms that have only "
1256 + "one connected neighbor) can be transformed into "
1257 + "on attachment point (AP). Click on the atom to "
1258 + "select it, and press <code><b>Atom to AP</b></code>."
1259 + "</p>"
1260 + "<p>Attachment points are depicted in the molecular "
1261 + "viewer as yellow arrows in the 3D space, and their "
1262 + "attachment point class (APClass) is specified in "
1263 + "the table below the viewer. Double-click on a "
1264 + "specific APClass field to change its value.</p>"
1265 + "<br>"
1266 + "<p>Hover over buttons get a tip.</p>"
1267 + "<br>"
1268 + "<p>Right-click on the Jmol viewer will open the "
1269 + "Jmol menu. However, since Jmol cannot handle the "
1270 + "attachment points data. Therefore, Jmol "
1271 + "functionality should only be used on systems "
1272 + "that have no attachment points, or for alterations "
1273 + "of the molecular structure that do not change the "
1274 + "list of atoms au to the last atom decorated with an "
1275 + "attachment point.</p></html>";
1276 JOptionPane.showMessageDialog(btnHelp,
1277 String.format(txt, 400),
1278 "Tips",
1279 JOptionPane.PLAIN_MESSAGE);
1280 }
1281 });
1282 commandsPane.add(btnHelp);
1283 }
1284
1285//-----------------------------------------------------------------------------
1286
1297 public static boolean dialogToDefineCuttingRules(
1298 FragmenterParameters settings, ClassLoader classLoader,
1299 Component parent,
1300 boolean setMolToGraphSettings)
1301 {
1302 settings.startConsoleLogger("GUI-controlledFragmenterLogger");
1303
1304 List<CuttingRule> defaultCuttingRules = new ArrayList<CuttingRule>();
1305 try
1306 {
1307 defaultCuttingRules = settings.getDefaultCuttingRules(classLoader);
1308 } catch (Exception e )
1309 {
1310 e.printStackTrace();
1311 JOptionPane.showMessageDialog(parent,String.format(
1312 "<html><body width='%1s'>"
1313 + "Could not read default cutting rules from "
1314 + "bundled jar. "
1315 + "Hint: "
1316 + e.getMessage() + "</html>", 400),
1317 "Error",
1318 JOptionPane.ERROR_MESSAGE,
1319 UIManager.getIcon("OptionPane.errorIcon"));
1320 return false;
1321 }
1322
1323 // Read last used cutting rules
1324 List<CuttingRule> customCuttingRules = new ArrayList<CuttingRule>();
1325 boolean useDefaultCuttingRules = true;
1326 try
1327 {
1329 {
1332 customCuttingRules);
1333 useDefaultCuttingRules = false;
1334 }
1335 } catch (DENOPTIMException e)
1336 {
1337 JOptionPane.showMessageDialog(parent,String.format(
1338 "<html><body width='%1s'"
1339 + "Could not read last-used cutting rules from '"
1341 + "Hint: "
1342 + e.getMessage() + "</html>", 400),
1343 "Error",
1344 JOptionPane.ERROR_MESSAGE,
1345 UIManager.getIcon("OptionPane.errorIcon"));
1346 return false;
1347 }
1348
1349 // Build a dialog that offers the possibility to see and edit
1350 // default cutting rules, and to define custom ones from scratch
1351 CuttingRulesSelectionDialog crs = null;
1352 if (setMolToGraphSettings)
1353 {
1355 defaultCuttingRules, customCuttingRules,
1356 useDefaultCuttingRules, parent, settings);
1357 } else {
1359 defaultCuttingRules, customCuttingRules,
1360 useDefaultCuttingRules, parent, settings);
1361 }
1362 crs.pack();
1363 crs.setVisible(true);
1364
1365 if (crs.result==null)
1366 return false;
1367
1368 String pathnameLastUsedCutRules = settings.getCuttingRulesFilePathname();
1369 if (pathnameLastUsedCutRules != null
1370 && !pathnameLastUsedCutRules.isBlank())
1371 {
1372 GUIPreferences.lastCutRulesFile = new File(pathnameLastUsedCutRules);
1373 }
1374
1375 return true;
1376 }
1377
1378//-----------------------------------------------------------------------------
1379
1380 public void importStructureFromFile(File file)
1381 {
1382 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1383
1384 // Cleanup
1386
1387 try {
1388 for (IAtomContainer mol : DenoptimIO.readAllAtomContainers(file))
1389 {
1390 // We mean to import only the structure: get rid of AP
1391 mol.setProperty(DENOPTIMConstants.APSTAG,null);
1392
1393 // NB: here we let the vertexViewer create a fragment object that we
1394 // then put into the local library. This to make sure that the
1395 // references to atoms selected in the viewer are referring to
1396 // members of the "vertex" object
1399
1400 // the system is not a fragment but, this is done for consistency:
1401 // when we have a molecule loaded the list is not empty
1402 // The currently viewed fragment (if any) is always part of the lib
1404 currVrtxIdx = verticesLibrary.size()-1;
1405 }
1407 unsavedChanges = true;
1408 btnDelSel.setEnabled(true);
1409 btnAtmToAP.setEnabled(true);
1410 btnBondToAPPair.setEnabled(true);
1411 } catch (Exception e) {
1412 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1413 e.printStackTrace();
1414 JOptionPane.showMessageDialog(this,
1415 "<html>Could not read file '" + file.getAbsolutePath()
1416 + "'!<br>Hint about reason: " + e.getCause() + "</html>",
1417 "Error",
1418 JOptionPane.PLAIN_MESSAGE,
1419 UIManager.getIcon("OptionPane.errorIcon"));
1420 }
1421
1422 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1423 }
1424
1425//-----------------------------------------------------------------------------
1426
1433 public void importStructureFromSMILES(String smiles)
1434 {
1435 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1436
1437 // Cleanup
1439
1440 // Load the structure using CACTUS service or CDK builder
1441 try {
1442 vertexViewer.loadSMILES(smiles);
1443 } catch (Exception e) {
1444 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1445 return;
1446 }
1447
1449
1450 // The system is not a fragment but, this is done for consistency:
1451 // when we have a molecule loaded the list is not empty:
1452 // The currently viewed fragment (if any) is always part of the library
1454 currVrtxIdx = verticesLibrary.size()-1;
1455
1456 // finalize GUI status
1458 unsavedChanges = true;
1459 btnDelSel.setEnabled(true);
1460 btnAtmToAP.setEnabled(true);
1461 btnBondToAPPair.setEnabled(true);
1462 btnSaveEdits.setEnabled(true);
1463
1464 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1465 }
1466
1467//-----------------------------------------------------------------------------
1468
1473 public void importVerticesFromFile(File file)
1474 {
1475 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1476
1477 ArrayList<Vertex> vrtxLib = new ArrayList<>();
1478 try {
1479 vrtxLib = DenoptimIO.readVertexes(file, BBType.FRAGMENT);
1480 } catch (Exception e1) {
1481 e1.printStackTrace();
1482 JOptionPane.showMessageDialog(btnAddVrtx,
1483 "<html>Could not read building blocks from file"
1484 + "<br>'" + file + "'"
1485 + "<br>Hint on cause: " + e1.getMessage()
1486 +"</html>",
1487 "Error",
1488 JOptionPane.ERROR_MESSAGE,
1489 UIManager.getIcon("OptionPane.errorIcon"));
1490 return;
1491 }
1492
1493 if (vrtxLib.size() == 0)
1494 {
1495 JOptionPane.showMessageDialog(btnAddVrtx,
1496 "<html>No building blocks in file"
1497 + "<br>'" + file + "'</html>",
1498 "Error",
1499 JOptionPane.ERROR_MESSAGE,
1500 UIManager.getIcon("OptionPane.errorIcon"));
1501 return;
1502 }
1503 importVertices(vrtxLib);
1504 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1505 }
1506
1507//-----------------------------------------------------------------------------
1508
1513 public void importVertices(List<Vertex> fragments)
1514 {
1515 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1516
1517 int firstOfNew = 0;
1518 boolean libFromScrtch = false;
1519 if (verticesLibrary == null)
1520 {
1521 libFromScrtch = true;
1522 verticesLibrary = new ArrayList<Vertex>();
1523 }
1524 else
1525 {
1526 firstOfNew = verticesLibrary.size();
1527 }
1528
1529 boolean addedOne = false;
1530 if (fragments.size() > 0)
1531 {
1532 verticesLibrary.addAll(fragments);
1533 addedOne = true;
1534
1535 // Display the first
1536 if (libFromScrtch)
1537 {
1538 currVrtxIdx = 0;
1539 }
1540 else if (addedOne)
1541 {
1542 currVrtxIdx = firstOfNew;
1543 }
1545
1546 // Update the fragment spinner
1548 } else {
1549 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1550 JOptionPane.showMessageDialog(this,
1551 "<html>No vertices to import from the given list.</html>",
1552 "Error",
1553 JOptionPane.PLAIN_MESSAGE,
1554 UIManager.getIcon("OptionPane.errorIcon"));
1555 }
1556 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1557 }
1558
1559
1560//-----------------------------------------------------------------------------
1561
1570 {
1571 if (verticesLibrary == null)
1572 {
1573 JOptionPane.showMessageDialog(this,
1574 "No list of building blocks loaded.",
1575 "Error",
1576 JOptionPane.PLAIN_MESSAGE,
1577 UIManager.getIcon("OptionPane.errorIcon"));
1578 return;
1579 }
1580
1582
1585 if (vertex == null || vertex instanceof Fragment == false)
1586 {
1587 btnDelSel.setEnabled(false);
1588 btnAtmToAP.setEnabled(false);
1589 btnBondToAPPair.setEnabled(false);
1590 } else {
1591 btnDelSel.setEnabled(true);
1592 btnAtmToAP.setEnabled(true);
1593 btnBondToAPPair.setEnabled(true);
1594 }
1595 }
1596
1597//-----------------------------------------------------------------------------
1598
1599 private void clearCurrentSystem()
1600 {
1601 // Get rid of currently loaded mol
1602 vertex = null;
1604 }
1605
1606//-----------------------------------------------------------------------------
1607
1609 {
1610 navigSpinner.setModel(new SpinnerNumberModel(currVrtxIdx+1, 1,
1611 verticesLibrary.size(), 1));
1612 totalVrtxsLabel.setText(Integer.toString(verticesLibrary.size()));
1613 }
1614
1615//-----------------------------------------------------------------------------
1616
1626 private boolean convertAtomToAP(IAtom trgAtm, String ruleAndSubClass)
1627 {
1628 if (!(vertex instanceof Fragment))
1629 {
1630 return false;
1631 }
1632 Fragment frag = (Fragment) vertex;
1633 // Accept ONLY if the atom has one and only one connected neighbour
1634 if (frag.getConnectedAtomsCount(trgAtm) != 1)
1635 {
1636 String str = "";
1637 for (IAtom atm : frag.getConnectedAtomsList(trgAtm))
1638 {
1639 str = str + " " + atm.getSymbol()
1640 + (frag.indexOf(atm));
1641 }
1642 System.out.println("Connected atoms: "+str);
1643
1644 JOptionPane.showMessageDialog(this,
1645 "<html>Atom "+ trgAtm.getSymbol()
1646 + (frag.indexOf(trgAtm))
1647 + " has zero or more than one neighbour.<br>I can only "
1648 + "transform atoms"
1649 + " that have one and only one neighbour.</html>",
1650 "Error",
1651 JOptionPane.ERROR_MESSAGE,
1652 UIManager.getIcon("OptionPane.errorIcon"));
1653 return false;
1654 }
1655
1656 IAtom srcAtm = frag.getConnectedAtomsList(trgAtm).get(0);
1657 BondType bt = BondType.valueOf(
1658 srcAtm.getBond(trgAtm).getOrder().toString());
1659
1660 Point3d srcP3d = MoleculeUtils.getPoint3d(srcAtm);
1661 Point3d trgP3d = MoleculeUtils.getPoint3d(trgAtm);
1662 Point3d vector = new Point3d();
1663 vector.x = srcP3d.x + (trgP3d.x - srcP3d.x);
1664 vector.y = srcP3d.y + (trgP3d.y - srcP3d.y);
1665 vector.z = srcP3d.z + (trgP3d.z - srcP3d.z);
1666
1667 //NB: assumption of validity!
1668 String[] parts = ruleAndSubClass.split(
1670 try {
1671 // NB: here we change the bond type to make it fit with the one we
1672 // have in the molecular model.
1673 frag.addAPOnAtom(srcAtm, APClass.make(parts[0],
1674 Integer.parseInt(parts[1]), bt), vector);
1675 } catch (DENOPTIMException e) {
1676 e.printStackTrace();
1677 JOptionPane.showMessageDialog(this,
1678 "<html>Could not make AP.<br>Possible cause: "
1679 + e.getMessage() +"</html>",
1680 "Error",
1681 JOptionPane.ERROR_MESSAGE,
1682 UIManager.getIcon("OptionPane.errorIcon"));
1683 return false;
1684 }
1685 return true;
1686 }
1687
1688//----------------------------------------------------------------------------
1689
1690 private void removeAtoms(ArrayList<IAtom> atmsToDels)
1691 {
1692 if (!(vertex instanceof Fragment))
1693 {
1694 return;
1695 }
1696 Fragment frag = (Fragment) vertex;
1697 ArrayList<IBond> bnsToDel = new ArrayList<IBond>();
1698 for (IAtom atm : atmsToDels)
1699 {
1700 for (IBond bnd : frag.bonds())
1701 {
1702 if (bnd.contains(atm))
1703 {
1704 bnsToDel.add(bnd);
1705 }
1706 }
1707 }
1708 for (IBond bnd : bnsToDel)
1709 {
1710 frag.removeBond(bnd);
1711 }
1712 for (IAtom atm : atmsToDels)
1713 {
1714 if (atm.getProperty(DENOPTIMConstants.ATMPROPAPS)!=null)
1715 {
1716 ArrayList<AttachmentPoint> apsOnAtm = frag.getAPsFromAtom(atm);
1717 frag.getAttachmentPoints().removeAll(apsOnAtm);
1718 }
1719 frag.removeAtom(atm);
1720 }
1721 frag.updateAPs();
1722 }
1723
1724//-----------------------------------------------------------------------------
1725
1726 private class VrtxSpinnerChangeEvent implements ChangeListener
1727 {
1728 private boolean inEnabled = true;
1729
1731 {}
1732
1738 public void setEnabled(boolean var)
1739 {
1740 this.inEnabled = var;
1741 }
1742
1743 @Override
1744 public void stateChanged(ChangeEvent event)
1745 {
1746 if (!inEnabled)
1747 {
1748 return;
1749 }
1750
1752
1753 //NB here we convert from 1-based index in GUI to 0-based index
1754 currVrtxIdx = ((Integer) navigSpinner.getValue()).intValue() - 1;
1756
1758 }
1759 }
1760
1761//-----------------------------------------------------------------------------
1762
1764 {
1765 //btnSaveEdits.setEnabled(false);
1766 btnAddVrtx.setEnabled(true);
1767 btnOpenVrtxs.setEnabled(true);
1768 btnOpenSMILES.setEnabled(true);
1769 btnOpenMol.setEnabled(true);
1770 btnEmptFrag.setEnabled(true);
1771 if (vertex == null || vertex instanceof Fragment == false)
1772 {
1773 btnDelSel.setEnabled(false);
1774 btnAtmToAP.setEnabled(false);
1775 btnBondToAPPair.setEnabled(false);
1776 } else {
1777 btnDelSel.setEnabled(true);
1778 btnAtmToAP.setEnabled(true);
1779 btnBondToAPPair.setEnabled(true);
1780 }
1781
1782 ((DefaultEditor) navigSpinner.getEditor())
1783 .getTextField().setEditable(true);
1784 ((DefaultEditor) navigSpinner.getEditor())
1785 .getTextField().setForeground(Color.BLACK);
1788
1790 }
1791
1792//-----------------------------------------------------------------------------
1793
1794 private void protectEditedSystem()
1795 {
1796 btnSaveEdits.setEnabled(true);
1797 btnAddVrtx.setEnabled(false);
1798 btnOpenVrtxs.setEnabled(false);
1799 btnOpenSMILES.setEnabled(false);
1800 btnOpenMol.setEnabled(false);
1801 btnEmptFrag.setEnabled(false);
1802 //btnDelSel.setEnabled(false);
1803 //btnAtmToAP.setEnabled(false);
1804
1805 navigSpinner.setModel(new SpinnerNumberModel(currVrtxIdx+1,
1806 currVrtxIdx+1, currVrtxIdx+1, 1));
1807 ((DefaultEditor) navigSpinner.getEditor())
1808 .getTextField().setEditable(false);
1809 ((DefaultEditor) navigSpinner.getEditor())
1810 .getTextField().setForeground(Color.GRAY);
1811
1813
1815 }
1816
1817//-----------------------------------------------------------------------------
1818
1819 private void activateTabEditsListener(boolean var)
1820 {
1822 }
1823
1824//-----------------------------------------------------------------------------
1825
1827 {
1829 {
1830 String[] options = new String[]{"Yes","No"};
1831 int res = JOptionPane.showOptionDialog(this,
1832 "<html>Removing unsaved vertex?",
1833 "Warning",
1834 JOptionPane.DEFAULT_OPTION,
1835 JOptionPane.QUESTION_MESSAGE,
1836 UIManager.getIcon("OptionPane.warningIcon"),
1837 options,
1838 options[1]);
1839 if (res == 1)
1840 {
1841 return;
1842 }
1843 }
1844
1846
1847 // Actual removal from the library
1848 if (verticesLibrary.size()>0)
1849 {
1851 int libSize = verticesLibrary.size();
1852
1853 if (currVrtxIdx>=0 && currVrtxIdx<libSize)
1854 {
1855 //we keep currFrgIdx as it will correspond to the next item
1856 }
1857 else
1858 {
1860 }
1861
1862 if (currVrtxIdx==-1 || verticesLibrary.size()==0)
1863 {
1864 // The viewer gets hidden so we do not need to clear it
1865 // with 'zap' (which is a very slow operation)
1867 currVrtxIdx = 0;
1868 navigSpinner.setModel(new SpinnerNumberModel(0,0,0,1));
1869 totalVrtxsLabel.setText(Integer.toString(0));
1871 }
1872 else
1873 {
1876 navigSpinner.setModel(new SpinnerNumberModel(currVrtxIdx+1, 1,
1877 verticesLibrary.size(), 1));
1879 }
1880 }
1881 }
1882
1883//-----------------------------------------------------------------------------
1884
1885 private void saveUnsavedChanges()
1886 {
1887 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1888
1890 {
1891 DefaultTableModel tabModel = vertexViewer.getAPTableModel();
1892 // Import changes from AP table into molecular representation
1893 for (int i=0; i<tabModel.getRowCount(); i++)
1894 {
1895 int apId = ((Integer) tabModel.getValueAt(i, 0)).intValue();
1896 String currApClass = tabModel.getValueAt(i, 1).toString();
1897
1898 // Make sure the new class has a proper syntax
1899 GUIAPClassDefinitionDialog apcDefiner =
1901 apcDefiner.setTitle("Confirm APClass on AP #"+i);
1902 apcDefiner.setPreDefinedAPClass(currApClass);
1903 Object chosen = apcDefiner.showDialog();
1904 if (chosen != null)
1905 {
1906 Object[] pair = (Object[]) chosen;
1907 currApClass = pair[0].toString();
1908 } else {
1909 currApClass = "dafaultAPClass:0";
1910 }
1911
1912 Map<Integer, AttachmentPoint> mapAPs =
1914
1915 if (mapAPs.containsKey(apId))
1916 {
1917 String origApClass = mapAPs.get(apId).getAPClass().toString();
1918 if (!origApClass.equals(currApClass))
1919 {
1920 try {
1921 mapAPs.get(apId).setAPClass(currApClass);
1922 } catch (DENOPTIMException e) {
1923 // We made sure the class is valid, so this
1924 // should never happen, though one never knows
1925 e.printStackTrace();
1926 JOptionPane.showMessageDialog(btnSaveEdits,
1927 "<html>Could not save due to errors setting a "
1928 + "new APClass.<br>Please report this to the "
1929 + "DENOPTIM team.</html>",
1930 "Error",
1931 JOptionPane.PLAIN_MESSAGE,
1932 UIManager.getIcon("OptionPane.errorIcon"));
1933 return;
1934 }
1935 }
1936 }
1937 else
1938 {
1939 JOptionPane.showMessageDialog(btnSaveEdits,
1940 "<html>Could not save due to mistmatch between AP "
1941 + "table and map.<br>Please report this to the "
1942 + "DENOPTIM team.</html>",
1943 "Error",
1944 JOptionPane.PLAIN_MESSAGE,
1945 UIManager.getIcon("OptionPane.errorIcon"));
1946 return;
1947 }
1948 }
1949 }
1950
1951 // Retrieve chemical object from the viewer, if edited, otherwise
1952 // we get what is already in 'vertex'
1954 if (verticesLibrary.size()==0
1955 && (vertex==null || vertex.getNumberOfAPs()==0))
1956 {
1957 //Nothing to same
1958 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1959 return;
1960 }
1962
1963 // Reload fragment from library to refresh table and viewer
1965 try {
1967 } catch (Throwable t) {
1968 //This can happen if the viewer has been started but is empty
1969 // E.G:, if the cactvs server is down).
1970 // We just keep going, and make sure we get the default cursor back.
1971 }
1972 // Release constraints
1974 navigSpinner.setModel(new SpinnerNumberModel(currVrtxIdx+1, 1,
1975 verticesLibrary.size(), 1));
1977
1978 this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1979 }
1980
1981//----------------------------------------------------------------------------
1982
1991 public static List<APClass> choseOrCreateNewAPClass(JComponent parent,
1992 boolean singleSelection)
1993 {
1994 return choseOrCreateNewAPClass(parent, singleSelection, "Choose APClasses to Add");
1995 }
1996
1997//----------------------------------------------------------------------------
1998
2008 public static List<APClass> choseOrCreateNewAPClass(JComponent parent,
2009 boolean singleSelection, String title)
2010 {
2011 // To facilitate selection of existing APCs we offer a list...
2012 DefaultListModel<String> apClassLstModel =
2013 new DefaultListModel<String>();
2014 JList<String> apClassList = new JList<String>(apClassLstModel);
2015 for (String apc : APClass.getAllAPClassesAsString())
2016 {
2017 apClassLstModel.addElement(apc);
2018 }
2019 //...and to the list we add the option to create a new APClass.
2020 apClassLstModel.addElement(
2021 "<html><b><i>Define a new APClass...<i></b></html>");
2022 if (singleSelection)
2023 {
2024 apClassList.setSelectionMode(
2025 ListSelectionModel.SINGLE_SELECTION);
2026 } else {
2027 apClassList.setSelectionMode(
2028 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
2029 }
2030 if (apClassList.getModel().getSize() == 1)
2031 {
2032 apClassList.setSelectedIndex(0);
2033 } else {
2034 apClassList.setSelectedIndex(apClassLstModel.getSize()-1);
2035 }
2036
2037 //Make and launch dialog for the user to make the selection
2038 JPanel chooseApPanel = new JPanel();
2039 JLabel header = new JLabel("Choose APClass:");
2040 JScrollPane apClassScroll = new JScrollPane(apClassList);
2041 chooseApPanel.add(header);
2042 chooseApPanel.add(apClassScroll);
2043
2044 int res = JOptionPane.showConfirmDialog(parent,
2045 chooseApPanel,
2046 title,
2047 JOptionPane.OK_CANCEL_OPTION,
2048 JOptionPane.PLAIN_MESSAGE,
2049 null);
2050 if (res != JOptionPane.OK_OPTION)
2051 {
2052 return new ArrayList<APClass>();
2053 }
2054
2055 // Interpret the selection made by the user
2056 ArrayList<APClass> selectedSPCs = new ArrayList<APClass>();
2057 int[] selectedIds = apClassList.getSelectedIndices();
2058 if (selectedIds.length > 0)
2059 {
2060 for (int ii=0; ii<selectedIds.length; ii++)
2061 {
2062 APClass apc = null;
2063 Integer idAPC = selectedIds[ii];
2064
2065 try {
2066 if (idAPC.intValue() == (apClassLstModel.size()-1))
2067 {
2068 // We chose to create a new class
2069 GUIAPClassDefinitionDialog apcDefiner =
2070 new GUIAPClassDefinitionDialog(parent, false);
2071 Object chosen = apcDefiner.showDialog();
2072 if (chosen != null)
2073 {
2074 Object[] pair = (Object[]) chosen;
2075 apc = APClass.make(pair[0].toString(),
2076 (BondType) pair[1]);
2077 }
2078 } else {
2079 apc = APClass.make(apClassLstModel.getElementAt(idAPC));
2080 }
2081 } catch (Exception e1) {
2082 // We have pressed cancel or closed the dialog: abandon
2083 continue;
2084 }
2085 selectedSPCs.add(apc);
2086 }
2087 }
2088 return selectedSPCs;
2089 }
2090
2091//-----------------------------------------------------------------------------
2092
2101 public static String ensureGoodAPRuleString(String currApRule,
2102 String title, boolean mustReply, JComponent parent)
2103 throws DENOPTIMException
2104 {
2105 String preStr = "";
2106 while (!APClass.isValidAPRuleString(currApRule))
2107 {
2108 if (currApRule != "")
2109 {
2110 preStr = "APRule '" + currApRule + "' is not valid!<br>"
2111 + "The valid syntax for APClass is:<br><br><code>APRule"
2112 + DENOPTIMConstants.SEPARATORAPPROPSCL
2113 + "subClass</code><br><br> where "
2114 + "<ul><li><code>APRule</code>"
2115 + " is the string you should provide now, and is "
2116 + "typically any string with no spaces,</li>"
2117 + "<li><code>subClass</code> is an integer.</ul>";
2118 }
2119
2120 currApRule = JOptionPane.showInputDialog(parent,String.format(
2121 "<html><body width='%1s'>" + preStr
2122 + " Please, provide a valid APClass rule string: </html>",
2123 300),
2124 title,
2125 JOptionPane.PLAIN_MESSAGE);
2126
2127 if (currApRule == null)
2128 {
2129 currApRule = "";
2130 if (!mustReply)
2131 {
2132 throw new DENOPTIMException();
2133 }
2134 }
2135 }
2136
2137 return currApRule;
2138 }
2139
2140//-----------------------------------------------------------------------------
2141
2147 public boolean hasUnsavedChanges()
2148 {
2149 return unsavedChanges;
2150 }
2151
2152//-----------------------------------------------------------------------------
2153
2154 /*
2155 * This is needed to stop Jmol threads upon closure of this gui card.
2156 */
2157 public void dispose()
2158 {
2160 }
2161
2162//-----------------------------------------------------------------------------
2163
2164}
General set of constants used in DENOPTIM.
static final String ATMPROPAPS
String tag of Atom property used to store attachment points.
static final String APSTAG
SDF tag defining attachment points.
static final String SEPARATORAPPROPSCL
Separator between APClass and APSubClass and coordinates.
A file with a conventional representation of its format.
static void addToRecentFiles(String fileName, FileFormat ff)
Appends an entry to the list of recent files.
Definition: FileUtils.java:67
static List< Vertex > fragmentation(IAtomContainer mol, FragmenterParameters settings)
Performs fragmentation according to the given settings.
static List< String > getAllAPClassesAsString()
Returns the list of the names of all APClasses.
Definition: APClass.java:331
static boolean isValidAPRuleString(String s)
Evaluates the given string as a candidate attachment point rule, i.e., as name of a fragmentation rul...
Definition: APClass.java:424
static APClass make(String ruleAndSubclass)
Creates an APClass if it does not exist already, or returns the reference to the existing instance.
Definition: APClass.java:164
An empty vertex has the behaviors of a vertex, but has no molecular structure.
Class representing a continuously connected portion of chemical object holding attachment points.
Definition: Fragment.java:61
IBond removeBond(int position)
Definition: Fragment.java:878
List< IAtom > getConnectedAtomsList(IAtom atom)
Definition: Fragment.java:943
AttachmentPoint addAPOnAtom(IAtom srcAtm, APClass apc, Point3d vector)
Add an attachment point to the specifies atom.
Definition: Fragment.java:424
List< AttachmentPoint > getAttachmentPoints()
Definition: Fragment.java:1141
ArrayList< AttachmentPoint > getAPsFromAtom(IAtom srcAtm)
Definition: Fragment.java:455
void removeAtom(IAtom atom)
Definition: Fragment.java:899
void updateAPs()
Changes the properties of each APs as to reflect the current atom list.
Definition: Fragment.java:511
Iterable< IBond > bonds()
Definition: Fragment.java:829
int getConnectedAtomsCount(IAtom atom)
Definition: Fragment.java:950
int indexOf(IAtom atom)
Definition: Fragment.java:850
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:61
abstract IAtomContainer getIAtomContainer()
Standardised horizontal bar with padded components, which are meant to be JButtons.
Definition: ButtonsBar.java:36
Component add(Component comp)
Definition: ButtonsBar.java:53
A modal dialog to define parameters for fragmentation and fragment filtering.
void setPreDefinedAPClass(String text)
Sets the content of the text field with the given predefined text.
A dialog window meant only to select atoms one or multiple times.
Remove the card from the deck of cards and takes care of removing also the entry in the list of activ...
Class of GUI panels meant to occupy one card in the deck-of-cards layout of the main panel.
GUIMainPanel mainPanel
The main panel (cards deck)
File opener for DENOPTIM GUI.
static File pickFile(Component parent)
GUI component to provide pathname where to save stuff.
static FileAndFormat pickFileForSavingVertexes(Component parent)
The main panel is a deck of cards that occupies all the GUI frame.
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.
The collection of tunable preferences.
static File lastCutRulesFile
File with last used cutting rules.
void setEnabled(boolean var)
Enables/disable the listener.
A panel with a viewer capable of visualising DENOPTIM fragments and allows to create and edit fragmen...
static String ensureGoodAPRuleString(String currApRule, String title, boolean mustReply, JComponent parent)
Forces the user to specify a properly formatted APRule, i.e., the first component of an APClass.
ArrayList< Vertex > verticesLibrary
The currently loaded list of fragments.
final VrtxSpinnerChangeEvent vrtxSpinnerListener
Vertex vertex
The currently loaded vertex.
void importStructureFromSMILES(String smiles)
Imports the given SMILES into the viewer.
static AtomicInteger prepVrtxTabUID
Unique identified for instances of this inspector.
void importVerticesFromFile(File file)
Imports fragments from a file.
void importVertices(List< Vertex > fragments)
Imports vertices.
boolean convertAtomToAP(IAtom trgAtm, String ruleAndSubClass)
Removes an atom and replaces it with an attachment point.
boolean unsavedChanges
Flag signaling that loaded data has changes since last save.
int currVrtxIdx
The index of the currently loaded fragment [0–(n-1)}.
boolean hasUnsavedChanges()
Check whether there are unsaved changes.
static List< APClass > choseOrCreateNewAPClass(JComponent parent, boolean singleSelection)
Runs a dialog aimed at selecting an existing APClass or defining a new one.
GUIVertexInspector(GUIMainPanel mainPanel)
Constructor.
void initialize()
Initialize the panel and add buttons.
void loadCurrentVrtxIdxToViewer()
Loads the fragments corresponding to the field index.
void removeAtoms(ArrayList< IAtom > atmsToDels)
static final long serialVersionUID
Version UID.
static boolean dialogToDefineCuttingRules(FragmenterParameters settings, ClassLoader classLoader, Component parent, boolean setMolToGraphSettings)
Starts a dialog to define the on-the-fly fragmentation settings.
static List< APClass > choseOrCreateNewAPClass(JComponent parent, boolean singleSelection, String title)
Runs a dialog aimed at selecting an existing APClass or defining a new one.
A modal dialog with a viewer that understands the different types of DENOPTIM vertex and allows to se...
void load(List< Vertex > fragments, int initialId)
Load the list of vertexes to choose from.
void setRequireApSelection(boolean enforced)
Allows to control whether confirming the selection of a vertex without having selected an attachment ...
A panel for visualizing vertices.
void clearCurrentSystem()
Removes the currently visualized molecule and AP table.
boolean hasUnsavedAPEdits()
Check for unsaved edits to the AP data.
DefaultTableModel getAPTableModel()
void activateTabEditsListener(boolean var)
Allows to activate and deactivate the listener.
Map< Integer, AttachmentPoint > getActiveMapAPs()
Returns the map of attachment points in the currently active viewer.
void deprotectEdits()
Overrides the flag signaling unsaved edits to saying that there are no altered data.
void loadVertexToViewer(Vertex v)
Loads the given vertex to this viewer.
Vertex getLoadedStructure()
Returns the currently loaded vertex.
void loadPlainStructure(IAtomContainer mol)
Loads a structure in the Jmol viewer.
boolean loadSMILES(String smiles)
Loads a molecule build from a smiles string.
void setSwitchable(boolean switchable)
Enable/disable switch-able view.
ArrayList< IAtom > getAtomsSelectedFromJMol()
Identifies the atoms that are selected in the Jmol viewer.
void clearMolecularViewer(boolean dataIsComing)
Clears the molecular viewer.
Utility methods for input/output.
static File writeVertexesToFile(File file, FileFormat format, List< Vertex > vertexes)
Writes vertexes to file.
static void readCuttingRules(BufferedReader reader, List< CuttingRule > cutRules, String source)
Read cutting rules from a stream.
static ArrayList< DGraph > readDENOPTIMGraphsFromFile(File inFile)
Reads a list of DGraphs from file.
static ArrayList< Vertex > readVertexes(File file, Vertex.BBType bbt)
Reads Vertexes from any file that can contain such items.
static List< IAtomContainer > readAllAtomContainers(File file)
Returns a single collection with all atom containers found in a file of any format.
Logger getLogger()
Get the name of the program specific logger.
Logger startConsoleLogger(String loggerIdentifier)
Starts a program-specific logger that prints to System.err stream.
Randomizer getRandomizer()
Returns the current program-specific randomizer.
Parameters controlling execution of the fragmenter.
void setFragmentationTmpls(List< DGraph > fragmentationTmpls)
Sets the list of graph templates for fragmentation.
List< CuttingRule > getDefaultCuttingRules()
Get default cutting rules from the class loader of the current class.
Toll to add/remove dummy atoms from linearities or multi-hapto sites.
static void addDummiesOnLinearities(Fragment frag, double angLim)
Append dummy atoms on otherwise linear arrangements of atoms.
Utilities for molecule conversion.
static String getAtomRef(IAtom atm, IAtomContainer mol)
static Point3d getPoint3d(IAtom atm)
Return the 3D coordinates, if present.
Possible chemical bond types an edge can represent.
Definition: Edge.java:305
The type of building block.
Definition: Vertex.java:86
Interface for all vertex viewers that intend to allow selection of attachment points.