001package jmri.jmrit.logixng.expressions.swing;
002
003import java.lang.reflect.InvocationTargetException;
004import java.util.List;
005
006import javax.annotation.CheckForNull;
007import javax.annotation.Nonnull;
008import javax.swing.*;
009
010import jmri.InstanceManager;
011import jmri.jmrit.logixng.Base;
012import jmri.jmrit.logixng.DigitalExpressionManager;
013import jmri.jmrit.logixng.MaleSocket;
014import jmri.jmrit.logixng.expressions.ConnectionName;
015import jmri.jmrix.*;
016import static jmri.jmrix.JmrixConfigPane.NONE_SELECTED;
017import jmri.util.swing.JComboBoxUtil;
018
019/**
020 * Configures an ConnectionName object with a Swing JPanel.
021 *
022 * @author Daniel Bergqvist Copyright 2022
023 */
024public class ConnectionNameSwing extends AbstractDigitalExpressionSwing {
025
026    private final ConnectionConfigManager manager =
027            InstanceManager.getDefault(ConnectionConfigManager.class);
028
029    private JComboBox<String> _manufacturerComboBox;
030    private JComboBox<String> _connectionComboBox;
031    private ConnectionConfig[] _connectionConfigs;
032
033    public ConnectionNameSwing() {
034    }
035
036    public ConnectionNameSwing(JDialog dialog) {
037        super.setJDialog(dialog);
038    }
039
040    @Override
041    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
042        // Create a temporary action if object is null
043        final ConnectionName action = (object != null)
044                ? (ConnectionName) object
045                : new ConnectionName("IQDE1", null);
046
047        String[] manufactureNameList = manager.getConnectionManufacturers();
048        _connectionConfigs = manager.getConnections();
049
050        panel = new JPanel();
051
052        String selectedManufacturer = action.getManufacturer();
053        if (selectedManufacturer == null
054                || selectedManufacturer.isBlank()
055                || NONE_SELECTED.equals(selectedManufacturer)) {
056            if (_connectionConfigs.length > 0) {
057                selectedManufacturer = _connectionConfigs[0].getManufacturer();
058            }
059        }
060
061        JPanel manufacturerPanel = new JPanel();
062        manufacturerPanel.setLayout(new BoxLayout(manufacturerPanel, BoxLayout.Y_AXIS));
063
064        var mLabel = new JPanel();
065        mLabel.add(new JLabel(Bundle.getMessage("ExpressionConnection_Manufacturer")));
066        manufacturerPanel.add(mLabel);
067
068        _manufacturerComboBox = new JComboBox<>();
069        manufacturerPanel.add(_manufacturerComboBox);
070
071        for (String manuName : manufactureNameList) {
072            _manufacturerComboBox.addItem(manuName);
073            if (manuName.equals(selectedManufacturer)) {
074                _manufacturerComboBox.setSelectedItem(selectedManufacturer);
075            }
076        }
077        if (_manufacturerComboBox.getSelectedIndex() == -1) {
078            _manufacturerComboBox.setSelectedIndex(0);
079        }
080
081        JPanel connectionNamePanel = new JPanel();
082        connectionNamePanel.setLayout(new BoxLayout(connectionNamePanel, BoxLayout.Y_AXIS));
083
084        var cLabel = new JPanel();
085        cLabel.add(new JLabel(Bundle.getMessage("ExpressionConnection_Connection")));
086        connectionNamePanel.add(cLabel);
087
088        _connectionComboBox = new JComboBox<>();
089        connectionNamePanel.add(_connectionComboBox);
090
091        _manufacturerComboBox.addActionListener((evt) -> {
092            updateConnectionComboBox(action);
093        });
094
095        updateConnectionComboBox(action);
096
097        JComboBoxUtil.setupComboBoxMaxRows(_manufacturerComboBox);
098        JComboBoxUtil.setupComboBoxMaxRows(_connectionComboBox);
099
100
101        panel.add(manufacturerPanel);
102        panel.add(connectionNamePanel);
103    }
104
105    private void updateConnectionComboBox(ConnectionName action) {
106        String selectedManufacturer = (String) _manufacturerComboBox.getSelectedItem();
107        String[] classConnectionNameList = manager.getConnectionTypes(selectedManufacturer);
108
109        String selectedConnectionName = null;
110
111        if (selectedManufacturer.equals(action.getManufacturer())) {
112            selectedConnectionName = action.getConnectionName();
113        }
114        if (selectedConnectionName == null
115                || selectedConnectionName.isBlank()
116                || NONE_SELECTED.equals(selectedConnectionName)) {
117            for (int i=0; i < _connectionConfigs.length; i++) {
118                if (_connectionConfigs[i].getManufacturer().equals(selectedManufacturer)) {
119                    selectedConnectionName = _connectionConfigs[i].name();
120                }
121            }
122        }
123
124        _connectionComboBox.removeAllItems();
125        _connectionComboBox.addItem(NONE_SELECTED);
126
127        for (String className : classConnectionNameList) {
128            try {
129                Class<?> cl = Class.forName(className);
130                ConnectionConfig config = (ConnectionConfig) cl.getDeclaredConstructor().newInstance();
131                if( !(config instanceof StreamConnectionConfig)) {
132                    // only include if the connection is not a
133                    // StreamConnection.  Those connections require
134                    // additional context.
135                    if (config != null) {
136                        _connectionComboBox.addItem(config.name());
137                        if (config.name().equals(selectedConnectionName)) {
138                            _connectionComboBox.setSelectedItem(selectedConnectionName);
139                        }
140                    }
141                }
142            } catch (NullPointerException e) {
143                log.error("Attempt to load {} failed.", className, e);
144            } catch (InvocationTargetException | ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
145                log.error("Attempt to load {} failed", className, e);
146            }
147        }
148
149        // Resize dialog if needed
150        JDialog dialog = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, _manufacturerComboBox);
151        if (dialog != null) dialog.pack();
152    }
153
154    /** {@inheritDoc} */
155    @Override
156    public boolean validate(@Nonnull List<String> errorMessages) {
157        return true;
158    }
159
160    /** {@inheritDoc} */
161    @Override
162    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
163        ConnectionName action = new ConnectionName(systemName, userName);
164        updateObject(action);
165        return InstanceManager.getDefault(DigitalExpressionManager.class).registerExpression(action);
166    }
167
168    /** {@inheritDoc} */
169    @Override
170    public void updateObject(@Nonnull Base object) {
171        if (! (object instanceof ConnectionName)) {
172            throw new IllegalArgumentException("object must be an ConnectionName but is a: "+object.getClass().getName());
173        }
174        ConnectionName action = (ConnectionName) object;
175
176        if (_manufacturerComboBox.getSelectedIndex() != -1) {
177            action.setManufacturer(_manufacturerComboBox.getItemAt(_manufacturerComboBox.getSelectedIndex()));
178        }
179        if (_connectionComboBox.getSelectedIndex() != -1) {
180            action.setConnectionName(_connectionComboBox.getItemAt(_connectionComboBox.getSelectedIndex()));
181        }
182    }
183
184    /** {@inheritDoc} */
185    @Override
186    public String toString() {
187        return Bundle.getMessage("ConnectionName_Short");
188    }
189
190    @Override
191    public void dispose() {
192    }
193
194
195    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConnectionNameSwing.class);
196
197}