$darkmode
DENOPTIM
CompatibilityMatrixForm.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.FlowLayout;
27import java.awt.event.ActionEvent;
28import java.awt.event.ActionListener;
29import java.awt.event.MouseEvent;
30import java.awt.event.MouseListener;
31import java.beans.PropertyChangeEvent;
32import java.beans.PropertyChangeListener;
33import java.beans.PropertyChangeListenerProxy;
34import java.io.File;
35import java.util.ArrayList;
36import java.util.Arrays;
37import java.util.Collections;
38import java.util.HashMap;
39import java.util.HashSet;
40import java.util.List;
41import java.util.Set;
42import java.util.SortedSet;
43import java.util.TreeSet;
44
45import javax.swing.BorderFactory;
46import javax.swing.Box;
47import javax.swing.BoxLayout;
48import javax.swing.DefaultListModel;
49import javax.swing.GroupLayout;
50import javax.swing.JButton;
51import javax.swing.JComponent;
52import javax.swing.JLabel;
53import javax.swing.JList;
54import javax.swing.JOptionPane;
55import javax.swing.JPanel;
56import javax.swing.JScrollPane;
57import javax.swing.JTabbedPane;
58import javax.swing.JTable;
59import javax.swing.JTextField;
60import javax.swing.ListSelectionModel;
61import javax.swing.SwingConstants;
62import javax.swing.UIManager;
63import javax.swing.table.DefaultTableModel;
64
65import denoptim.exception.DENOPTIMException;
66import denoptim.graph.APClass;
67import denoptim.graph.Edge.BondType;
68import denoptim.io.DenoptimIO;
69
70public class CompatibilityMatrixForm extends JPanel {
71
75 private static final long serialVersionUID = -8042143358823563589L;
76
80 protected static final String REMOVETRGAPC = "REMOVETRGAPC";
81
87 private SortedSet<APClass> allAPClasses = new TreeSet<APClass>();
88
93 private SortedSet<String> allAPRules = new TreeSet<String>();
94
100 private SortedSet<APClass> allCapAPClasses = new TreeSet<APClass>();
101
105 private SortedSet<APClass> allAPClsInCPMap = new TreeSet<APClass>();
106
111 private HashMap<APClass, ArrayList<APClass>> compatMap =
112 new HashMap<APClass, ArrayList<APClass>>();
113
118 private HashMap<APClass, APClass> cappingMap =
119 new HashMap<APClass, APClass>();
120
124 private HashSet<APClass> forbiddenEndList = new HashSet<APClass>();
125
126 private JTabbedPane tabbedPane;
127
128 private JPanel panelCPMap;
129 private JButton btnAddCompRul;
130 private JButton btnDelCompRul;
131 private JButton btnCopyCompRul;
132 private JButton btnClearMatch;
133 private JButton btnHelpCPMap;
134 private JPanel panelCPRules;
135 private JScrollPane scrollPanelCPMap;
136 private JTextField txtSearch;
137 private JLabel matchCounter;
138
139 private JPanel panelCapping;
140 private DefaultTableModel tabModCapping;
141 private JTable tableCapping;
142 private JButton btnAddCapping;
143 private JButton btnDelCapping;
144 private JButton btnSortCapping;
145 private JButton btnHelpCapping;
146
147 private JPanel panelFrbEnd;
148 private DefaultTableModel tabModFrbEnd;
149 private JTable tableFrbEnd;
150 private JButton btnAddFrbEnd;
151 private JButton btnDelFrbEnd;
152 private JButton btnSortFrbEnd;
153 private JButton btnHelpFrbEnd;
154
155//-----------------------------------------------------------------------------
156
157 @SuppressWarnings("serial")
159 {
160 this.setLayout(new BorderLayout());
161 tabbedPane = new JTabbedPane(JTabbedPane.TOP);
162 super.add(tabbedPane, BorderLayout.CENTER);
163
164 //
165 // APClass Compatibility rules (i.e., the actual compatibility matrix)
166 //
167
168 panelCPMap = new JPanel(new BorderLayout());
169 tabbedPane.addTab("APClass compatibility",null,panelCPMap,null);
170
171 btnAddCompRul = new JButton("Add Compatibility Rule");
172 btnAddCompRul.setToolTipText("Add compatibility rules for a new "
173 + "source APClass.");
174 btnAddCompRul.addActionListener(new ActionListener() {
175 public void actionPerformed(ActionEvent e) {
176 DefaultListModel<String> sAPCsStr =
177 new DefaultListModel<String>();
178 JList<String> srcClsList = new JList<String>(sAPCsStr);
179 for (APClass apc : allAPClasses)
180 {
181 if (!compatMap.keySet().contains(apc))
182 {
183 sAPCsStr.addElement(apc.toString());
184 }
185 }
186 sAPCsStr.addElement("<html><b><i>Define a new APClass...<i>"
187 + "</b></html>");
188 srcClsList.setSelectionMode(
189 ListSelectionModel.SINGLE_SELECTION);
190 if (srcClsList.getModel().getSize() == 1)
191 {
192 srcClsList.setSelectedIndex(0);
193 }
194
195 DefaultListModel<String> trgAPCs =
196 new DefaultListModel<String>();
197 JList<String> trgClsList = new JList<String>(trgAPCs);
198 for (APClass apc : allAPClasses)
199 {
200 trgAPCs.addElement(apc.toString());
201 }
202 trgAPCs.addElement("<html><b><i>Define a new APClass...<i>"
203 + "</b></html>");
204 trgClsList.setSelectionMode(
205 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
206 if (trgClsList.getModel().getSize() == 1)
207 {
208 trgClsList.setSelectedIndex(0);
209 }
210
211 JPanel twoListsPanel = new JPanel();
212 JLabel headSrc = new JLabel("APClass on the growing graph");
213 JLabel headTrg = new JLabel("APClass on incoming fragment");
214 JScrollPane scrollSrc = new JScrollPane(srcClsList);
215 JScrollPane scrollTrg = new JScrollPane(trgClsList);
216 GroupLayout lyoAddCapRule = new GroupLayout(twoListsPanel);
217 twoListsPanel.setLayout(lyoAddCapRule);
218 lyoAddCapRule.setAutoCreateGaps(true);
219 lyoAddCapRule.setAutoCreateContainerGaps(true);
220 lyoAddCapRule.setHorizontalGroup(
221 lyoAddCapRule.createSequentialGroup()
222 .addGroup(lyoAddCapRule.createParallelGroup()
223 .addComponent(headSrc)
224 .addComponent(scrollSrc))
225 .addGap(30)
226 .addGroup(lyoAddCapRule.createParallelGroup()
227 .addComponent(headTrg)
228 .addComponent(scrollTrg)));
229 lyoAddCapRule.setVerticalGroup(
230 lyoAddCapRule.createSequentialGroup()
231 .addGroup(lyoAddCapRule.createParallelGroup()
232 .addComponent(headSrc)
233 .addGap(10)
234 .addComponent(headTrg))
235 .addGroup(lyoAddCapRule.createParallelGroup()
236 .addComponent(scrollSrc)
237 .addComponent(scrollTrg)));
238
239 int res = JOptionPane.showConfirmDialog(btnAddCompRul,
240 twoListsPanel,
241 "New APClass compatibility rule",
242 JOptionPane.OK_CANCEL_OPTION,
243 JOptionPane.PLAIN_MESSAGE,
244 null);
245
246 if (res != JOptionPane.OK_OPTION)
247 {
248 return;
249 }
250
251 if (trgClsList.getSelectedIndices().length > 0
252 && srcClsList.getSelectedIndices().length > 0)
253 {
254 //NB: we allow a single selection in the src APClass list
255 Integer idSrc = srcClsList.getSelectedIndices()[0];
256
257 APClass srcAPClass = null;
258 if (idSrc.intValue() == (sAPCsStr.size()-1))
259 {
260 try {
261 GUIAPClassDefinitionDialog apcDefiner =
263 btnAddCompRul, true);
264 Object chosen = apcDefiner.showDialog();
265 if (chosen == null)
266 {
267 return;
268 }
269
270 Object[] pair = (Object[]) chosen;
271 srcAPClass = APClass.make(pair[0].toString(),
272 (BondType) pair[1]);
273
274 if (allAPClasses.contains(srcAPClass))
275 {
276 JOptionPane.showMessageDialog(btnAddCompRul,
277 "<html>Class '<code>" + srcAPClass
278 +"</code>' is not new!</html>",
279 "Error",
280 JOptionPane.WARNING_MESSAGE,
281 UIManager.getIcon(
282 "OptionPane.errorIcon"));
283 return;
284 }
285 allAPClasses.add(srcAPClass);
286 allAPRules.add(srcAPClass.getRule());
287 } catch (DENOPTIMException e1) {
288 JOptionPane.showMessageDialog(btnAddCompRul,
289 "<html>Error definging anew APClass.<br>"
290 + "Please, report this to the DENOPTIM "
291 + "team.</html>",
292 "Error",
293 JOptionPane.WARNING_MESSAGE,
294 UIManager.getIcon("OptionPane.errorIcon"));
295 return;
296 }
297 }
298 else
299 {
300 try
301 {
302 srcAPClass = APClass.make(
303 sAPCsStr.getElementAt(idSrc));
304 } catch (DENOPTIMException e1)
305 {
306 // Unreachable thanks to ensureGoodAPClassString()
307 e1.printStackTrace();
308 }
309 }
310
311 ArrayList<APClass> trgCPClasses = new ArrayList<APClass>();
312 for (Integer id : trgClsList.getSelectedIndices())
313 {
314 if (id.intValue() == (trgAPCs.size()-1))
315 {
316 try {
317 GUIAPClassDefinitionDialog apcDefiner =
319 btnAddCompRul, true);
320 Object chosen = apcDefiner.showDialog();
321 if (chosen == null)
322 {
323 return;
324 }
325
326 Object[] pair = (Object[]) chosen;
327 APClass cls = APClass.make(pair[0].toString(),
328 (BondType) pair[1]);
329
330 trgCPClasses.add(cls);
331 allAPClasses.add(cls);
332 allAPRules.add(cls.getRule());
333 } catch (DENOPTIMException e1) {
334 continue;
335 }
336 }
337 else
338 {
339 try
340 {
341 trgCPClasses.add(APClass.make(
342 (String) trgAPCs.getElementAt(id)));
343 } catch (DENOPTIMException e1)
344 {
345 // Unreachable thanks to ensureGoodAPClassString
346 e1.printStackTrace();
347 }
348 }
349 }
350
351 if (compatMap.keySet().contains(srcAPClass))
352 {
353 compatMap.get(srcAPClass).addAll(trgCPClasses);
354 }
355 else
356 {
357 compatMap.put(srcAPClass,trgCPClasses);
358 }
359 allAPClsInCPMap.add(srcAPClass);
360
362 }
363 }
364 });
365
366 btnCopyCompRul = new JButton("Copy Rule");
367 btnCopyCompRul.setToolTipText(String.format("<html><body width='%1s'>"
368 + "<p>Copy all the compatibility rules of a selected source "
369 + "APClass to a new, user-selected source APClass.</p></html>",
370 300));
371 btnCopyCompRul.addActionListener(new ActionListener() {
372 public void actionPerformed(ActionEvent e) {
373 ArrayList<String> selected = new ArrayList<String>();
374 for (Component lineComponent : panelCPRules.getComponents())
375 {
376 if (lineComponent instanceof CompatibilityRuleLine)
377 {
378 if (((CompatibilityRuleLine) lineComponent).isSelected)
379 {
380 selected.add(lineComponent.getName());
381 }
382 }
383 }
384
385 if (selected.size() == 1)
386 {
387 String srcOrig = selected.get(0);
388
389 DefaultListModel<String> srcAPCs =
390 new DefaultListModel<String>();
391 JList<String> srcClsList = new JList<String>(srcAPCs);
392 for (APClass apc : allAPClasses)
393 {
394 if (!compatMap.keySet().contains(apc))
395 {
396 srcAPCs.addElement(apc.toString());
397 }
398 }
399 srcClsList.setSelectionMode(
400 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
401
402 int res = JOptionPane.showConfirmDialog(btnCopyCompRul,
403 new JScrollPane(srcClsList),
404 "New APClass sources",
405 JOptionPane.OK_CANCEL_OPTION,
406 JOptionPane.PLAIN_MESSAGE,
407 null);
408
409 if (res != JOptionPane.OK_OPTION)
410 {
411 return;
412 }
413
414 List<String> selSrc = srcClsList.getSelectedValuesList();
415 if (selSrc.size() > 0)
416 {
417 for (String srcAPClassStr : selSrc)
418 {
419 APClass srcAPClass = null;
420 try
421 {
422 srcAPClass = APClass.make(srcAPClassStr);
423 } catch (DENOPTIMException e1)
424 {
425 //should never happen
426 e1.printStackTrace();
427 }
428 ArrayList<APClass> newTrg =
429 new ArrayList<APClass>();
430 try
431 {
432 newTrg.addAll(compatMap.get(APClass.make(srcOrig)));
433 } catch (DENOPTIMException e1)
434 {
435 // Should not happen
436 e1.printStackTrace();
437 }
438 compatMap.put(srcAPClass,newTrg);
439 allAPClsInCPMap.add(srcAPClass);
440 }
442 }
443 }
444 else
445 {
446 JOptionPane.showMessageDialog(btnCopyCompRul,
447 "<html>Please, select one and only one source "
448 + "APCLasss.</html>",
449 "Error",
450 JOptionPane.WARNING_MESSAGE,
451 UIManager.getIcon("OptionPane.errorIcon"));
452 return;
453 }
454 }
455 });
456
457 btnDelCompRul = new JButton("Remove Selected");
458 btnDelCompRul.setToolTipText(String.format("<html><body width='%1s'>"
459 + "<p>Remove all the compatibility rules of selected "
460 + "source APClasses. Click on the "
461 + "name of a source APClass to select all its compatibility"
462 + "rules. You can select multiple source APClasses."
463 + "</p></html>",
464 300));
465 btnDelCompRul.addActionListener(new ActionListener() {
466 public void actionPerformed(ActionEvent e) {
467 int i = 0;
468 for (Component lineComponent : panelCPRules.getComponents())
469 {
470 if (lineComponent instanceof CompatibilityRuleLine)
471 {
472 if (((CompatibilityRuleLine) lineComponent).isSelected)
473 {
474 try
475 {
476 compatMap.remove(APClass.make(
477 lineComponent.getName()));
479 lineComponent.getName()));
480 panelCPRules.remove(lineComponent);
481 i++;
482 } catch (DENOPTIMException e1)
483 {
484 //This should never happen
485 e1.printStackTrace();
486 }
487 }
488 }
489 }
490
491 if (i > 0)
492 {
494 }
495 else
496 {
497 JOptionPane.showMessageDialog(btnDelCompRul,
498 "<html>Please, click to select at least one source "
499 + "AP CLasss.</html>",
500 "Error",
501 JOptionPane.WARNING_MESSAGE,
502 UIManager.getIcon("OptionPane.errorIcon"));
503 return;
504 }
505 }
506 });
507
508 JButton btnSearch = new JButton("Search");
509 btnSearch.setToolTipText(String.format("<html><body width='%1s'>Search "
510 + "for the given APClass. Matching compatibility rules are "
511 + "selected and highlighted accordingly.</html>",150));
512 btnSearch.addActionListener(new ActionListener() {
513 public void actionPerformed(ActionEvent e) {
514 searchAPClass(txtSearch.getText());
515 }
516 });
517
518 txtSearch = new JTextField();
519 txtSearch.setToolTipText(String.format("<html><body width='%1s'>Type "
520 + "here the APClass name or part of it. The search supports "
521 + "regual expressions and initial and final '(.*)' are added "
522 + "to all queries.",250));
523 txtSearch.addActionListener(new ActionListener() {
524 public void actionPerformed(ActionEvent e) {
525 searchAPClass(txtSearch.getText());
526 }
527 });
528 JScrollPane txtSearchPanel = new JScrollPane(txtSearch,
529 JScrollPane.VERTICAL_SCROLLBAR_NEVER,
530 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
531 txtSearchPanel.getHorizontalScrollBar().setPreferredSize(new Dimension(0,2));
532 txtSearchPanel.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
533
534 matchCounter = new JLabel(" ");
535
536 btnClearMatch = new JButton("Clear");
537 btnClearMatch.setEnabled(false);
538 btnClearMatch.setToolTipText("Clear selection of search hits");
539 btnClearMatch.addActionListener(new ActionListener() {
540 public void actionPerformed(ActionEvent e) {
542 txtSearch.setText("");
543 matchCounter.setText(" ");
544 btnClearMatch.setEnabled(false);
545 }
546 });
547
548
549 btnHelpCPMap = new JButton("?");
550 btnHelpCPMap.setToolTipText("Displays the help message.");
551 btnHelpCPMap.addActionListener(new ActionListener() {
552 public void actionPerformed(ActionEvent e) {
553 String txt = "<html><body width='%1s'><p>Attachment points "
554 + "(APs) can be annotated with information encoded in "
555 + "a string of text, i.e., the attachment point class "
556 + "(APClass). The APClass can be used to define "
557 + "APClass compatibility rules. Namely, whether two "
558 + "attachment point can be used to form a connection "
559 + "between fragment or not. Each rule includes:"
560 + "<ul> "
561 + "<li>the <i>Source APClass</i>, which is the class "
562 + "of the AP on the growing molecule,</li>"
563 + "<li>a list of compatible APClasses, i.e., an AP "
564 + "belonging to any incoming fragment and annotated "
565 + "with any of the compatible APClasses can be chosen "
566 + "to form a bond with any AP annotated with the "
567 + "<i>Source APClass</i>.</li></ul></p></html>";
568 JOptionPane.showMessageDialog(btnHelpCPMap,
569 String.format(txt, 400),
570 "Tips",
571 JOptionPane.PLAIN_MESSAGE);
572 }
573 });
574
575 JPanel panelBtnCPMap = new JPanel();
576 panelBtnCPMap.setLayout(new BoxLayout(panelBtnCPMap, BoxLayout.X_AXIS));
577 panelBtnCPMap.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
578 panelBtnCPMap.add(btnAddCompRul);
579 panelBtnCPMap.add(btnCopyCompRul);
580 panelBtnCPMap.add(btnDelCompRul);
581 panelBtnCPMap.add(btnSearch);
582 panelBtnCPMap.add(txtSearchPanel);
583 panelBtnCPMap.add(matchCounter);
584 panelBtnCPMap.add(btnClearMatch);
585 panelBtnCPMap.add(btnHelpCPMap);
586 panelCPMap.add(panelBtnCPMap, BorderLayout.NORTH);
587
588 panelCPRules = new JPanel();
589 scrollPanelCPMap = new JScrollPane(panelCPRules,
590 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
591 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
592 scrollPanelCPMap.getVerticalScrollBar().setPreferredSize(
593 new Dimension(15,0));
594 panelCPRules.setLayout(new BoxLayout(panelCPRules,
595 SwingConstants.VERTICAL));
596 panelCPMap.add(scrollPanelCPMap, BorderLayout.CENTER);
597
598
599 //
600 // Capping rules
601 //
602 panelCapping = new JPanel(new BorderLayout());
603 tabbedPane.addTab("Capping",null,panelCapping,null);
604
605 String toolTipCapping = String.format("<html><body width='%1s'>"
606 + "Capping rules define the attachment point class (APClass) "
607 + "of the capping group used to saturate unused attachment "
608 + "points of a given APClass that need to be saturated when "
609 + "finalizing the construction of a graph.</html>",300);
610
611 tabModCapping = new DefaultTableModel() {
612 @Override
613 public boolean isCellEditable(int row, int column) {
614 return false;
615 }
616 };
617 tabModCapping.setColumnCount(2);
618 String column_name_fe[]= {"<html><b>APClasses on graph</b></html>",
619 "<html><b>APClasses of Capping Group</b></html>"};
620 tabModCapping.setColumnIdentifiers(column_name_fe);
621 tableCapping = new JTable(tabModCapping);
622 tableCapping.setToolTipText(toolTipCapping);
623
624 btnAddCapping = new JButton("Add Capping Rules");
625 btnAddCapping.setToolTipText("Add new lines to the table");
626 btnAddCapping.addActionListener(new ActionListener() {
627 public void actionPerformed(ActionEvent e) {
628 DefaultListModel<String> srcAPCs =
629 new DefaultListModel<String>();
630 JList<String> srcClsList = new JList<String>(srcAPCs);
631 for (APClass apc : allAPClasses)
632 {
633 if (!cappingMap.keySet().contains(apc))
634 {
635 srcAPCs.addElement(apc.toString());
636 }
637 }
638 srcAPCs.addElement("<html><b><i>Define a new APClass...<i>"
639 + "</b></html>");
640 if (srcClsList.getModel().getSize() == 1)
641 {
642 srcClsList.setSelectedIndex(0);
643 }
644
645 DefaultListModel<String> capAPCs =
646 new DefaultListModel<String>();
647 JList<String> capClsList = new JList<String>(capAPCs);
648 for (APClass apc : allCapAPClasses)
649 {
650 capAPCs.addElement(apc.toString());
651 }
652 capAPCs.addElement("<html><b><i>Define a new APClass...<i>"
653 + "</b></html>");
654 capClsList.setSelectionMode(
655 ListSelectionModel.SINGLE_SELECTION);
656 if (capClsList.getModel().getSize() == 1)
657 {
658 capClsList.setSelectedIndex(0);
659 }
660
661 JPanel twoListsPanel = new JPanel();
662 JLabel headSrc = new JLabel("APClass of APs to be capped:");
663 JLabel headCap = new JLabel("APClass of capping group:");
664 JScrollPane scrollSrc = new JScrollPane(srcClsList);
665 JScrollPane scrollCap = new JScrollPane(capClsList);
666 GroupLayout lyoAddCapRule = new GroupLayout(twoListsPanel);
667 twoListsPanel.setLayout(lyoAddCapRule);
668 lyoAddCapRule.setAutoCreateGaps(true);
669 lyoAddCapRule.setAutoCreateContainerGaps(true);
670 lyoAddCapRule.setHorizontalGroup(lyoAddCapRule.createSequentialGroup()
671 .addGroup(lyoAddCapRule.createParallelGroup()
672 .addComponent(headSrc)
673 .addComponent(scrollSrc))
674 .addGroup(lyoAddCapRule.createParallelGroup()
675 .addComponent(headCap)
676 .addComponent(scrollCap)));
677 lyoAddCapRule.setVerticalGroup(lyoAddCapRule.createSequentialGroup()
678 .addGroup(lyoAddCapRule.createParallelGroup()
679 .addComponent(headSrc)
680 .addComponent(headCap))
681 .addGroup(lyoAddCapRule.createParallelGroup()
682 .addComponent(scrollSrc)
683 .addComponent(scrollCap)));
684
685 int res = JOptionPane.showConfirmDialog(btnAddCapping,
686 twoListsPanel,
687 "Choose APClasses",
688 JOptionPane.OK_CANCEL_OPTION,
689 JOptionPane.PLAIN_MESSAGE,
690 null);
691
692 if (res != JOptionPane.OK_OPTION)
693 {
694 return;
695 }
696
697 if (capClsList.getSelectedIndices().length > 0
698 && srcClsList.getSelectedIndices().length > 0)
699 {
700 //NB: we allow a single selection in the cap APClass list
701 Integer idc = capClsList.getSelectedIndices()[0];
702 APClass cappingAPClass = null;
703 if (idc.intValue() == (capAPCs.size()-1))
704 {
705 try {
706 GUIAPClassDefinitionDialog apcDefiner =
708 btnAddCapping, true);
709 Object chosen = apcDefiner.showDialog();
710 if (chosen == null)
711 {
712 return;
713 }
714
715 Object[] pair = (Object[]) chosen;
716 cappingAPClass = APClass.make(pair[0].toString(),
717 (BondType) pair[1]);
718
719 if (allAPClasses.contains(cappingAPClass))
720 {
721 JOptionPane.showMessageDialog(btnAddCapping,
722 "<html>Class '<code>" + cappingAPClass
723 +"</code>' is not new!</html>",
724 "Error",
725 JOptionPane.WARNING_MESSAGE,
726 UIManager.getIcon("OptionPane.errorIcon"));
727 return;
728 }
729 allAPClasses.add(cappingAPClass);
730 allAPRules.add(cappingAPClass.getRule());
731 } catch (DENOPTIMException e1) {
732 JOptionPane.showMessageDialog(btnAddCapping,
733 "<html>Error definging a new APClass.<br>"
734 + "Please, report this to the DENOPTIM "
735 + "team.</html>",
736 "Error",
737 JOptionPane.WARNING_MESSAGE,
738 UIManager.getIcon("OptionPane.errorIcon"));
739 return;
740 }
741 }
742 else
743 {
744 try
745 {
746 cappingAPClass = APClass.make(
747 (String) capAPCs.getElementAt(idc));
748 } catch (DENOPTIMException e1)
749 {
750 //this should never happen
751 e1.printStackTrace();
752 }
753 }
754
755 for (Integer id : srcClsList.getSelectedIndices())
756 {
757 if (id.intValue() == (srcAPCs.size()-1))
758 {
759 try {
760 GUIAPClassDefinitionDialog apcDefiner =
762 btnAddCapping, true);
763 Object chosen = apcDefiner.showDialog();
764 if (chosen == null)
765 {
766 return;
767 }
768
769 Object[] pair = (Object[]) chosen;
770 APClass newAPC = APClass.make(pair[0].toString(),
771 (BondType) pair[1]);
772
773 if (allAPClasses.contains(newAPC))
774 {
775 JOptionPane.showMessageDialog(btnAddCapping,
776 "<html>Class '<code>" + newAPC
777 +"</code>' is not new!</html>",
778 "Error",
779 JOptionPane.WARNING_MESSAGE,
780 UIManager.getIcon("OptionPane.errorIcon"));
781 return;
782 }
783 tabModCapping.addRow(new Object[]{newAPC,
784 cappingAPClass});
785 cappingMap.put(newAPC,cappingAPClass);
786 allAPClasses.add(newAPC);
787 allAPRules.add(newAPC.getRule());
788 } catch (DENOPTIMException e1) {
789 continue;
790 }
791 }
792 else
793 {
794 APClass srcAPClass = null;
795 try
796 {
797 srcAPClass = APClass.make(
798 (String) srcAPCs.getElementAt(id));
799 } catch (DENOPTIMException e1)
800 {
801 //this should never happen
802 e1.printStackTrace();
803 }
804 tabModCapping.addRow(new Object[]{srcAPClass,
805 cappingAPClass});
806 cappingMap.put(srcAPClass,cappingAPClass);
807 }
808 }
809 }
810 }
811 });
812
813 btnDelCapping = new JButton("Remove Selected");
814 btnDelCapping.setToolTipText(String.format("<html><body width='%1s'>"
815 + "Remove all the selected "
816 + "lines in the list. Click on one or more lines to select "
817 + "them. Multiple lines can be selected by holding the "
818 + "appropriate key (e.g., <code>shift</code>, "
819 + "<code>alt</code>, <code>ctrl</code>, <code>cmd</code> "
820 + "depending on your keyboard settings).</html>",250));
821 btnDelCapping.addActionListener(new ActionListener() {
822 public void actionPerformed(ActionEvent e) {
823 if (tableCapping.getRowCount() > 0)
824 {
825 if (tableCapping.getSelectedRowCount() > 0)
826 {
827 int selectedRowIds[] = tableCapping.getSelectedRows();
828 Arrays.sort(selectedRowIds);
829 for (int i=(selectedRowIds.length-1); i>-1; i--)
830 {
831 APClass apc = null;
832 try
833 {
834 apc = APClass.make(tableCapping.getValueAt(
835 selectedRowIds[i], 0).toString());
836 } catch (DENOPTIMException e1)
837 {
838 //Nothing to do: this should never happen here
839 e1.printStackTrace();
840 }
841 cappingMap.remove(apc);
842 tabModCapping.removeRow(selectedRowIds[i]);
843 }
844 }
845 }
846 }
847 });
848
849 btnSortCapping = new JButton("Sort List");
850 btnSortCapping.setToolTipText("Sorts according to alphabetic order.");
851 btnSortCapping.addActionListener(new ActionListener() {
852 public void actionPerformed(ActionEvent e) {
854 }
855 });
856
857 btnHelpCapping = new JButton("?");
858 btnHelpCapping.setToolTipText("Displays the help message.");
859 btnHelpCapping.addActionListener(new ActionListener() {
860 public void actionPerformed(ActionEvent e) {
861 String txt = "<html><body width='%1s'><p>Capping rules are "
862 + "used to saturate free attachment points (APs) when "
863 + "finalizing the construction of a graph. Since APs "
864 + "are often (but not always) the representation of "
865 + "open valences, the capping procedure serves to "
866 + "saturate all open valences according to AP's "
867 + "compatibility. This procedure follows the capping "
868 + "rules defined in this table.</p>"
869 + "<br>"
870 + "<p>Each capping "
871 + "rule (i.e., each line in this table) identifies "
872 + "the combination of two attachment point classes "
873 + "(APClasses): "
874 + "<ul>"
875 + "<li>APCLass of the attachment points to be "
876 + "capped (first column).</li>"
877 + "<li>APClass of the capping group used to "
878 + "saturate APs above attachment points.</li>"
879 + "</ul></p><br>"
880 + "<p>You can select multiple entries as intervals or "
881 + "by multiple clicks while holding the appropriate "
882 + "key (e.g., <code>shift</code>, <code>alt</code>, "
883 + "<code>ctrl</code>, "
884 + "<code>cmd</code> depending on your keyboard "
885 + "settings).</p></html>";
886 JOptionPane.showMessageDialog(btnHelpCapping,
887 String.format(txt, 400),
888 "Tips",
889 JOptionPane.PLAIN_MESSAGE);
890 }
891 });
892
893 JPanel panelBtnCapping = new JPanel(new FlowLayout(FlowLayout.LEFT));
894 panelBtnCapping.add(btnAddCapping);
895 panelBtnCapping.add(btnDelCapping);
896 panelBtnCapping.add(btnSortCapping);
897 panelBtnCapping.add(btnHelpCapping);
898 panelCapping.add(panelBtnCapping, BorderLayout.NORTH);
899
900 JScrollPane panelCappingTable = new JScrollPane(tableCapping);
901 panelCapping.add(panelCappingTable, BorderLayout.CENTER);
902
903 //
904 // Forbidden ends panel
905 //
906 panelFrbEnd = new JPanel(new BorderLayout());
907 tabbedPane.addTab("Forbidden ends",null,panelFrbEnd,null);
908
909 String toolTipFrbEnd = String.format("<html><body width='%1s'>Graphs "
910 + "holding free "
911 + "(i.e., unsaturated) attachment point with these "
912 + "APClasses are considered incomplete and are not "
913 + "submitted to fitness evaluation.</html>",300);
914
915 tabModFrbEnd = new DefaultTableModel() {
916 @Override
917 public boolean isCellEditable(int row, int column) {
918 return false;
919 }
920 };
921 tabModFrbEnd.setColumnCount(1);
922 String column_name_cap[]= {"<html><b>APClasses defining the forbidden "
923 + "ends:</b></html>"};
924 tabModFrbEnd.setColumnIdentifiers(column_name_cap);
925 tableFrbEnd = new JTable(tabModFrbEnd);
926 tableFrbEnd.setToolTipText(toolTipFrbEnd);
927
928 btnAddFrbEnd = new JButton("Add Forbidden End Rules");
929 btnAddFrbEnd.setToolTipText("Define a new forbidden end and add it to "
930 + "the list.");
931 btnAddFrbEnd.addActionListener(new ActionListener() {
932 public void actionPerformed(ActionEvent e) {
933 DefaultListModel<String> claLstModel =
934 new DefaultListModel<String>();
935 JList<String> clsList = new JList<String>(claLstModel);
936 for (APClass apc : allAPClasses)
937 {
938 if (!forbiddenEndList.contains(apc))
939 {
940 claLstModel.addElement(apc.toString());
941 }
942 }
943 claLstModel.addElement("<html><b><i>Define a new APClass..."
944 + " <i>"
945 + "</b></html>");
946 if (clsList.getModel().getSize() == 1)
947 {
948 clsList.setSelectedIndex(0);
949 }
950
951 int res = JOptionPane.showConfirmDialog(btnAddFrbEnd,
952 new JScrollPane(clsList),
953 "Choose APClasses",
954 JOptionPane.OK_CANCEL_OPTION,
955 JOptionPane.PLAIN_MESSAGE,
956 null);
957
958 if (res != JOptionPane.OK_OPTION)
959 {
960 return;
961 }
962
963 for (Integer id : clsList.getSelectedIndices())
964 {
965 if (id.intValue() == (claLstModel.size()-1))
966 {
967 try {
968 GUIAPClassDefinitionDialog apcDefiner =
970 btnAddFrbEnd, true);
971 Object chosen = apcDefiner.showDialog();
972 if (chosen == null)
973 {
974 return;
975 }
976
977 Object[] pair = (Object[]) chosen;
978 APClass newAPC = APClass.make(pair[0].toString(),
979 (BondType) pair[1]);
980
981 if (allAPClasses.contains(newAPC))
982 {
983 JOptionPane.showMessageDialog(btnAddFrbEnd,
984 "<html>Class '<code>" + newAPC
985 +"</code>' is not new!</html>",
986 "Error",
987 JOptionPane.WARNING_MESSAGE,
988 UIManager.getIcon("OptionPane.errorIcon"));
989 return;
990 }
991 tabModFrbEnd.addRow(new Object[]{newAPC});
992 forbiddenEndList.add(newAPC);
993 allAPClasses.add(newAPC);
994 allAPRules.add(newAPC.getRule());
995 } catch (DENOPTIMException e1) {
996 continue;
997 }
998 }
999 else
1000 {
1001 APClass apClass = null;
1002 try
1003 {
1004 apClass = APClass.make(
1005 (String) claLstModel.getElementAt(id));
1006 } catch (DENOPTIMException e1)
1007 {
1008 //this should never happen
1009 e1.printStackTrace();
1010 }
1011 tabModFrbEnd.addRow(new Object[]{apClass});
1012 forbiddenEndList.add(apClass);
1013 }
1014 }
1015 }
1016 });
1017
1018 btnDelFrbEnd = new JButton("Remove Selected");
1019 btnDelFrbEnd.setToolTipText(String.format("<html><body width='%1s'>"
1020 + "Remove all the selected "
1021 + "lines in the list. Click on one or more lines to select "
1022 + "them. Multiple lines can be selected by holding the "
1023 + "appropriate key (e.g., <code>shift</code>, "
1024 + "<code>alt</code>, <code>ctrl</code>, <code>cmd</code> "
1025 + "depending on your keyboard settings).</html>",250));
1026 btnDelFrbEnd.addActionListener(new ActionListener() {
1027 public void actionPerformed(ActionEvent e) {
1028 if (tableFrbEnd.getRowCount() > 0)
1029 {
1030 if (tableFrbEnd.getSelectedRowCount() > 0)
1031 {
1032 int selectedRowIds[] = tableFrbEnd.getSelectedRows();
1033 Arrays.sort(selectedRowIds);
1034 for (int i=(selectedRowIds.length-1); i>-1; i--)
1035 {
1036 forbiddenEndList.remove(tableFrbEnd.getValueAt(
1037 selectedRowIds[i], 0));
1038 tabModFrbEnd.removeRow(selectedRowIds[i]);
1039 }
1040 }
1041 }
1042 }
1043 });
1044
1045 btnSortFrbEnd = new JButton("Sort List");
1046 btnSortFrbEnd.setToolTipText("Sorts according to alphabetic order.");
1047 btnSortFrbEnd.addActionListener(new ActionListener() {
1048 public void actionPerformed(ActionEvent e) {
1050 }
1051 });
1052
1053 btnHelpFrbEnd = new JButton("?");
1054 btnHelpFrbEnd.setToolTipText("Displays the help message.");
1055 btnHelpFrbEnd.addActionListener(new ActionListener() {
1056 public void actionPerformed(ActionEvent e) {
1057 String txt = "<html><body width='%1s'><p>Use these buttons to "
1058 + "add/remove attachment point classes (APClasses) "
1059 + "that define <i>forbidden ends</i>, i.e., "
1060 + "attachment point that cannot be left free in a "
1061 + "finished graph. Graphs holding free (i.e., "
1062 + "unsaturated) attachment point with any of these "
1063 + "APClasses are considered incomplete and are not "
1064 + "submitted to fitness evaluation.</p><br>"
1065 + "<p>You can select multiple entries as intervals or "
1066 + "by multiple clicks while holding the appropriate "
1067 + "key (e.g., <code>shift</code>, <code>alt</code>, "
1068 + "<code>ctrl</code>, "
1069 + "<code>cmd</code> depending on your keyboard "
1070 + "settings).</p></html>";
1071 JOptionPane.showMessageDialog(btnHelpFrbEnd,
1072 String.format(txt, 400),
1073 "Tips",
1074 JOptionPane.PLAIN_MESSAGE);
1075 }
1076 });
1077
1078 JPanel panelBtnFrbEnd = new JPanel(new FlowLayout(FlowLayout.LEFT));
1079 panelBtnFrbEnd.add(btnAddFrbEnd);
1080 panelBtnFrbEnd.add(btnDelFrbEnd);
1081 panelBtnFrbEnd.add(btnSortFrbEnd);
1082 panelBtnFrbEnd.add(btnHelpFrbEnd);
1083 panelFrbEnd.add(panelBtnFrbEnd, BorderLayout.NORTH);
1084
1085 JScrollPane panelFrbEndTable = new JScrollPane(tableFrbEnd);
1086 panelFrbEnd.add(panelFrbEndTable, BorderLayout.CENTER);
1087
1088 }
1089
1090//-----------------------------------------------------------------------------
1091
1092 protected void clearSearchMatches()
1093 {
1094 for (Component lineComponent : panelCPRules.getComponents())
1095 {
1096 if (lineComponent instanceof CompatibilityRuleLine)
1097 {
1098 ((CompatibilityRuleLine) lineComponent).clearMatches();
1099 }
1100 }
1101 }
1102
1103//-----------------------------------------------------------------------------
1104
1105 protected void searchAPClass(String query)
1106 {
1108
1109 int n = 0;
1110 if (query.equals(""))
1111 {
1112 matchCounter.setText(" 0 matches");
1113 return;
1114 }
1115
1116 for (Component lineComponent : panelCPRules.getComponents())
1117 {
1118 if (lineComponent instanceof CompatibilityRuleLine)
1119 {
1120 CompatibilityRuleLine line =
1121 (CompatibilityRuleLine) lineComponent;
1122 int m = line.renderIfMatches("(.*)" + query + "(.*)");
1123 n = n+m;
1124 }
1125 }
1126
1127 if (n>0)
1128 {
1129 btnClearMatch.setEnabled(true);
1130 if (n == 1)
1131 matchCounter.setText(" "+n+" match");
1132 else
1133 matchCounter.setText(" "+n+" matches");
1134 }
1135 }
1136
1137//-----------------------------------------------------------------------------
1138
1139 protected void importCPMapFromFile(JComponent parent, File inFile)
1140 {
1141 //Read data from file
1142 compatMap = new HashMap<APClass,ArrayList<APClass>>();
1143 cappingMap = new HashMap<APClass,APClass>();
1144 forbiddenEndList = new HashSet<APClass>();
1145 try {
1146 DenoptimIO.readCompatibilityMatrix(inFile.getAbsolutePath(),
1147 compatMap,
1148 cappingMap,
1150 allAPClsInCPMap.addAll(compatMap.keySet());
1151 } catch (DENOPTIMException e) {
1152 JOptionPane.showMessageDialog(parent,
1153 "<html>Could not read compatibility matrix data from "
1154 + "file<br>'" + inFile + "': " + e.getMessage() + "</html>",
1155 "Error",
1156 JOptionPane.WARNING_MESSAGE,
1157 UIManager.getIcon("OptionPane.errorIcon"));
1158 return;
1159 }
1160
1161 // Update list of all APClasses
1162 // WARNING: the compatibility matrix files may not contain all the
1163 // APClasses of a fragment space! But without reading the actual list
1164 // of fragments there is nothing else we can do.
1167
1168 //Place data into GUI
1172 }
1173
1174//-----------------------------------------------------------------------------
1175
1183 public void writeCopatibilityMatrixFile(JComponent parent, File outFile)
1184 {
1185 try {
1186 DenoptimIO.writeCompatibilityMatrix(outFile.getAbsolutePath(),
1188 } catch (DENOPTIMException e) {
1189 JOptionPane.showMessageDialog(parent,
1190 "<html>Could not write compatibility matrix data to "
1191 + "file<br>'" + outFile + "'</html>",
1192 "Error",
1193 JOptionPane.WARNING_MESSAGE,
1194 UIManager.getIcon("OptionPane.errorIcon"));
1195 return;
1196 }
1197 }
1198
1199//-----------------------------------------------------------------------------
1200
1202 {
1203 // Cleanup previous content
1204 panelCPRules.removeAll();
1205
1206 // Fill with new content
1208 h.setAlignmentX(LEFT_ALIGNMENT);
1209 panelCPRules.add(h);
1210 for (APClass srcAPClass : allAPClsInCPMap)
1211 {
1212 CompatibilityRuleLine r = new CompatibilityRuleLine(srcAPClass);
1213 r.setAlignmentX(LEFT_ALIGNMENT);
1214 panelCPRules.add(r);
1215 }
1216 panelCPRules.repaint();
1217 panelCPRules.revalidate();
1218 }
1219
1220//-----------------------------------------------------------------------------
1221
1223 {
1224 // Remove all lines
1225 int szTab = tabModCapping.getRowCount();
1226 for (int i=0; i<szTab; i++)
1227 {
1228 //Always remove the first to avoid dealing with changing row ids
1229 tabModCapping.removeRow(0);
1230 }
1231
1232 // Get sorted list of table rows
1233 ArrayList<APClass> sortedCappings = new ArrayList<APClass>();
1234 sortedCappings.addAll(cappingMap.keySet());
1235 Collections.sort(sortedCappings);
1236
1237 // Re-build table
1238 for (APClass apc : sortedCappings)
1239 {
1240 tabModCapping.addRow(
1241 new Object[]{apc.toString(), cappingMap.get(apc)});
1242 }
1243 }
1244
1245//-----------------------------------------------------------------------------
1246
1248 {
1249 // Remove all lines
1250 int szTab = tabModFrbEnd.getRowCount();
1251 for (int i=0; i<szTab; i++)
1252 {
1253 //Always remove the first to avoid dealing with changing row ids
1254 tabModFrbEnd.removeRow(0);
1255 }
1256
1257 // Get sorted list of table rows
1258 ArrayList<APClass> sortedFrbEnds = new ArrayList<APClass>();
1259 sortedFrbEnds.addAll(forbiddenEndList);
1260 Collections.sort(sortedFrbEnds);
1261
1262 // Re-build table
1263 for (APClass apc : sortedFrbEnds)
1264 {
1265 tabModFrbEnd.addRow(new Object[]{apc.toString()});
1266 }
1267 }
1268
1269//-----------------------------------------------------------------------------
1270
1278 private void importAllAPClassesFromCPMatrix(boolean cleanup)
1279 {
1280 if (cleanup)
1281 {
1282 allAPClasses = new TreeSet<APClass>();
1283 }
1284
1285 allAPClasses.addAll(compatMap.keySet());
1286
1287 for (ArrayList<APClass> apcs : compatMap.values())
1288 {
1289 allAPClasses.addAll(apcs);
1290 }
1291
1292 for (APClass apc : allAPClasses)
1293 {
1294 allAPRules.add(apc.getRule());
1295 }
1296 }
1297
1298//-----------------------------------------------------------------------------
1299
1308 {
1309 if (cleanup)
1310 {
1311 allCapAPClasses = new TreeSet<APClass>();
1312 }
1313 allCapAPClasses.addAll(cappingMap.values());
1315 for (APClass apc : allAPClasses)
1316 {
1317 allAPRules.add(apc.getRule());
1318 }
1319 }
1320
1321//-----------------------------------------------------------------------------
1322
1330 public void importAllAPClassesFromCappingGroupLibs(Set<File> fragLibs,
1331 boolean cleanup)
1332 {
1333 this.setCursor(Cursor.getPredefinedCursor(
1334 Cursor.WAIT_CURSOR));
1335 if (cleanup)
1336 {
1337 allCapAPClasses = new TreeSet<APClass>();
1338 }
1339
1340 for (File fragLib : fragLibs)
1341 {
1343 }
1344
1345 for (APClass apc : allCapAPClasses)
1346 {
1347 allAPRules.add(apc.getRule());
1348 }
1349
1350 this.setCursor(Cursor.getPredefinedCursor(
1351 Cursor.DEFAULT_CURSOR));
1352 }
1353
1354//-----------------------------------------------------------------------------
1355
1363 public void importAllAPClassesFromFragmentLibs(Set<File> fragLibs,
1364 boolean cleanup)
1365 {
1366 this.setCursor(Cursor.getPredefinedCursor(
1367 Cursor.WAIT_CURSOR));
1368 if (cleanup)
1369 {
1370 allAPClasses = new TreeSet<APClass>();
1371 allAPRules = new TreeSet<String>();
1372 }
1373
1374 for (File fragLib : fragLibs)
1375 {
1376 allAPClasses.addAll(DenoptimIO.readAllAPClasses(fragLib));
1377 }
1378
1379 for (APClass apc : allAPClasses)
1380 {
1381 allAPRules.add(apc.getRule());
1382 }
1383
1384 this.setCursor(Cursor.getPredefinedCursor(
1385 Cursor.DEFAULT_CURSOR));
1386 }
1387
1388//-----------------------------------------------------------------------------
1389
1394 private class CompatibilityRuleLine extends JPanel implements MouseListener
1395 {
1399 private static final long serialVersionUID = -5007017502551954331L;
1400
1401 private JTextField srcClassName;
1402 private JScrollPane srcClassNameScroller;
1403 private JPanel trgClassesPanel;
1404 private JScrollPane trgClassesScroller;
1405 private JButton btnAdd;
1407
1409
1410 private boolean isSelected = false;
1411
1412 private final Dimension minSrcAPClassName = new Dimension(200,26);
1413 private final Dimension scrollerSize = new Dimension(300,41);
1414 private final Color SELECTEDBACKGROUND = Color.BLUE;
1415 private final Color DEFAULTBACKGROUND =
1416 UIManager.getLookAndFeelDefaults().getColor("Panel.background");
1417
1418
1419 //-------------------------------------------------------------------------
1420
1422 {
1423 this.srcAPClass = srcAPClass;
1424 this.setName(srcAPClass.toString());
1425 this.setBackground(DEFAULTBACKGROUND);
1426 this.setLayout(new BorderLayout());
1427
1428 this.trgDelListener = new TrgRemovalListener(srcAPClass);
1429
1430 srcClassName = new JTextField(srcAPClass.toString());
1431 srcClassName.setBorder(null);
1432 srcClassName.setOpaque(false);
1433 srcClassName.setEditable(false);
1434 srcClassName.setForeground(Color.BLACK);
1435 srcClassName.setFont(UIManager.getLookAndFeelDefaults()
1436 .getFont("Label.font"));
1437 srcClassName.setToolTipText(srcAPClass.toString());
1438 srcClassName.addMouseListener(this);
1439 srcClassNameScroller = new JScrollPane(srcClassName,
1440 JScrollPane.VERTICAL_SCROLLBAR_NEVER,
1441 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1442 srcClassNameScroller.getHorizontalScrollBar().setPreferredSize(
1443 new Dimension(0,5));
1444 srcClassNameScroller.setPreferredSize(minSrcAPClassName);
1445 srcClassNameScroller.setBorder(BorderFactory.createEmptyBorder(0,5,0,5));
1446 srcClassNameScroller.setOpaque(false);
1447 srcClassNameScroller.getViewport().setOpaque(false);
1448 this.add(srcClassNameScroller, BorderLayout.WEST);
1449
1450 trgClassesPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
1451 for (APClass trgAPClass : compatMap.get(srcAPClass))
1452 {
1453 TargetAPClassToken trg = new TargetAPClassToken(trgAPClass);
1454 trg.addPropertyChangeListener(
1455 new PropertyChangeListenerProxy(
1457 trgClassesPanel.add(trg);
1458 }
1459 trgClassesScroller = new JScrollPane(trgClassesPanel,
1460 JScrollPane.VERTICAL_SCROLLBAR_NEVER,
1461 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1462 trgClassesScroller.getHorizontalScrollBar().setPreferredSize(
1463 new Dimension(0,5));
1464 trgClassesScroller.setPreferredSize(scrollerSize);
1465 this.add(trgClassesScroller, BorderLayout.CENTER);
1466
1467 btnAdd = new JButton("Add");
1468 btnAdd.setToolTipText(String.format("<html><body width='%1s'>"
1469 + "Add more compatible APClasses to source class <i>"
1470 + srcAPClass + "</i></html>",250));
1471 btnAdd.addActionListener(new ActionListener() {
1472 public void actionPerformed(ActionEvent e) {
1473 DefaultListModel<String> trgAPCs =
1474 new DefaultListModel<String>();
1475 JList<String> trgClsList = new JList<String>(trgAPCs);
1476 for (APClass apc : allAPClasses)
1477 {
1478 trgAPCs.addElement(apc.toString());
1479 }
1480 trgAPCs.addElement("<html><b><i>Define a new APClass...<i>"
1481 + "</b></html>");
1482 trgClsList.setSelectionMode(
1483 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
1484
1485 JScrollPane scrollTrg = new JScrollPane(trgClsList);
1486
1487 JOptionPane.showMessageDialog(
1488 btnAdd,
1489 scrollTrg,
1490 "Choose Compatible APClasses",
1491 JOptionPane.PLAIN_MESSAGE);
1492
1493 if (trgClsList.getSelectedIndices().length > 0)
1494 {
1495 ArrayList<APClass> trgCPClasses =
1496 new ArrayList<APClass>();
1497 for (Integer id : trgClsList.getSelectedIndices())
1498 {
1499 if (id.intValue() == (trgAPCs.size()-1))
1500 {
1501 try {
1502 GUIAPClassDefinitionDialog apcDefiner =
1504 btnAdd, true);
1505 Object chosen = apcDefiner.showDialog();
1506 if (chosen == null)
1507 {
1508 return;
1509 }
1510
1511 Object[] pair = (Object[]) chosen;
1512 APClass newAPC = APClass.make(pair[0].toString(),
1513 (BondType) pair[1]);
1514
1515 if (allAPClasses.contains(newAPC))
1516 {
1517 JOptionPane.showMessageDialog(btnAdd,
1518 "<html>Class '<code>" + newAPC
1519 +"</code>' is not new!</html>",
1520 "Error",
1521 JOptionPane.WARNING_MESSAGE,
1522 UIManager.getIcon(
1523 "OptionPane.errorIcon"));
1524 return;
1525 }
1526 trgCPClasses.add(newAPC);
1527 allAPClasses.add(newAPC);
1528 allAPRules.add(newAPC.getRule());
1529 } catch (DENOPTIMException e1) {
1530 continue;
1531 }
1532 }
1533 else
1534 {
1535 try
1536 {
1537 trgCPClasses.add(APClass.make(
1538 (String) trgAPCs.getElementAt(id)));
1539 } catch (DENOPTIMException e1)
1540 {
1541 //this will never happen
1542 e1.printStackTrace();
1543 }
1544 }
1545 }
1546 compatMap.get(srcAPClass).addAll(trgCPClasses);
1548 }
1549 }
1550 });
1551 this.add(btnAdd, BorderLayout.EAST);
1552
1553 this.setBorder(BorderFactory.createRaisedSoftBevelBorder());
1554
1555 addMouseListener(this);
1556 setFocusable(true);
1557 }
1558
1559 //-------------------------------------------------------------------------
1560
1561 public void clearMatches()
1562 {
1563 for (Component c : trgClassesPanel.getComponents())
1564 {
1565 if (c instanceof TargetAPClassToken)
1566 {
1567 ((TargetAPClassToken) c).renderAsSelected(false);
1568 }
1569 }
1570 isSelected = false;
1571 renderdAsSelected(false);
1572 }
1573
1574 //-------------------------------------------------------------------------
1575
1582 public int renderIfMatches(String regex)
1583 {
1584 boolean found = false;
1585 int n = 0;
1586
1587 if (srcAPClass.toString().matches(regex))
1588 {
1589 found = true;
1590 n = 1;
1591 }
1592
1593 for (Component c : trgClassesPanel.getComponents())
1594 {
1595 if (c instanceof TargetAPClassToken)
1596 {
1598 if (tac.matchesAPClass(regex))
1599 {
1600 found = true;
1601 tac.renderAsSelected(true);
1602 n++;
1603 }
1604 }
1605 }
1606
1607 if (found)
1608 {
1609 isSelected = true;
1610 renderdAsSelected(true);
1611 }
1612
1613 return n;
1614 }
1615
1616 //-------------------------------------------------------------------------
1617
1618 public void renderdAsSelected(boolean selected)
1619 {
1620 if (selected)
1621 {
1622 super.setBackground(SELECTEDBACKGROUND);
1623 srcClassName.setForeground(Color.WHITE);
1624 }
1625 else
1626 {
1627 super.setBackground(DEFAULTBACKGROUND);
1628 srcClassName.setForeground(Color.BLACK);
1629 }
1630 }
1631
1632 //-------------------------------------------------------------------------
1633
1634 @Override
1635 public void mouseClicked(MouseEvent e)
1636 {
1637 if (isSelected)
1638 isSelected = false;
1639 else
1640 isSelected = true;
1642 }
1643
1644 //-------------------------------------------------------------------------
1645
1646 @Override
1647 public void mousePressed(MouseEvent e) {}
1648
1649 @Override
1650 public void mouseReleased(MouseEvent e) {}
1651
1652 @Override
1653 public void mouseEntered(MouseEvent e) {}
1654
1655 @Override
1656 public void mouseExited(MouseEvent e) {}
1657 }
1658
1659//-----------------------------------------------------------------------------
1660
1666 private class TrgRemovalListener implements PropertyChangeListener
1667 {
1669
1671 {
1672 this.srcAPClass = srcAPClass;
1673 }
1674
1675 public void propertyChange(PropertyChangeEvent evt)
1676 {
1677 APClass trgAPClass = (APClass) evt.getNewValue();
1678 compatMap.get(srcAPClass).remove(trgAPClass);
1680 }
1681 }
1682
1683//-----------------------------------------------------------------------------
1684
1685 @SuppressWarnings("serial")
1686 private class CompatRulesHeader extends JPanel
1687 {
1688 private Dimension minSrcAPClassName = new Dimension(200,26);
1689 public final Color DEFAULTBACKGROUND =
1690 UIManager.getLookAndFeelDefaults().getColor("Panel.background");
1691
1693 {
1694 this.setName("Header");
1695 this.setBackground(DEFAULTBACKGROUND);
1696 this.setLayout(new BorderLayout());
1697
1698 JLabel srcClassTitle = new JLabel("<html>"
1699 + "<div style='text-align: center;'>"
1700 + "<b>Source APClass:</b></div></html>");
1701 srcClassTitle.setBackground(DEFAULTBACKGROUND);
1702 srcClassTitle.setPreferredSize(minSrcAPClassName);
1703 srcClassTitle.setBorder(BorderFactory.createEmptyBorder(0,5,0,5));
1704 this.add(srcClassTitle, BorderLayout.WEST);
1705
1706 JLabel trgClassTitle = new JLabel("<html>"
1707 + "<div style='text-align: center;'>"
1708 + "<b>Compatible APClasses of incoming fragments:</b></div></html>");
1709 trgClassTitle.setBackground(DEFAULTBACKGROUND);
1710 trgClassTitle.setPreferredSize(minSrcAPClassName);
1711 trgClassTitle.setBorder(BorderFactory.createEmptyBorder(0,5,0,5));
1712
1713 this.add(trgClassTitle, BorderLayout.CENTER);
1714
1715 this.setBorder(BorderFactory.createRaisedSoftBevelBorder());
1716 }
1717 }
1718
1719//-----------------------------------------------------------------------------
1720
1721 @SuppressWarnings("serial")
1722 private class TargetAPClassToken extends JPanel
1723 {
1725 private JTextField trgAPClLabel;
1726 private JButton btnDel;
1727
1728 private final Color BTNPRESS = Color.decode("#fbae9d");
1729 private final Color BTNDEF = Color.decode("#f74922");
1730
1731 private final Color SELECTEDBACKGROUND = Color.BLUE;
1732 private final Color DEFAULTBACKGROUND =
1733 UIManager.getLookAndFeelDefaults().getColor("Panel.background");
1734
1735 public TargetAPClassToken(APClass trgAPClass)
1736 {
1737 this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
1738 this.trgAPClass = trgAPClass;
1739 trgAPClLabel = new JTextField(trgAPClass.toString());
1740 trgAPClLabel.setBorder(null);
1741 trgAPClLabel.setOpaque(false);
1742 trgAPClLabel.setEditable(false);
1743 trgAPClLabel.setForeground(Color.BLACK);
1744 trgAPClLabel.setFont(UIManager.getLookAndFeelDefaults()
1745 .getFont("Label.font"));
1746 this.add(trgAPClLabel);
1747 btnDel = new JButton("X");
1748 btnDel.setMaximumSize(new Dimension(15,15));
1749 btnDel.setBackground(BTNDEF);
1750 btnDel.setOpaque(true);
1751 btnDel.setBorderPainted(true);
1752 btnDel.setBorder(BorderFactory.createRaisedSoftBevelBorder());
1753 btnDel.setForeground(Color.BLACK);
1754 btnDel.setToolTipText("<html>Remove <code>" + trgAPClass
1755 + "</code></html>");
1756 btnDel.addMouseListener(new MouseListener() {
1757
1758 @Override
1759 public void mouseReleased(MouseEvent e)
1760 {
1761 firePropertyChange(CompatibilityMatrixForm.REMOVETRGAPC,
1762 "#", trgAPClass);
1763 }
1764
1765 @Override
1766 public void mousePressed(MouseEvent e)
1767 {
1768 btnDel.setBackground(BTNPRESS);
1769 }
1770
1771 @Override
1772 public void mouseExited(MouseEvent e)
1773 {
1774 btnDel.setBackground(BTNDEF);
1775 }
1776
1777 @Override
1778 public void mouseEntered(MouseEvent e) {}
1779
1780 @Override
1781 public void mouseClicked(MouseEvent e) {}
1782 });
1783 this.add(btnDel);
1784 this.add(Box.createRigidArea(new Dimension(15,15)));
1785 }
1786
1787 //-------------------------------------------------------------------------
1788
1789 public boolean matchesAPClass(String regex)
1790 {
1791 return trgAPClass.toString().matches(regex);
1792 }
1793
1794 //-------------------------------------------------------------------------
1795
1796 public void renderAsSelected(boolean selected)
1797 {
1798 if (selected)
1799 {
1800 super.setBackground(SELECTEDBACKGROUND);
1801 trgAPClLabel.setForeground(Color.WHITE);
1802 }
1803 else
1804 {
1805 super.setBackground(DEFAULTBACKGROUND);
1806 trgAPClLabel.setForeground(Color.BLACK);
1807 }
1808 }
1809
1810 //-------------------------------------------------------------------------
1811
1812 }
1813
1814//-----------------------------------------------------------------------------
1815
1816}
String toString()
Do not use this to make SDF representations.
Definition: APClass.java:352
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:136
Single line in the list of APClass compatibility rules.
int renderIfMatches(String regex)
Checks if there is any component matching the regex query and returns the number of matches.
Listens for clicks that require removal of a compatible APClass (i.e., the target APClass) from the e...
void importAllCappingGroupsAPClassesFromCPMatrix(boolean cleanup)
Reads all the APClasses of capping groups as found in the currently loaded capping rules.
void importCPMapFromFile(JComponent parent, File inFile)
void importAllAPClassesFromCappingGroupLibs(Set< File > fragLibs, boolean cleanup)
Reads all the APClasses found in a list of files.
static final long serialVersionUID
Version UID.
HashMap< APClass, ArrayList< APClass > > compatMap
Data structure that stored the true entries of the attachment point classes compatibility matrix.
SortedSet< APClass > allAPClsInCPMap
Sorted list of APClasses in the map of compatibility rules.
void writeCopatibilityMatrixFile(JComponent parent, File outFile)
Writes all the compatibility matrix data to the given file.
SortedSet< String > allAPRules
List of all APRules.
SortedSet< APClass > allAPClasses
List of all APClasses.
void importAllAPClassesFromCPMatrix(boolean cleanup)
Reads all the APClasses found in the currently loaded compatibility matrix.
SortedSet< APClass > allCapAPClasses
List of APClasses of capping groups.
void importAllAPClassesFromFragmentLibs(Set< File > fragLibs, boolean cleanup)
Reads all the APClasses found in a list of files.
HashMap< APClass, APClass > cappingMap
Data structure that stores the AP-classes to be used to cap unused APS on the growing molecule.
static final String REMOVETRGAPC
Property used to trigger removal of a target APClass.
HashSet< APClass > forbiddenEndList
Data structure that stores AP classes that cannot be held unused.
Object showDialog()
Shows the dialog and restrains the modality to it, until the dialog gets closed.
Utility methods for input/output.
static void readCompatibilityMatrix(String fileName, HashMap< APClass, ArrayList< APClass > > compatMap, HashMap< APClass, APClass > cappingMap, Set< APClass > forbiddenEndList)
Read the APclass compatibility matrix data from file.
static Set< APClass > readAllAPClasses(File fragLib)
static void writeCompatibilityMatrix(String fileName, HashMap< APClass, ArrayList< APClass > > cpMap, HashMap< APClass, APClass > capMap, HashSet< APClass > ends)
The class compatibility matrix.
Possible chemical bond types an edge can represent.
Definition: Edge.java:303