package org.das2.client; import java.awt.Dimension; import java.awt.Component; import java.awt.FlowLayout; import java.io.IOException; import javax.swing.JPanel; import javax.swing.BoxLayout; import javax.swing.JOptionPane; import javax.swing.JCheckBox; import javax.swing.JTextArea; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.JList; import java.util.LinkedHashMap; import java.util.ArrayList; import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathConstants; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilderFactory; import java.io.StringReader; import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.Box; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; /** * Code for editing a Das2Server parameters argument. This is a somewhat * arbitary control, but the DSDF may try to describe a GUI, using the * spec at https://github.com/das-developers/das2docs/wiki/Structured-Sub%E2%80%90values-for-Params * * * Das2ServerGUI x = new Das2ServerGUI(); * String dsdf = "param_01 = '1.5V_REF | Simulate +1.8 monitor'\n" * + "param_02 = '1.5V_WvFE'\n" * + "param_03 = '1.5V_Y180'\n" * + "param_04 = '1.8U | Power Supply'\n" * + "param_05 = '1.8V_MEM'"; * x.setSpecification(dsdf); * x.setParameters("1.5V_REF 1.5V_REF 1.8V_MEM"); * if (JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(null, x.panel)) { * System.err.println(x.getParameters()); * } * * @author jbf */ public class Das2ServerGUI { /** * Read the Das2Server container for DSDF * * @param xmlsrc * @return string array * @throws SAXException * @throws IOException * @throws ParserConfigurationException * @throws XPathExpressionException */ private static Control[] readXML(String xmlsrc) throws SAXException, IOException, ParserConfigurationException, XPathExpressionException { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(true); DocumentBuilder builder = domFactory.newDocumentBuilder(); InputSource inputsrc = new InputSource(new StringReader(xmlsrc)); Document doc = builder.parse(inputsrc); XPath xp = XPathFactory.newInstance().newXPath(); Node nn = (Node) xp.evaluate("//properties", doc, XPathConstants.NODE); ArrayList ll = new ArrayList(MAX_CONTROLS); for (int i = 0; i < MAX_CONTROLS; i++) { ll.add(i, ""); } NamedNodeMap aa = nn.getAttributes(); for (int i = 0; i < aa.getLength(); i++) { Node itm = aa.item(i); if (itm.getNodeName().startsWith("param_")) { int idx = Integer.parseInt(itm.getNodeName().substring(6)); ll.set(idx, itm.getNodeValue()); } } Control[] controls= new Control[MAX_CONTROLS]; for ( int i=0; i ll = new ArrayList<>(MAX_CONTROLS-1); for (int i = 0; i < MAX_CONTROLS-1; i++) { ll.add(i, ""); } for (String line : dsdfsrc.split("\n")) { if (line.startsWith("param_")) { int ieq = line.indexOf("="); int idx = parseInt(line.substring(0, ieq).substring(6)); String vv = line.substring(ieq + 1).trim(); if ((vv.charAt(0) == '\'') && (vv.charAt(vv.length() - 1) == '\'')) { vv = vv.substring(1, vv.length() - 1); } ll.set(idx, vv); } } Control[] controls= new Control[MAX_CONTROLS]; for ( int i=0; i -1) { tp.setSelected(true); } } catch (Exception e) { continue; } } } private List getSelectedListItems(Component jcomponent) { if (jcomponent instanceof JList) { return ((JList) jcomponent).getSelectedValuesList(); } else { ArrayList resultList = new ArrayList(); JPanel jList = (JPanel) jcomponent; for (Component c : jList.getComponents()) { if ( c instanceof JCheckBox ) { JCheckBox b = (JCheckBox) c; if (b.isSelected()) { resultList.add(b.getText()); } } } return resultList; } } private String getRegex(String t) { // "Return the regular expression for the template. The first field will be the @ symbol value"; return t.replaceAll("@", "(\\S+)"); } private static class Control { private Control(String line) { this.ll= line; } /** * the line */ String ll; /** * the type */ String tt; /** * formats (e.g. --dftlen @) */ String ff; /** * special arguments for the GUI type, like sep */ String ss; /** * the component implementing the control */ JComponent cc; } private static final int MAX_CONTROLS=101; private Control[] controls; private JPanel panel; /** * set the DSDF specification for the parameters. This can be an XML document * or a list of IDL name/value pairs. * @param sss */ public void setSpecification(String sss) { if ( sss.length()<4 ) { throw new IllegalArgumentException("control string is too short"); } if ( sss.substring(0, 4).equals("[00]") ){ sss = sss.substring(10); } if ( sss.trim().startsWith("<") ) { try { controls = readXML(sss); } catch (SAXException | IOException | ParserConfigurationException | XPathExpressionException ex) { Logger.getLogger("das2").log(Level.SEVERE, null, ex); } } else { controls = readDsdf(sss); } controls[MAX_CONTROLS-1]= new Control(""); // last control is used to capture everything not recognized. } public void setParameters(String paramz) { String delim= "\\s+"; //TODO: delim String delimRaw=" "; String[] paramsArr = paramz.split(delim); panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.setAlignmentX(0.0f); boolean addedFirst= false; boolean extra = false; for (int i = 0; i < 100; i++) { Control contrl= controls[i]; String itm = contrl.ll; if (itm.length() > 0) { if ( addedFirst ) { panel.add( Box.createVerticalStrut( panel.getFont().getSize() ) ); } itm = itm.trim(); String[] ss = itm.split("\\s*\\|\\s*", -2); int narg = ss.length; JComponent c2 = null; JComponent row= null; String title= narg>1 ? ss[1] : ""; if ( title.contains("\\n") ) { title= ""+title.replaceAll("\\\\n","
"); } if (narg == 1) { JCheckBox c = new JCheckBox(ss[0]); String vv = findParamValue(paramsArr, ss[0], null); if (vv.length() > 0) { c.setSelected(true); } contrl.tt = "JCheckBox"; contrl.ss = ss[0]; panel.add(c); c2 = c; } else if (narg == 2) { JCheckBox c = new JCheckBox(ss[0] + ": " + title); String vv = findParamValue(paramsArr, ss[0], null); if (vv.length() > 0) { c.setSelected(true); } contrl.tt = "JCheckBox"; contrl.ss = ss[0]; panel.add(c); c2 = c; } else if (narg == 3) { if ( isFlagOrSwitch( ss[2]) ) { JCheckBox cb= new JCheckBox(title + " (" + ss[2] + ")" ); panel.add( cb ); String vv = findParamValue(paramsArr, ss[2], null); cb.setSelected(vv.length()>0); contrl.tt = "JCheckBox"; contrl.ss = ss[2]; c2= cb; } else { panel.add( new JLabel(title) ); JTextField c = new JTextField(""); c.setMaximumSize(new Dimension(8000, c.getPreferredSize().height)); String vv = findParamValue(paramsArr, ss[0], null); contrl.ff = ss[2]; vv = findParamValue(paramsArr, ss[0], ss[2]); if (vv.length() > 0) { c.setText(vv); } contrl.tt = "JTextField"; panel.add(c); row = getRow( new JLabel(ss[0]+": "), c ); c2= c; } } else if (narg == 4) { if (ss[3].startsWith("set:")) { panel.add(new JLabel(title)); String[] sepAllItems = ss[3].substring(4).trim().split("\\s+"); String[] allItems = Arrays.copyOfRange(sepAllItems, 1, sepAllItems.length); String sep = sepAllItems[0]; contrl.ss = sep; JPanel panel1 = new JPanel(); panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS)); panel1.add( new JLabel(ss[0]+ ":" )); for (String item : allItems) { JCheckBox b1 = new JCheckBox(item); b1.setSelected(false); panel1.add(b1); } c2 = panel1; String itemMatch = String.join("|", allItems); String regex = String.format("^(%s)(?:%s(%s))*$", itemMatch, sep, itemMatch); String vv = findParamValue(paramsArr, ss[0], regex); if (vv.length() > 0) { String[] items = vv.split(sep); setSelectedListItems(c2, allItems, items); } contrl.tt = "JList"; } else if ( ss[3].startsWith("option:") ) { panel.add(new JLabel( title )); String[] options= ss[3].substring(8).trim().split("\\s+"); String[] options1= new String[options.length+1]; options1[0]= ""; System.arraycopy( options, 0, options1, 1, options.length); options= options1; JComboBox c = new JComboBox(options); row = getRow( new JLabel(ss[0]+": "), c ); c2= c; c.setMaximumSize(new Dimension(8000, c.getPreferredSize().height)); String vv = findParamValue(paramsArr, ss[0], null); contrl.ff = ss[2]; vv = findParamValue(paramsArr, ss[0], ss[2]); if (vv.length() > 0) { c.setSelectedItem(vv); } contrl.tt = "JComboBox"; } else { panel.add( new JLabel(title) ); JTextField c = new JTextField(""); row = getRow( new JLabel(ss[0]+": "), c ); c2= c; c.setMaximumSize(new Dimension(8000, c.getPreferredSize().height)); String vv = findParamValue(paramsArr, ss[0], null); contrl.ff = ss[2]; vv = findParamValue(paramsArr, ss[0], ss[2]); if (vv.length() > 0) { c.setText(vv); } contrl.tt = "JTextField"; } if ( row==null ) { panel.add(c2); } else { panel.add(row); } } else { extra = true; } if (c2 != null) { if ( row==null ) { panel.add(c2); } else { panel.add(row); } contrl.cc = c2; c2.setAlignmentX(Component.LEFT_ALIGNMENT); } addedFirst= true; } } StringBuilder extraArgs= new StringBuilder(); for ( int i=0; i0 ) { extraArgs.append(paramsArr[i]); } if ( i>0 ) extraArgs.append(delimRaw); } if ( extra || extraArgs.length()>0 ) { if ( addedFirst ) { panel.add( Box.createVerticalStrut( panel.getFont().getSize() ) ); } panel.add(new JLabel("Text not described in DSDF")); JTextArea c = new JTextArea(); c.setAlignmentX(Component.LEFT_ALIGNMENT); c.setText(extraArgs.toString()); c.setRows(4); panel.add(c); controls[100].cc = c; } } public String getParameters() { String delim = " "; StringBuilder parametersBuilder = new StringBuilder(); for (int i = 0; i < 100; i++) { if (controls[i].cc == null) { } else if (controls[i].tt.equals("JCheckBox")) { if (((JCheckBox) controls[i].cc).isSelected()) { String txt = controls[i].ss; parametersBuilder.append(txt); parametersBuilder.append(delim); } } else if (controls[i].tt.equals("JTextField")) { String s = ((JTextField) controls[i].cc).getText(); if (s.trim().length() > 0) { s = controls[i].ff.replace("@", s); parametersBuilder.append(s); parametersBuilder.append(delim); } } else if (controls[i].tt.equals("JList")) { List selectedItems = getSelectedListItems(controls[i].cc); String sep = controls[i].ss; parametersBuilder.append(String.join(sep, selectedItems)); parametersBuilder.append(delim); } else if (controls[i].tt.equals("JComboBox")) { String s= String.valueOf(((JComboBox)controls[i].cc).getSelectedItem()); if ( s.trim().length()>0 ) { s = controls[i].ff.replace("@", s); parametersBuilder.append(s); parametersBuilder.append(delim); } } } if (controls[100].cc != null) { parametersBuilder.append(delim); String txt = ((JTextArea) controls[100].cc).getText().replace("\n", delim); txt = txt.trim(); parametersBuilder.append(txt); } return parametersBuilder.toString(); } /** * return the panel. See the javadoc for how this is to be called. * Note this will typically need to be put into a scrollpane. * @return */ public JPanel getPanel() { return panel; } private JComponent getRow(JComponent jLabel, JComponent c) { JPanel result= new JPanel(); result.setLayout( new BoxLayout(result,BoxLayout.X_AXIS) ); result.add(jLabel); result.add(c); result.setAlignmentX(0.0f); return result; } private boolean isFlagOrSwitch(String ss3) { if (ss3.startsWith("set:")) { return false; } else if ( ss3.startsWith("option:") ) { return false; } else { return true; } } }