001package jmri.jmrix.loconet.logixng.swing;
002
003import java.awt.Color;
004import java.awt.event.ActionEvent;
005import java.text.NumberFormat;
006import java.util.*;
007
008import javax.annotation.CheckForNull;
009import javax.annotation.Nonnull;
010import javax.swing.*;
011import javax.swing.text.NumberFormatter;
012
013import jmri.*;
014import jmri.jmrit.logixng.Base;
015import jmri.jmrit.logixng.DigitalExpressionManager;
016import jmri.jmrit.logixng.MaleSocket;
017import jmri.jmrit.logixng.expressions.swing.AbstractDigitalExpressionSwing;
018import jmri.jmrix.loconet.logixng.ExpressionSlotUsage;
019import jmri.jmrix.loconet.logixng.ExpressionSlotUsage.Has_HasNot;
020import jmri.jmrix.loconet.logixng.ExpressionSlotUsage.AdvancedState;
021import jmri.jmrix.loconet.logixng.ExpressionSlotUsage.SimpleState;
022import jmri.jmrix.loconet.logixng.ExpressionSlotUsage.Compare;
023import jmri.jmrix.loconet.logixng.ExpressionSlotUsage.PercentPieces;
024import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
025import jmri.jmrix.loconet.LocoNetSystemConnectionMemo;
026
027/**
028 * Configures an ExpressionTurnout object with a Swing JPanel.
029 *
030 * @author Daniel Bergqvist Copyright 2020
031 */
032public class ExpressionSlotUsageSwing extends AbstractDigitalExpressionSwing {
033
034    private JButton _findNumSlotsButton;
035    private JComboBox<LocoNetConnection> _locoNetConnection;
036    private JTabbedPane _tabbedPane;
037    private JPanel _simplePanel;
038    private JPanel _advancedPanel;
039    private JComboBox<Has_HasNot> _has_HasNot_ComboBox;
040    private JComboBox<SimpleState> _simpleStateComboBox;
041    private JCheckBox _inUseCheckBox;
042    private JCheckBox _idleCheckBox;
043    private JCheckBox _commonCheckBox;
044    private JCheckBox _freeCheckBox;
045    private JComboBox<Compare> _compareComboBox;
046    private JTextField _numberField;
047    private JComboBox<PercentPieces> _percentPiecesComboBox;
048    private JTextField _totalSlotsField;
049    private JPanel _slotsPanel;
050
051    @Override
052    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
053        if ((object != null) && !(object instanceof ExpressionSlotUsage)) {
054            throw new IllegalArgumentException("object must be an ExpressionSlotUsage but is a: "+object.getClass().getName());
055        }
056
057        ExpressionSlotUsage expression = (ExpressionSlotUsage)object;
058
059        _slotsPanel = new JPanel();
060
061        panel = new JPanel();
062        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
063
064        JPanel queryPanel = new JPanel();
065        queryPanel.setBorder(BorderFactory.createLineBorder(Color.black));
066
067        JPanel locoNetPanel = new JPanel();
068        locoNetPanel.add(new JLabel(Bundle.getMessage("LocoNetConnection")));
069
070        _locoNetConnection = new JComboBox<>();
071        List<LocoNetSystemConnectionMemo> systemConnections =
072                jmri.InstanceManager.getList(LocoNetSystemConnectionMemo.class);
073        for (LocoNetSystemConnectionMemo connection : systemConnections) {
074            LocoNetConnection c = new LocoNetConnection(connection);
075            _locoNetConnection.addItem(c);
076            if ((expression != null) && (expression.getMemo() == connection)) {
077                _locoNetConnection.setSelectedItem(c);
078            }
079        }
080        locoNetPanel.add(_locoNetConnection);
081
082        _has_HasNot_ComboBox = new JComboBox<>();
083        for (Has_HasNot e : Has_HasNot.values()) {
084            _has_HasNot_ComboBox.addItem(e);
085        }
086
087        _simpleStateComboBox = new JComboBox<>();
088        for (SimpleState e : SimpleState.values()) {
089            _simpleStateComboBox.addItem(e);
090        }
091
092        _tabbedPane = new JTabbedPane();
093        _simplePanel = new javax.swing.JPanel();
094        _advancedPanel = new javax.swing.JPanel();
095        _advancedPanel.setLayout(new BoxLayout(_advancedPanel, BoxLayout.Y_AXIS));
096
097        _tabbedPane.addTab(Bundle.getMessage("TabbedPaneSimple"), _simplePanel); // NOI1aa8N
098        _tabbedPane.addTab(Bundle.getMessage("TabbedPaneAdvanced"), _advancedPanel); // NOIaa18N
099
100        _simpleStateComboBox = new JComboBox<>();
101        for (SimpleState e : SimpleState.values()) {
102            _simpleStateComboBox.addItem(e);
103        }
104        _simplePanel.add(_simpleStateComboBox);
105
106        _inUseCheckBox = new JCheckBox(Bundle.getMessage("AdvancedStateType_InUse"));
107        _idleCheckBox = new JCheckBox(Bundle.getMessage("AdvancedStateType_Idle"));
108        _commonCheckBox = new JCheckBox(Bundle.getMessage("AdvancedStateType_Common"));
109        _freeCheckBox = new JCheckBox(Bundle.getMessage("AdvancedStateType_Free"));
110        _advancedPanel.add(_inUseCheckBox);
111        _advancedPanel.add(_idleCheckBox);
112        _advancedPanel.add(_commonCheckBox);
113        _advancedPanel.add(_freeCheckBox);
114
115        _compareComboBox = new JComboBox<>();
116        for (Compare e : Compare.values()) {
117            _compareComboBox.addItem(e);
118        }
119
120        NumberFormat format = NumberFormat.getInstance();
121        NumberFormatter formatter = new NumberFormatter(format);
122        formatter.setValueClass(Integer.class);
123        formatter.setMinimum(0);
124        formatter.setMaximum(120);
125        formatter.setAllowsInvalid(false);
126        // If you want the value to be committed on each keystroke instead of focus lost
127        formatter.setCommitsOnValidEdit(true);
128        _numberField = new JFormattedTextField();
129        _numberField.setColumns(3);
130
131        _percentPiecesComboBox = new JComboBox<>();
132        for (PercentPieces e : PercentPieces.values()) {
133            _percentPiecesComboBox.addItem(e);
134        }
135/*
136        _percentPiecesComboBox.addActionListener((ActionEvent e) -> {
137            PercentPieces pp = _percentPiecesComboBox.getItemAt(_percentPiecesComboBox.getSelectedIndex());
138            if (pp == PercentPieces.Percent) _slotsPanel.setVisible(true);
139            else _slotsPanel.setVisible(false);
140            ExpressionSlotUsageSwing.this.getFrame().pack();
141        });
142*/
143        if (expression != null) {
144            if (expression.getAdvanced()) {
145                _tabbedPane.setSelectedComponent(_advancedPanel);
146            }
147
148            if (expression.getAdvancedStates().contains(AdvancedState.InUse)) {
149                _inUseCheckBox.setSelected(true);
150            }
151            if (expression.getAdvancedStates().contains(AdvancedState.Idle)) {
152                _idleCheckBox.setSelected(true);
153            }
154            if (expression.getAdvancedStates().contains(AdvancedState.Common)) {
155                _commonCheckBox.setSelected(true);
156            }
157            if (expression.getAdvancedStates().contains(AdvancedState.Free)) {
158                _freeCheckBox.setSelected(true);
159            }
160
161            _has_HasNot_ComboBox.setSelectedItem(expression.get_Has_HasNot());
162            _simpleStateComboBox.setSelectedItem(expression.getSimpleState());
163            _compareComboBox.setSelectedItem(expression.getCompare());
164            _numberField.setText(Integer.toString(expression.getNumber()));
165            _percentPiecesComboBox.setSelectedItem(expression.getPercentPieces());
166        }
167
168        panel.add(locoNetPanel);
169
170        JComponent[] components = new JComponent[]{
171            _has_HasNot_ComboBox,
172            _tabbedPane,
173            _compareComboBox,
174            _numberField,
175            _percentPiecesComboBox
176            };
177
178        List<JComponent> componentList = SwingConfiguratorInterface.parseMessage(Bundle.getMessage("ExpressionSlotUsage_Long"), components);
179
180        for (JComponent c : componentList) queryPanel.add(c);
181
182        panel.add(queryPanel);
183
184        _slotsPanel.setLayout(new BoxLayout(_slotsPanel, BoxLayout.Y_AXIS));
185        _slotsPanel.add(new JLabel(Bundle.getMessage("InfoTotalSlots1")));
186        _slotsPanel.add(new JLabel(Bundle.getMessage("InfoTotalSlots2")));
187        _slotsPanel.add(new JLabel(Bundle.getMessage("InfoTotalSlots3")));
188
189        JPanel numSlotsPanel = new JPanel();
190        numSlotsPanel.add(new JLabel(Bundle.getMessage("TotalNumSlots")));
191        format = NumberFormat.getInstance();
192        formatter = new NumberFormatter(format);
193        formatter.setValueClass(Integer.class);
194        formatter.setMinimum(0);
195        formatter.setMaximum(120);
196        formatter.setAllowsInvalid(false);
197        // If you want the value to be committed on each keystroke instead of focus lost
198        formatter.setCommitsOnValidEdit(true);
199        _totalSlotsField = new JFormattedTextField();
200        _totalSlotsField.setColumns(3);
201        numSlotsPanel.add(_totalSlotsField);
202        _findNumSlotsButton = new JButton(Bundle.getMessage("GetNumSlots"));
203        _findNumSlotsButton.addActionListener((ActionEvent e) -> {
204            LocoNetSystemConnectionMemo memo =
205                    _locoNetConnection.getItemAt(_locoNetConnection.getSelectedIndex())._memo;
206            new GetNumSlotsDialog(memo, _totalSlotsField).initComponents();
207        });
208        numSlotsPanel.add(_findNumSlotsButton);
209        if (expression != null) {
210            _totalSlotsField.setText(Integer.toString(expression.getTotalSlots()));
211        }
212        _slotsPanel.add(numSlotsPanel);
213
214        panel.add(_slotsPanel);
215    }
216
217    /** {@inheritDoc} */
218    @Override
219    public boolean validate(@Nonnull List<String> errorMessages) {
220        try {
221            Integer.parseInt(_numberField.getText());
222        } catch (NumberFormatException e) {
223            errorMessages.add("Number is not a valid integer");
224            return false;
225        }
226        return true;
227    }
228
229    /** {@inheritDoc} */
230    @Override
231    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
232        LocoNetSystemConnectionMemo memo =
233                _locoNetConnection.getItemAt(_locoNetConnection.getSelectedIndex())._memo;
234
235        ExpressionSlotUsage expression = new ExpressionSlotUsage(systemName, userName, memo);
236        updateObject(expression);
237
238        return InstanceManager.getDefault(DigitalExpressionManager.class).registerExpression(expression);
239    }
240
241    /** {@inheritDoc} */
242    @Override
243    public void updateObject(@Nonnull Base object) {
244        if (! (object instanceof ExpressionSlotUsage)) {
245            throw new IllegalArgumentException("object must be an ExpressionTurnout but is a: "+object.getClass().getName());
246        }
247
248        ExpressionSlotUsage expression = (ExpressionSlotUsage)object;
249
250        expression.setMemo(_locoNetConnection.getItemAt(_locoNetConnection.getSelectedIndex())._memo);
251
252        expression.setAdvanced(_tabbedPane.getSelectedComponent() == _advancedPanel);
253
254        Set<AdvancedState> advancedStates = new HashSet<>();
255        if (_inUseCheckBox.isSelected()) advancedStates.add(AdvancedState.InUse);
256        if (_idleCheckBox.isSelected()) advancedStates.add(AdvancedState.Idle);
257        if (_commonCheckBox.isSelected()) advancedStates.add(AdvancedState.Common);
258        if (_freeCheckBox.isSelected()) advancedStates.add(AdvancedState.Free);
259        expression.setAdvancedStates(advancedStates);
260
261        expression.set_Has_HasNot(_has_HasNot_ComboBox.getItemAt(_has_HasNot_ComboBox.getSelectedIndex()));
262        expression.setSimpleState(_simpleStateComboBox.getItemAt(_simpleStateComboBox.getSelectedIndex()));
263        expression.setCompare(_compareComboBox.getItemAt(_compareComboBox.getSelectedIndex()));
264        expression.setNumber(Integer.parseInt(_numberField.getText()));
265        expression.setPercentPieces(_percentPiecesComboBox.getItemAt(_percentPiecesComboBox.getSelectedIndex()));
266        expression.setTotalSlots(Integer.parseInt(_totalSlotsField.getText()));
267    }
268
269    /** {@inheritDoc} */
270    @Override
271    public String toString() {
272        return Bundle.getMessage("ExpressionSlotUsage_Short");
273    }
274
275    @Override
276    public void dispose() {
277    }
278
279
280
281    private static class LocoNetConnection {
282
283        private LocoNetSystemConnectionMemo _memo;
284
285        public LocoNetConnection(LocoNetSystemConnectionMemo memo) {
286            _memo = memo;
287        }
288
289        @Override
290        public String toString() {
291            return _memo.getUserName();
292        }
293    }
294
295    @Override
296    public void setDefaultValues() {
297        _numberField.setText("10");
298        _totalSlotsField.setText("100");
299    }
300
301//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionSlotUsageSwing.class);
302
303}