package au.com.acpfg.xml.query; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.PrintWriter; import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileFilter; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import org.apache.commons.codec.binary.Base64; import org.knime.core.data.DataColumnSpec; import org.knime.core.data.DataTableSpec; import org.knime.core.node.InvalidSettingsException; import org.knime.core.node.NodeSettingsRO; import org.knime.core.node.NodeSettingsWO; import org.knime.core.node.NotConfigurableException; import org.knime.core.node.defaultnodesettings.DefaultNodeSettingsPane; import org.knime.core.node.defaultnodesettings.DialogComponentColumnNameSelection; import org.knime.core.node.defaultnodesettings.SettingsModelString; import org.knime.core.node.util.ColumnFilter; import au.com.acpfg.xml.query.XMLQueryEntry.ResultsType; import au.com.acpfg.xml.reader.XMLCell; /** * <code>NodeDialog</code> for the "XMLreader" Node. * Provides an XPath knime api & XML "blob" cell type and data processing. Useful for many life science XML formats (PepXML, ProtXML, BLAST XML etc. etc.) * * This node dialog derives from {@link DefaultNodeSettingsPane} which allows * creation of a simple dialog with standard components. If you need a more * complex dialog please derive directly from * {@link org.knime.core.node.NodeDialogPane}. * * @author Andrew Cassin */ public class XQueryProcessorNodeDialog extends DefaultNodeSettingsPane { /** * The currently selected XMLQueryEntry */ private XMLQueryEntry m_cur_edit; private int m_cur_idx; private final JList query_list; // contains a custom model which can serialise the XMLQueryEntry's for KNIME /** * New pane for configuring XMLreader node dialog. * This is just a suggestion to demonstrate possible default dialog * components. */ protected XQueryProcessorNodeDialog() { super(); m_cur_edit = null; m_cur_idx = -1; final JPanel xqueries_panel = new JPanel(); xqueries_panel.setLayout(new BorderLayout()); final JPanel button_panel = new JPanel(); button_panel.setLayout(new GridLayout(5,1)); MyQueryEntryListModel mdl = new MyQueryEntryListModel(); query_list = new JList(mdl); query_list.setPreferredSize(new Dimension(300,200)); final JButton b_add = new JButton("Add"); final JButton b_load_template = new JButton("Load template..."); b_load_template.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { String filename = choose_template(); if (filename != null) { load_queries(query_list, filename, false); } } }); final JButton b_append_template = new JButton("Append template..."); b_append_template.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { String filename = choose_template(); if (filename != null) { load_queries(query_list, filename, true); } } }); final JButton b_save_template = new JButton("Save template..."); b_save_template.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { String filename = save_template(); if (filename != null) { save_queries(query_list, filename); } } }); final JTextArea t_query = new JTextArea(5,80); final JTextField t_name = new JTextField(20); final JList t_result_types = new JList(XMLQueryEntry.rt2items()); t_result_types.setVisibleRowCount(5); t_result_types.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); final JCheckBox t_fail_empty = new JCheckBox("Abort iff no match"); final JCheckBox t_enabled = new JCheckBox("Enabled?"); query_list.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent arg0) { Object sel = query_list.getSelectedValue(); m_cur_idx = query_list.getSelectedIndex(); if (sel == null) { m_cur_edit = null; m_cur_idx = -1; return; } XMLQueryEntry xqe = (XMLQueryEntry) sel; m_cur_edit = xqe; t_name.setText(xqe.getName()); t_query.setText(xqe.getQuery()); t_fail_empty.setSelected(xqe.getFailEmpty()); t_enabled.setSelected(xqe.isEnabled()); t_result_types.setSelectedIndices(XMLQueryEntry.rt2idx(xqe.getWantedResults())); } }); b_add.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { MyQueryEntryListModel lm = (MyQueryEntryListModel) query_list.getModel(); if (lm != null) lm.add(new XMLQueryEntry(lm.getSize()+1)); } }); final JButton b_load_builtin = new JButton("Load Builtin Template"); b_load_builtin.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { new BuiltinTemplateListDialog(); } }); final JButton b_remove = new JButton("Remove"); b_remove.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MyQueryEntryListModel lm = (MyQueryEntryListModel) query_list.getModel(); Object cur = query_list.getSelectedValue(); if (cur == null || lm == null) return; lm.remove((XMLQueryEntry)cur); if (cur == m_cur_edit) { m_cur_edit = null; m_cur_idx = -1; } } }); button_panel.add(b_add); button_panel.add(b_load_builtin); button_panel.add(b_load_template); button_panel.add(b_append_template); button_panel.add(b_save_template); button_panel.add(b_remove); query_list.setCellRenderer(new MyQueryEntryRenderer()); xqueries_panel.add(new JScrollPane(query_list), BorderLayout.CENTER); xqueries_panel.add(button_panel, BorderLayout.WEST); final JPanel text_panel = new JPanel(); text_panel.setBorder(BorderFactory.createTitledBorder("Edit XQuery")); text_panel.setLayout(new BorderLayout()); final JPanel left_panel = new JPanel(); left_panel.setLayout(new BorderLayout()); left_panel.add(t_name, BorderLayout.NORTH); t_name.getDocument().addDocumentListener(new DocumentListener() { private void do_update(Document doc) { try { if (m_cur_edit != null && doc != null) { m_cur_edit.setName(doc.getText(0, doc.getLength())); query_list.repaint(); } } catch (Exception e) { // silent } } @Override public void changedUpdate(DocumentEvent arg0) { do_update(arg0.getDocument()); } @Override public void insertUpdate(DocumentEvent arg0) { do_update(arg0.getDocument()); } @Override public void removeUpdate(DocumentEvent arg0) { do_update(arg0.getDocument()); } }); final JPanel checkbox_panel = new JPanel(); checkbox_panel.setLayout(new GridLayout(2,1)); checkbox_panel.add(t_fail_empty); checkbox_panel.add(t_enabled); t_enabled.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { if (m_cur_edit != null) { m_cur_edit.setEnabled(t_enabled.isSelected()); query_list.repaint(); } } }); t_fail_empty.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { if (m_cur_edit != null) { m_cur_edit.setFailEmpty(t_fail_empty.isSelected()); query_list.repaint(); } } }); left_panel.add(checkbox_panel, BorderLayout.CENTER); left_panel.add(t_result_types, BorderLayout.SOUTH); t_result_types.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent arg0) { ResultsType[] sel = XMLQueryEntry.item2rt(t_result_types.getSelectedValues()); if (m_cur_edit != null) { m_cur_edit.setResults(sel); query_list.repaint(); } } }); text_panel.add(left_panel, BorderLayout.WEST); text_panel.add(new JScrollPane(t_query), BorderLayout.CENTER); t_query.getDocument().addDocumentListener(new DocumentListener() { private void do_update(Document doc) { try { if (m_cur_edit != null && doc != null) { m_cur_edit.setQuery(doc.getText(0, doc.getLength())); query_list.repaint(); } } catch (BadLocationException e) { // be silent (should not normally occur) } } @Override public void changedUpdate(DocumentEvent arg0) { do_update(arg0.getDocument()); } @Override public void insertUpdate(DocumentEvent arg0) { do_update(arg0.getDocument()); } @Override public void removeUpdate(DocumentEvent arg0) { do_update(arg0.getDocument()); } }); xqueries_panel.add(text_panel, BorderLayout.SOUTH); this.removeTab("Options"); this.addTabAt(0, "XQueries", xqueries_panel); createNewTab("Data Source"); addDialogComponent(new DialogComponentColumnNameSelection(new SettingsModelString(XQueryProcessorNodeModel.CFGKEY_XML_COL, "XML Data"), "XML Data Column", 0, new ColumnFilter() { @Override public boolean includeColumn(DataColumnSpec colSpec) { boolean result = colSpec.getType().equals(XMLCell.TYPE); return result; } @Override public String allFilteredMsg() { return "No XML columns (please use an XML Reader node to load the data)!"; } })); } protected static String choose_template() { JFileChooser jfc = new JFileChooser(); jfc.addChoosableFileFilter(new FileFilter() { @Override public boolean accept(File arg0) { if (arg0.isDirectory() || arg0.getAbsolutePath().toLowerCase().endsWith(".xmlr")) { return true; } return false; } @Override public String getDescription() { return "XML Query Templates (.xmlr)"; } }); jfc.setDialogTitle("Select an XML query template..."); int action = jfc.showOpenDialog(null); if (action == JFileChooser.APPROVE_OPTION && jfc.getSelectedFile() != null) { return jfc.getSelectedFile().getAbsolutePath(); } return null; } protected static void load_queries(JList query_list, String filename, boolean append) { ListModel lm = query_list.getModel(); try { if (!append) { lm = new MyQueryEntryListModel(); query_list.setModel(lm); } BufferedReader br = new BufferedReader(new FileReader(filename)); String line; MyQueryEntryListModel qlm = (MyQueryEntryListModel) lm; while ((line = br.readLine()) != null) { byte[] vec = Base64.decodeBase64(line.getBytes()); String xqe_serialised = new String(vec); if (xqe_serialised.trim().length() > 0) { XMLQueryEntry xqe = new XMLQueryEntry(xqe_serialised); qlm.add(xqe); } } br.close(); } catch (Exception e) { Logger.getAnonymousLogger().warning(e.getMessage()); e.printStackTrace(); } } protected static void save_queries(JList query_list, String filename) { ListModel lm = query_list.getModel(); try { PrintWriter os = new PrintWriter(filename); for (int i=0; i<lm.getSize(); i++) { Object cur = lm.getElementAt(i); if (cur instanceof XMLQueryEntry) { String xqe_serialised = cur.toString(); byte[] vec = xqe_serialised.getBytes(); os.println(new String(Base64.encodeBase64(vec))); } } os.close(); } catch (Exception e) { Logger.getAnonymousLogger().warning(e.getMessage()); e.printStackTrace(); } } protected static String save_template() { JFileChooser jfc = new JFileChooser(); int action = jfc.showSaveDialog(null); if (action == JFileChooser.APPROVE_OPTION && jfc.getSelectedFile() != null) { String sel_file = jfc.getSelectedFile().getAbsolutePath(); if (!sel_file.endsWith(".xmlr")) { sel_file += ".xmlr"; } return sel_file; } return null; } @Override public void loadAdditionalSettingsFrom(final NodeSettingsRO settings, final DataTableSpec[] specs) throws NotConfigurableException { try { String[] vec = settings.getStringArray(XQueryProcessorNodeModel.CFGKEY_QUERIES); query_list.setModel(new MyQueryEntryListModel(vec)); } catch (InvalidSettingsException e) { // use default constructor, rather than loaded from model e.printStackTrace(); query_list.setModel(new MyQueryEntryListModel()); } } @Override public void saveAdditionalSettingsTo(NodeSettingsWO settings) throws InvalidSettingsException { ListModel lm = query_list.getModel(); if (lm instanceof MyQueryEntryListModel) { MyQueryEntryListModel my_lm = (MyQueryEntryListModel) lm; settings.addStringArray(XQueryProcessorNodeModel.CFGKEY_QUERIES, my_lm.getStringArrayValue()); } else { throw new InvalidSettingsException("Unknown list model: cannot save state!"); } } }