001package jmri.jmrix.bidib.serialdriver;
002
003import java.awt.AWTEvent;
004import java.awt.Color;
005import java.awt.event.ActionEvent;
006import java.awt.event.ActionListener;
007import java.awt.event.FocusEvent;
008import java.awt.event.FocusListener;
009import java.awt.event.ItemEvent;
010import java.util.List;
011import java.util.Vector;
012import javax.swing.JCheckBox;
013import javax.swing.JComboBox;
014import javax.swing.JLabel;
015import javax.swing.JTextField;
016import org.bidib.jbidibc.messages.utils.ByteUtils;
017//import org.bidib.jbidibc.scm.ScmPortIdentifierUtils;
018import org.slf4j.Logger;
019import org.slf4j.LoggerFactory;
020
021/**
022 * Definition of objects to handle configuring a layout connection via a BiDiB
023 * SerialDriverAdapter object.
024 *
025 * @author Bob Jacobsen Copyright (C) 2001, 2003
026 * @author Eckart Meyer Copyright (C) 2019
027 */
028public class ConnectionConfig extends jmri.jmrix.AbstractSerialConnectionConfig {
029
030    public final static String NAME = Bundle.getMessage("TypeSerial");
031//    protected JCheckBox useAutoScan = new JCheckBox(Bundle.getMessage("Use Autoscan"));
032    // TODO: use Bundle for localization of the field text
033    protected JCheckBox useAutoScan = new JCheckBox("Use Autoscan");
034    protected JLabel rootNodeLabel = new JLabel("Root Node (hex):");
035    protected JTextField rootNodeField = new JTextField(16);
036    protected JLabel portNameFilterLabel = new JLabel("Port Name Filter:");
037    protected JTextField portNameFilterField = new JTextField(15);
038
039    /**
040     * Ctor for an object being created during load process; Swing init is
041     * deferred.
042     *
043     * @param p SerialPortAdapter for existing adapter
044     */
045    public ConnectionConfig(jmri.jmrix.SerialPortAdapter p) {
046        super(p);
047    }
048
049    /**
050     * Ctor for a functional Swing object with no existing adapter
051     */
052    public ConnectionConfig() {
053        super();
054    }
055
056    @Override
057    public String name() {
058        return NAME;
059    }
060
061    /**
062     * {@inheritDoc}
063     */
064    @Override
065    protected void setInstance() {
066        log.debug("BiDiB Simulator ConnectionConfig.setInstance: {}", adapter);
067        if (adapter == null) {
068            adapter = new SerialDriverAdapter();
069            log.debug("-- adapter created: {}", adapter);
070        }
071    }
072    
073    /**
074     * {@inheritDoc}
075     */
076    @Override
077//    @SuppressWarnings("UseOfObsoleteCollectionType")
078    public Vector<String> getPortNames() {
079        // used for SCM - will prepend "/dev" fpr Linux
080        Vector<String> portNameVector = new Vector<>();
081        try {
082            List<String> portNameList = ((SerialDriverAdapter)adapter).getPortIdentifiers();
083            for (String portName : portNameList) {
084                portNameVector.addElement(portName);
085            }
086        }
087        catch (Exception ex) {
088            log.error("Serial adapter not set: ", ex); // NOSONAR
089        }
090//        List<String> portNameList = SerialDriverAdapter.getPortIdentifiers();
091        log.trace("getPortNames done {}", portNameVector);
092        return portNameVector;
093    }
094    
095    /**
096     * {@inheritDoc}
097     */
098    @Override
099    protected void checkInitDone() {
100        super.checkInitDone();
101        log.debug("checkInitDone");
102        if (adapter.getSystemConnectionMemo() != null) {
103            SerialDriverAdapter a = (SerialDriverAdapter)adapter;
104            rootNodeField.setText(ByteUtils.formatHexUniqueId(a.getRootNodeUid()));
105            portNameFilterField.setText(a.getPortNameFilter());
106            useAutoScan.setSelected(a.getUseAutoScan());
107            if (a.getUseAutoScan()) {
108                rootNodeField.setEnabled(true);
109                portBox.setEnabled(false);
110            }
111            else {
112                rootNodeField.setEnabled(false);
113                portBox.setEnabled(true);
114            }
115            // add listeners
116            // portBox combobox
117            portBox.addActionListener(new ActionListener() {
118                @Override
119                public void actionPerformed(ActionEvent e) {
120                    log.debug("portBox action!");
121                    portBoxChanged(e);
122                }
123            });
124            // rootNode field
125            rootNodeField.addActionListener(new ActionListener() {
126                @Override
127                public void actionPerformed(ActionEvent e) {
128                    log.debug("rootNodeUID action!");
129                    rootNodeUidChanged(e);
130                }
131            });
132            rootNodeField.addFocusListener(new FocusListener() {
133                @Override
134                public void focusLost(FocusEvent e) {
135                    log.debug("rootNodeUID focus lost!");
136                    rootNodeUidChanged(e);
137                }
138                @Override
139                public void focusGained(FocusEvent e) {
140                }
141            });
142            // portNameFilter field
143            portNameFilterField.addActionListener(new ActionListener() {
144                @Override
145                public void actionPerformed(ActionEvent e) {
146                    log.debug("portNameFilter action!");
147                    portNameFilterChanged(e);
148                }
149            });
150            portNameFilterField.addFocusListener(new FocusListener() {
151                @Override
152                public void focusLost(FocusEvent e) {
153                    log.debug("portNameFilter focus lost!");
154                    portNameFilterChanged(e);
155                }
156                @Override
157                public void focusGained(FocusEvent e) {
158                }
159            });
160            // useAutoScan checkbox
161            useAutoScan.addItemListener((ItemEvent e) -> {
162                log.debug("useAutoScan changed!");
163                a.setUseAutoScan(useAutoScan.isSelected());
164                rootNodeField.setEnabled(useAutoScan.isSelected());
165                portBox.setEnabled(!useAutoScan.isSelected());
166            });
167            
168            baudBox.setEnabled(false);// Bidib SCM always tries to find the the baudrate itself, the user cannot select
169        }
170    }
171
172    @SuppressWarnings (value="unchecked") //because of the unchecked cast of the event object. but we can be sure here...
173    private void portBoxChanged(AWTEvent e) {
174        SerialDriverAdapter a = (SerialDriverAdapter)adapter;
175        String fieldtext = ((JComboBox<String>)e.getSource()).getSelectedItem().toString();
176        log.debug("portBox selected: {}", fieldtext);
177        if (!a.getUseAutoScan()) {
178            //Long uid = SerialDriverAdapter.checkPort(fieldtext); //call static function
179            Long uid = a.checkPort(fieldtext); //call static function
180            if (uid == null) {
181                a.setRootNodeUid(null);
182                rootNodeField.setText("");
183            }
184            else {
185                a.setRootNodeUid(uid);
186                //rootNodeField.setText(String.format("0x%X", a.getRootNodeUid() & 0xffffffffffffffL));
187                rootNodeField.setText(ByteUtils.formatHexUniqueId(a.getRootNodeUid()));
188            }
189        }
190    }
191    
192    private void rootNodeUidChanged(AWTEvent e) {
193        SerialDriverAdapter a = (SerialDriverAdapter)adapter;
194        String fieldtext = ((JTextField)e.getSource()).getText();
195        if (fieldtext.isEmpty()) {
196            //a.setRootNodeUid(null); //don't set
197        }
198        else {
199            try {
200                if (a.getUseAutoScan()) {
201                    Long uid = ByteUtils.parseHexUniqueId(fieldtext);
202                    String err = a.findPortbyUniqueID(uid);
203                    if (err == null) {
204                        log.info("found port name for UID {} is {}",
205                                    ByteUtils.formatHexUniqueId(a.getRootNodeUid()), a.getCurrentPortName());
206                        a.setRootNodeUid(uid);
207                        //rootNodeField.setText(String.format("0x%X", a.getRootNodeUid() & 0x0000ffffffffffL));
208                        rootNodeField.setText(ByteUtils.formatHexUniqueId(a.getRootNodeUid()));
209                        // TODO set portBox
210                        rootNodeField.setForeground(Color.black);
211                        portBox.setSelectedItem(a.getCurrentPortName());
212                    }
213                    else {
214                        log.warn(err);
215                        rootNodeField.setForeground(Color.red);
216                    }
217                }
218            }
219            catch (NumberFormatException ex) {
220                a.setRootNodeUid(null);
221                rootNodeField.setText("");
222                log.warn("Exception:", ex);
223            }
224        }
225    }
226    
227    private void portNameFilterChanged(AWTEvent e) {
228        SerialDriverAdapter a = (SerialDriverAdapter)adapter;
229        // String s = a.getCurrentPortName();
230        String fieldtext = ((JTextField)e.getSource()).getText();
231        a.setPortNameFilter(fieldtext);
232        refreshPortBox();
233    }
234    
235    /**
236     * {@inheritDoc}
237     */
238    @Override
239    protected void showAdvancedItems() {
240        super.showAdvancedItems(); // we're adding to the normal advanced items.
241        log.debug("showAdvancedItems");
242        if (adapter.getSystemConnectionMemo() != null) {
243            cR.gridy += 2;
244            cL.gridy += 2;
245            gbLayout.setConstraints(rootNodeLabel, cL);
246            gbLayout.setConstraints(rootNodeField, cR);
247            _details.add(rootNodeLabel);
248            //rootNodeField.setEnabled(false);
249            _details.add(rootNodeField);
250            
251            cR.gridy += 2;
252            cL.gridy += 2;
253            gbLayout.setConstraints(useAutoScan, cL);
254            useAutoScan.setFont(useAutoScan.getFont().deriveFont(9f));
255            useAutoScan.setForeground(Color.blue);
256            _details.add(useAutoScan);
257
258            cR.gridy += 2;
259            cL.gridy += 2;
260            gbLayout.setConstraints(portNameFilterLabel, cL);
261            gbLayout.setConstraints(portNameFilterField, cR);
262            _details.add(portNameFilterLabel);
263            _details.add(portNameFilterField);
264        }
265        if (_details.getParent() != null) {
266            _details.getParent().revalidate();
267            _details.getParent().repaint();
268        }
269    }
270    
271    @Override
272    public void updateAdapter() {
273        super.updateAdapter(); // we're adding more details to the connection.
274        log.debug("updateAdapter");
275        SerialDriverAdapter a = (SerialDriverAdapter)adapter;
276        if (adapter.getSystemConnectionMemo() != null) {
277            a.setUseAutoScan(useAutoScan.isSelected());
278            a.setRootNodeUid(ByteUtils.parseHexUniqueId(rootNodeField.getText()));
279            a.setPortNameFilter(portNameFilterField.getText());
280        }
281    }
282
283
284    private final static Logger log = LoggerFactory.getLogger(ConnectionConfig.class);
285}