21import java.awt.BorderLayout;
23import java.awt.Component;
24import java.awt.Cursor;
25import java.awt.Desktop;
26import java.awt.Dimension;
27import java.awt.FlowLayout;
28import java.awt.event.ActionEvent;
29import java.awt.event.ActionListener;
30import java.awt.event.FocusEvent;
31import java.awt.event.FocusListener;
32import java.awt.event.InputEvent;
33import java.awt.event.MouseAdapter;
34import java.awt.event.MouseEvent;
36import java.io.IOException;
38import java.net.URISyntaxException;
39import java.util.ArrayList;
40import java.util.Arrays;
42import java.util.Vector;
44import javax.swing.BoxLayout;
45import javax.swing.ButtonGroup;
46import javax.swing.JButton;
47import javax.swing.JComponent;
48import javax.swing.JLabel;
49import javax.swing.JOptionPane;
50import javax.swing.JPanel;
51import javax.swing.JRadioButton;
52import javax.swing.JScrollPane;
53import javax.swing.JSeparator;
54import javax.swing.JSplitPane;
55import javax.swing.JTable;
56import javax.swing.JTextField;
57import javax.swing.UIManager;
58import javax.swing.table.DefaultTableModel;
60import org.apache.batik.swing.JSVGCanvas;
61import org.apache.batik.swing.gvt.AbstractImageZoomInteractor;
62import org.apache.batik.swing.gvt.AbstractPanInteractor;
63import org.apache.batik.swing.gvt.AbstractResetTransformInteractor;
65import denoptim.exception.DENOPTIMException;
66import denoptim.files.FileAndFormat;
67import denoptim.files.FileFormat;
68import denoptim.files.FileUtils;
69import denoptim.io.DenoptimIO;
70import denoptim.programs.fragmenter.CuttingRule;
71import denoptim.programs.fragmenter.FragmenterParameters;
72import denoptim.utils.GeneralUtils;
118 (int) (
new JTextField()).getPreferredSize().getHeight();
148 List<CuttingRule> customCuttingRules,
boolean preselectDefault,
151 super(refForPlacement);
152 this.frgParams = settings;
153 setTitle(
"Choose Cutting Rules");
155 rdbUseDefault =
new JRadioButton(
"Use default cutting rules.");
157 "Use the following curtomized cutting rules.");
159 if (preselectDefault)
167 ButtonGroup rdbGroup =
new ButtonGroup();
173 String column_names[]= {
"<html><b>Rule Name</b></html>",
174 "<html><b>Order of Use</b></html>",
175 "<html><b>SMARTS Atom 1</b></html>",
176 "<html><b>SMARTS Bond 1-2</b></html>",
177 "<html><b>SMARTS Atom 2</b></html>",
178 "<html><b>Options</b></html>"};
186 e2.printStackTrace();
189 defaultRulesTable.setToolTipText(
"<html>"
190 +
"Double click to edit any entry. <br>"
191 +
"Edited lists are saved in '"
193 defaultRulesTable.putClientProperty(
"terminateEditOnFocusLost",
195 defaultRulesTable.addFocusListener(
new FocusListener() {
198 public void focusGained(FocusEvent e)
204 public void focusLost(FocusEvent e) {}
208 String[] values =
new String[6];
209 values[0] = cr.getName();
210 values[1] = String.valueOf(cr.getPriority());
211 values[2] = cr.getSMARTSAtom0();
212 values[3] = cr.getSMARTSBnd();
213 values[4] = cr.getSMARTSAtom1();
214 StringBuilder sb =
new StringBuilder();
215 cr.getOptions().stream().forEach(s -> sb.append(
" " + s));
216 values[5] = sb.toString();
219 JScrollPane defaultRulesScrollPane =
new JScrollPane(defaultRulesTable);
220 defaultRulesTable.getTableHeader().setPreferredSize(
221 new Dimension(defaultRulesScrollPane.getWidth(), 40));
223 String[] emptyRow =
new String[] {
224 "double click to edit...",
"",
"",
"",
"",
""};
226 JButton btnAddDefaultRule =
new JButton(
"Add Rule");
227 btnAddDefaultRule.addActionListener(
new ActionListener() {
230 public void actionPerformed(ActionEvent e)
235 JButton btnRemoveDefaultRule =
new JButton(
"Remove Selected");
236 btnRemoveDefaultRule.addActionListener(
new ActionListener() {
239 public void actionPerformed(ActionEvent e)
241 if (defaultRulesTable.getRowCount() > 0)
243 if (defaultRulesTable.getSelectedRowCount() > 0)
245 int selectedRowIds[] =
246 defaultRulesTable.getSelectedRows();
247 Arrays.sort(selectedRowIds);
248 for (
int i=(selectedRowIds.length-1); i>-1; i--)
263 @SuppressWarnings(
"serial")
266 public Dimension getPreferredScrollableViewportSize() {
267 return new Dimension(super.getPreferredSize().width,
268 getRowHeight() * getRowCount());
271 customRulesTable.setToolTipText(
"<html>"
272 +
"Double click to edit any entry. <br>"
273 +
"Edited lists are saved in '"
275 customRulesTable.putClientProperty(
"terminateEditOnFocusLost",
277 customRulesTable.addFocusListener(
new FocusListener() {
280 public void focusGained(FocusEvent e)
286 public void focusLost(FocusEvent e) {}
290 JButton btnAddCustomRule =
new JButton(
"Add Rule");
291 btnAddCustomRule.addActionListener(
new ActionListener() {
294 public void actionPerformed(ActionEvent e)
299 JButton btnRemoveCustomRule =
new JButton(
"Remove Selected");
300 btnRemoveCustomRule.addActionListener(
new ActionListener() {
303 public void actionPerformed(ActionEvent e)
305 if (customRulesTable.getRowCount() > 0)
307 if (customRulesTable.getSelectedRowCount() > 0)
309 int selectedRowIds[] =
310 customRulesTable.getSelectedRows();
311 Arrays.sort(selectedRowIds);
312 for (
int i=(selectedRowIds.length-1); i>-1; i--)
323 JButton btnImportRules =
new JButton(
"Import Rules...");
324 btnImportRules.addActionListener(
new ActionListener() {
327 public void actionPerformed(ActionEvent e)
329 customCuttingRules.clear();
337 JOptionPane.showMessageDialog(btnImportRules,String.format(
338 "<html><body width='%1s'"
339 +
"Could not read cutting rules from '"
340 + cutRulFile.getAbsolutePath() +
"'. Hint: "
341 + e1.getMessage() +
"</html>", 400),
343 JOptionPane.ERROR_MESSAGE,
344 UIManager.getIcon(
"OptionPane.errorIcon"));
354 JButton btnSaveRules =
new JButton(
"Save Rules...");
355 btnSaveRules.addActionListener(
new ActionListener() {
358 public void actionPerformed(ActionEvent e)
360 List<CuttingRule> rules =
new ArrayList<CuttingRule>();
369 String optsStr = (String) rowdat.elementAt(5);
371 (String) rowdat.elementAt(0),
372 (String) rowdat.elementAt(2),
373 (String) rowdat.elementAt(4),
374 (String) rowdat.elementAt(3),
375 Integer.valueOf((String) rowdat.elementAt(1)),
376 new ArrayList<String>(
377 Arrays.asList(optsStr.split(
"\\s+")))));
378 }
catch (Exception ecr)
380 JOptionPane.showMessageDialog(btnSaveRules,
381 String.format(
"<html><body width='%1s'>"
382 +
"Could not create cutting rule "
385 + rowdat.elementAt(i)
386 +
". Hint: " + ecr.getMessage()
387 +
". Skipping this line!</html>",
390 JOptionPane.PLAIN_MESSAGE,
391 UIManager.getIcon(
"OptionPane.errorIcon"));
396 System.out.println(
"Name: "+name);
402 if (fileAndFormat ==
null)
414 ex.printStackTrace();
415 JOptionPane.showMessageDialog(btnSaveRules,
416 "Could not write to '" + fileAndFormat.
file +
"'! "
417 +
"Hint: "+ex.getMessage(),
419 JOptionPane.PLAIN_MESSAGE,
420 UIManager.getIcon(
"OptionPane.errorIcon"));
429 JScrollPane customRulesScrollPane =
new JScrollPane(customRulesTable);
430 customRulesTable.getTableHeader().setPreferredSize(
431 new Dimension(customRulesScrollPane.getWidth(), 40));
434 JPanel pnlButtonsDefaultRules =
new JPanel(
new FlowLayout(FlowLayout.LEFT));
435 pnlButtonsDefaultRules.add(btnAddDefaultRule);
436 pnlButtonsDefaultRules.add(btnRemoveDefaultRule);
437 pnlButtonsDefaultRules.add(btnViewSelectedDefaultRule);
439 JPanel headerDefaultBlock =
new JPanel(
new BorderLayout());
441 headerDefaultBlock.add(pnlButtonsDefaultRules, BorderLayout.CENTER);
443 JPanel defaultRulesPanel =
new JPanel(
new BorderLayout());
444 defaultRulesPanel.add(headerDefaultBlock, BorderLayout.NORTH);
445 defaultRulesPanel.add(defaultRulesScrollPane, BorderLayout.CENTER);
448 JPanel pnlButtonsCustomRules =
new JPanel(
new FlowLayout(FlowLayout.LEFT));
449 pnlButtonsCustomRules.add(btnAddCustomRule);
450 pnlButtonsCustomRules.add(btnRemoveCustomRule);
451 pnlButtonsCustomRules.add(btnViewSelectedCustomRule);
452 pnlButtonsCustomRules.add(btnImportRules);
453 pnlButtonsCustomRules.add(btnSaveRules);
455 JPanel headerCustomBlock =
new JPanel(
new BorderLayout());
457 headerCustomBlock.add(pnlButtonsCustomRules, BorderLayout.CENTER);
459 JPanel customRulesPanel =
new JPanel(
new BorderLayout());
460 customRulesPanel.add(headerCustomBlock, BorderLayout.NORTH);
461 customRulesPanel.add(customRulesScrollPane, BorderLayout.CENTER);
464 JSplitPane masterPane =
new JSplitPane(JSplitPane.VERTICAL_SPLIT);
465 masterPane.setTopComponent(defaultRulesPanel);
466 masterPane.setBottomComponent(customRulesPanel);
478 String toolTipLinearity = String.format(
"<html><body width='%1s'>"
479 +
"Defines the max bond angle before considering the bond "
480 +
"angle close to linear and, thus, adding a "
481 +
"linearity-breaking dummy atom. Setting a value larger than "
482 +
"180 prevents addition of any linearity-breaking dummy atom."
484 JPanel lineLinearity =
new JPanel(
new FlowLayout(FlowLayout.LEFT));
485 JLabel lblLinearity =
new JLabel(
486 "Non-linearity limit for bond angles (DEG): ");
487 lblLinearity.setToolTipText(toolTipLinearity);
493 lineLinearity.setToolTipText(toolTipLinearity);
494 lineLinearity.add(lblLinearity);
499 btnDone.setText(
"Start Fragmentation");
500 btnDone.setToolTipText(String.format(
"<html><body width='%1s'>"
501 +
"Uses the selected rules to produce fragments.</html>",400));
507 btnDone.addActionListener(
new ActionListener() {
509 public void actionPerformed(ActionEvent e)
515 boolean setOfCuttingRulesHasBeenModified =
false;
518 for (
int iRow=0; iRow<chosenTab.getRowCount(); iRow++)
520 String[] values =
new String[5];
521 for (
int iCol=0; iCol<5; iCol++)
523 values[iCol] = chosenTab.getValueAt(iRow,iCol)
526 ArrayList<String> opts =
new ArrayList<String>();
527 if (!chosenTab.getValueAt(iRow,5).toString().trim().isBlank())
528 opts.addAll(Arrays.asList(chosenTab.getValueAt(iRow,5)
529 .toString().trim().split(
"\\s+")));
533 prioIdx = Integer.parseInt(values[1]);
534 }
catch (Throwable t)
536 JOptionPane.showMessageDialog(
btnDone,String.format(
537 "<html><body width='%1s'>"
538 +
"Could not convert string '" + values[1]
539 +
"' into an integer. Ignoring row " + iRow
540 +
" in table of custom cutting rules.</html>",
543 JOptionPane.ERROR_MESSAGE,
544 UIManager.getIcon(
"OptionPane.errorIcon"));
549 values[2], values[4], values[3], prioIdx, opts);
553 if (!setOfCuttingRulesHasBeenModified)
555 boolean fromDefault =
false;
556 if (defaultCuttingRules.size() > iRow)
558 fromDefault = defaultCuttingRules.get(iRow).equals(
561 boolean fromCustom =
false;
562 if (customCuttingRules.size() > iRow)
564 fromCustom = customCuttingRules.get(iRow).equals(
567 if (!fromDefault && !fromCustom)
569 setOfCuttingRulesHasBeenModified =
true;
575 if (
chosenOnes.size() != defaultCuttingRules.size()
576 &&
chosenOnes.size() != customCuttingRules.size())
578 setOfCuttingRulesHasBeenModified =
true;
582 if (setOfCuttingRulesHasBeenModified)
593 e1.printStackTrace();
602 getRootPane().setDefaultButton(
btnDone);
604 this.
btnCanc.setToolTipText(
"Exit without running fragmentation.");
612 if (lastUsedCutRulFile!=
null)
630 panel.setAlignmentX(Component.CENTER_ALIGNMENT);
641 @SuppressWarnings(
"serial")
649 private String templateURL =
"https://smarts.plus/smartsview/"
650 +
"download_rest?smarts="
659 DefaultTableModel tabModel)
661 super(
"Visualize Selected...");
663 addActionListener(
new ActionListener() {
666 public void actionPerformed(ActionEvent e)
668 if (table.getRowCount()==0
669 || table.getSelectedRowCount()==0)
671 JOptionPane.showMessageDialog(refToThis,
672 "No SMARTS selected.",
673 "Visualization of SMARTS",
674 JOptionPane.PLAIN_MESSAGE);
678 JPanel masterPanel =
new JPanel();
679 masterPanel.setLayout(
new BoxLayout(masterPanel,
680 BoxLayout.PAGE_AXIS));
682 int selectedRowIds[] = table.getSelectedRows();
683 Arrays.sort(selectedRowIds);
684 for (
int i=0; i<selectedRowIds.length; i++)
686 String smarts = tabModel.getValueAt(
687 selectedRowIds[i],2).toString()
688 + tabModel.getValueAt(
689 selectedRowIds[i],3).toString()
690 + tabModel.getValueAt(
691 selectedRowIds[i],4).toString();
694 String url = templateURL.replace(
"SMARTS", smarts);
696 JPanel header =
new JPanel(
new FlowLayout(FlowLayout.LEFT));
697 header.add(
new JLabel(tabModel.getValueAt(
698 selectedRowIds[i],0).toString() +
" - "));
700 JLabel link =
new JLabel(
"Download SVG");
701 link.setForeground(Color.BLUE.darker());
702 link.setCursor(Cursor.getPredefinedCursor(
703 Cursor.HAND_CURSOR));
704 link.addMouseListener(
new MouseAdapter() {
707 public void mouseClicked(MouseEvent e) {
709 Desktop.getDesktop().browse(
new URI(url));
710 }
catch (IOException | URISyntaxException e1) {
711 e1.printStackTrace();
718 header.add(
new JLabel(
" "
721 masterPanel.add(header);
724 svgCanvas.setURI(url);
725 masterPanel.add(svgCanvas);
729 dialog.
btnCanc.setVisible(
false);
731 dialog.
btnExtra.addActionListener(
new ActionListener() {
734 public void actionPerformed(ActionEvent e)
736 JOptionPane.showMessageDialog(dialog.
btnExtra,
737 String.format(
"<html><body width='%1s'>"
738 +
"<p>Visual representations of SMARTS are depicted by the "
739 +
"SMARTSview service offered "
740 +
"by the ZBH - Center for Bioinformatics of the "
741 +
"University of Hamburg (visit https://smarts.plus/).</p>"
743 +
"<li>Use the 'Download SVG' button to download the "
745 +
"<li>Pan the image in any direction by dragging the mouse "
746 +
"(left button).</li>"
747 +
"<li>Zoom in/out by holding the SHIFT key while dragging "
748 +
"down-/up-wards.</li></ul></html>", 400),
749 "Visualization of SMARTS - Instructions",
750 JOptionPane.PLAIN_MESSAGE);
779 setEnableZoomInteractor(
false);
780 setEnableImageZoomInteractor(
false);
781 setEnablePanInteractor(
false);
782 setEnableRotateInteractor(
false);
783 setEnableResetTransformInteractor(
false);
793 zoomInteractor =
null;
798 imageZoomInteractor =
new AbstractImageZoomInteractor() {
799 public boolean startInteraction(InputEvent ie) {
800 int mods = ie.getModifiersEx();
802 ie.getID() == MouseEvent.MOUSE_PRESSED &&
803 (mods & InputEvent.BUTTON1_DOWN_MASK) != 0 &&
804 (mods & InputEvent.SHIFT_DOWN_MASK) != 0;
811 panInteractor =
new AbstractPanInteractor() {
812 public boolean startInteraction(InputEvent ie) {
813 int mods = ie.getModifiersEx();
815 ie.getID() == MouseEvent.MOUSE_PRESSED &&
816 (mods & InputEvent.BUTTON1_DOWN_MASK) != 0;
824 public void mouseExited(MouseEvent e) {}
830 rotateInteractor =
null;
835 resetTransformInteractor =
new AbstractResetTransformInteractor() {
836 public boolean startInteraction(InputEvent ie) {
837 int mods = ie.getModifiersEx();
839 ie.getID() == MouseEvent.MOUSE_PRESSED &&
840 (mods & InputEvent.CTRL_DOWN_MASK) != 0;
849 setEnableImageZoomInteractor(
true);
850 setEnableResetTransformInteractor(
true);
851 setEnablePanInteractor(
true);
863 String escapedSmarts = smarts;
864 escapedSmarts = escapedSmarts.replaceAll(
"%",
"%25");
865 escapedSmarts = escapedSmarts.replaceAll(
"&",
"%26");
866 escapedSmarts = escapedSmarts.replaceAll(
"\\+",
"%2B");
867 escapedSmarts = escapedSmarts.replaceAll(
"#",
"%23");
868 escapedSmarts = escapedSmarts.replaceAll(
";",
"%3B");
870 return escapedSmarts;
882 if (customCuttingRules.size()==0)
888 String[] values =
new String[6];
889 values[0] = cr.getName();
890 values[1] = String.valueOf(cr.getPriority());
891 values[2] = cr.getSMARTSAtom0();
892 values[3] = cr.getSMARTSBnd();
893 values[4] = cr.getSMARTSAtom1();
894 StringBuilder sb =
new StringBuilder();
895 cr.getOptions().stream().forEach(s -> sb.append(
" " + s));
896 values[5] = sb.toString();
static File getAvailableFileName(File parent, String baseName)
Define a filename that can be used, i.e., is still available, because no other file with the same pat...
static void addToRecentFiles(String fileName, FileFormat ff)
Appends an entry to the list of recent files.
Special canvas that overrides the set interpretation of mouse+key input to achieve a simplified zoom/...
static final long serialVersionUID
Version ID.
A modal dialog to define parameters for fragmentation and fragment filtering.
JRadioButton rdbUseCustom
List< CuttingRule > chosenOnes
Chosen set of rules.
DefaultTableModel defaultRulesTabModel
FragmenterParameters frgParams
Parameter storage were we store parameters.
JRadioButton rdbUseDefault
final int preferredHeight
Default text field height.
File nextWrittenCutRulFile
The file where we will save next edited list of cutting rules.
DefaultTableModel customRulesTabModel
JTextField txtLinearity
User-controlled definition of the linearity limit.
static final long serialVersionUID
Version ID.
CuttingRulesSelectionDialog(List< CuttingRule > defaultCuttingRules, List< CuttingRule > customCuttingRules, boolean preselectDefault, Component refForPlacement, FragmenterParameters settings)
Constructor.
File getTmpFileForCuttingRules()
void appendToCentralPanel(JComponent panel)
Method to append a panel to the bottom of the central panel.
File lastUsedCutRulFile
The file where we last saved cutting rules different from the default.
String escapeCharactersForSMARTSViewer(String smarts)
Escaping some characters as explained in https://smarts.plus/rest.
final Dimension strFieldSize
Default sizes for mid-long text.
JPanel centralPanel
The panel in the central part of the dialog.
void buildCustomRulesTable(List< CuttingRule > customCuttingRules, String[] emptyRow)
File opener for DENOPTIM GUI.
static File pickFile(Component parent)
GUI component to provide pathname where to save stuff.
static FileAndFormat pickFileForSavingCuttingRules(Component parent)
JButton btnCanc
The button that is used to close the dialog without processing any input.
void addToCentralPane(JComponent comp)
Adds a component to the central part of this dialog frame.
JButton btnExtra
The button that can be used for any action that does not close the dialog.
JButton btnDone
The button that is used to launch the processing of the data given to the open dialog,...
Object result
The result to be returned once the dialog is closed.
Object showDialog()
Shows the dialog and restrains the modality to it, until the dialog gets closed.
GUIModalDialog(Component refForPlacement)
Constructor.
void close()
Closes the dialog window.
The collection of tunable preferences.
static String tmpSpace
Readable/writable space for tmp files.
Utility methods for input/output.
static void readCuttingRules(BufferedReader reader, List< CuttingRule > cutRules, String source)
Read cutting rules from a stream.
static void writeCuttingRules(File file, List< CuttingRule > cutRules)
Writes a formatted text file that collects cutting rule.
A cutting rule with three SMARTS queries (atom 1, bond, atom2) and options.
Parameters controlling execution of the fragmenter.
double getLinearAngleLimit()
void setCuttingRules(List< CuttingRule > cuttingRules)
Assigns the cutting rules loaded from the input.
void setLinearAngleLimit(double linearAngleLimit)
Sets the upper limit for an angle before it is treated as "flat" angle, i.e., close enough to 180 DEG...
void setCuttingRulesFilePathname(String pathname)
Assigns the pathname to the cutting rules file.
static String getEnglishFormattedDecimal(String pattern, int decimals, double value)
Formats a decimal number using the given pattern but with English format as for separators.