001package jmri.jmrix.can.cbus.swing.configtool;
002
003import java.awt.Color;
004import java.awt.Frame;
005import java.awt.GridBagConstraints;
006import java.awt.GridBagLayout;
007import java.awt.event.ActionEvent;
008import java.awt.event.FocusEvent;
009import java.awt.event.FocusListener;
010import javax.swing.*;
011
012import jmri.jmrix.AbstractMessage;
013import jmri.jmrix.can.CanFrame;
014import jmri.jmrix.can.CanListener;
015import jmri.jmrix.can.CanSystemConnectionMemo;
016import jmri.jmrix.can.cbus.CbusMessage;
017import jmri.jmrix.can.cbus.swing.console.CbusConsolePane;
018import jmri.jmrix.can.cbus.swing.CbusEventHighlightFrame;
019import jmri.jmrix.can.cbus.swing.CbusFilterFrame;
020import jmri.util.swing.JmriJOptionPane;
021
022/**
023 * Pane for user creation of Sensor, Turnouts and Lights that are linked to CBUS
024 * events.
025 *
026 * @author Bob Jacobsen Copyright (C) 2008
027 * @since 2.3.1
028 */
029public class ConfigToolPane extends jmri.jmrix.can.swing.CanPanel implements CanListener {
030
031    static int configtool_instance_num;
032    final static int NRECORDERS = 6;
033    private final CbusEventRecorder[] recorders = new CbusEventRecorder[NRECORDERS];
034    private CbusFilterFrame _filterFrame;
035    private CbusEventHighlightFrame _highlightFrame;
036    private final CbusConsolePane _console;
037    protected JButton filterButton;
038    protected JButton highlightButton;
039    private JButton resetCaptureButton;
040
041    public static void incrementInstance() {
042        configtool_instance_num++;
043    }
044
045    public static int getConfigToolInstanceNum() {
046        log.debug("instance num {}",configtool_instance_num);
047        return configtool_instance_num;
048    }
049
050    public ConfigToolPane() {
051        super();
052        _filterFrame = null;
053        _highlightFrame = null;
054        _console = null;
055    }
056
057    public ConfigToolPane(CbusConsolePane console, CbusFilterFrame filterFrame, CbusEventHighlightFrame highlightFrame) {
058        super();
059        _filterFrame = filterFrame;
060        _highlightFrame = highlightFrame;
061        _console = console;
062    }
063
064    public void init() {
065        // log.debug("ConfigToolPane init");
066
067        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
068
069        // add event displays
070        JPanel p1 = new JPanel();
071        p1.setLayout(new BoxLayout(p1, BoxLayout.Y_AXIS));
072
073        JPanel buttons = new JPanel();
074        buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
075
076        filterButton = new JButton(Bundle.getMessage("ButtonFilter"));
077        filterButton.setVisible(true);
078        filterButton.setToolTipText(Bundle.getMessage("TooltipFilter"));
079        buttons.add(filterButton);
080
081        filterButton.addActionListener(this::filterButtonActionPerformed);
082
083
084        highlightButton = new JButton(Bundle.getMessage("ButtonHighlight"));
085        highlightButton.setVisible(true);
086        highlightButton.setToolTipText(Bundle.getMessage("TooltipHighlighter"));
087        buttons.add(highlightButton);
088
089        highlightButton.addActionListener(this::highlightButtonActionPerformed);
090
091        resetCaptureButton = new JButton(Bundle.getMessage("ButtonResetCapture"));
092        resetCaptureButton.setVisible(true);
093        resetCaptureButton.setHorizontalAlignment(SwingConstants.RIGHT);
094        buttons.add(resetCaptureButton);
095
096        resetCaptureButton.addActionListener(this::resetCaptureButtonActionPerformed);
097
098        p1.add(buttons);
099
100        for (int i = 0; i < recorders.length; i++) {
101            recorders[i] = new CbusEventRecorder();
102            p1.add(recorders[i]);
103        }
104        p1.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutEvents")));
105        add(p1);
106
107        // add sensor
108        makeSensor = new MakeNamedBean("LabelEventActive", "LabelEventInactive") {
109            @Override
110            void create(String name) {
111                try {
112                    memo.get(jmri.SensorManager.class).provideSensor(name);
113                }
114                catch (IllegalArgumentException ex) {
115                    JmriJOptionPane.showMessageDialog(this,
116                        ex.getMessage(), Bundle.getMessage("WarningTitle"),
117                        JmriJOptionPane.ERROR_MESSAGE);
118                }
119            }
120        };
121        makeSensor.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TitleAddX", Bundle.getMessage("BeanNameSensor"))));
122        add(makeSensor);
123
124        // add turnout
125        makeTurnout = new MakeNamedBean("LabelEventThrown", "LabelEventClosed") {
126            @Override
127            void create(String name) {
128                try {
129                    memo.get(jmri.TurnoutManager.class).provideTurnout(name);
130                }
131                catch (IllegalArgumentException ex) {
132                    JmriJOptionPane.showMessageDialog(this,
133                        ex.getMessage(), Bundle.getMessage("WarningTitle"),
134                        JmriJOptionPane.ERROR_MESSAGE);
135                }
136            }
137        };
138        makeTurnout.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TitleAddX", Bundle.getMessage("BeanNameTurnout"))));
139        add(makeTurnout);
140
141        // add light
142        makeLight = new MakeNamedBean("LabelEventLightOn", "LabelEventLightOff") {
143            @Override
144            void create(String name) {
145                try {
146                    memo.get(jmri.LightManager.class).provideLight(name);
147                }
148                catch (Exception ex) {
149                    JmriJOptionPane.showMessageDialog(this,
150                        ex.getMessage(), Bundle.getMessage("WarningTitle"),
151                        JmriJOptionPane.ERROR_MESSAGE);
152                }
153            }
154        };
155        makeLight.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TitleAddX", Bundle.getMessage("BeanNameLight"))));
156        add(makeLight);
157
158    }
159
160    @Override
161    public void initComponents(CanSystemConnectionMemo memo) {
162        super.initComponents(memo);
163        addTc(memo);
164        incrementInstance();
165        init();
166    }
167
168    @Override
169    public String getTitle() {
170        if (memo != null) {
171            StringBuilder title = new StringBuilder(20);
172            title.append(memo.getUserName());
173            title.append(" ");
174            title.append(Bundle.getMessage("CapConfigTitle"));
175            if (getConfigToolInstanceNum() > 1) {
176                title.append(" ");
177                title.append( getConfigToolInstanceNum() );
178            }
179            return title.toString();
180        }
181        return Bundle.getMessage("CapConfigTitle");
182    }
183
184    private MakeNamedBean makeSensor;
185    private MakeNamedBean makeTurnout;
186    private MakeNamedBean makeLight;
187
188    @Override
189    public void reply(jmri.jmrix.can.CanReply m) {
190        sendToListeners(m);
191    }
192
193    /** {@inheritDoc} */
194    @Override
195    public void message(jmri.jmrix.can.CanMessage m) {
196        sendToListeners(m);
197    }
198
199    private void sendToListeners( AbstractMessage m ){
200        if ( ((CanFrame)m).extendedOrRtr()) {
201            return;
202        }
203        if ( ( _filterFrame!=null ) && ( _filterFrame.filter(m)) ) {
204            return;
205        }
206        // forward to anybody waiting to capture
207        makeSensor.processFrame(m);
208        makeTurnout.processFrame(m);
209        makeLight.processFrame(m);
210        for (CbusEventRecorder recorder : recorders) {
211            if (recorder.waiting()) {
212                recorder.processFrame(m);
213                break;
214            }
215        }
216    }
217
218    /** {@inheritDoc} */
219    @Override
220    public String getHelpTarget() {
221        return "package.jmri.jmrix.can.cbus.swing.configtool.ConfigToolFrame";
222    }
223
224    @Override
225    public void dispose() {
226        removeTc(memo);
227        clearFilterFrame();
228        clearHighlightFrame();
229        super.dispose();
230    }
231
232    private void clearFilterFrame(){
233        if (_filterFrame != null) {
234            _filterFrame.dispose();
235        }
236        _filterFrame=null;
237    }
238
239    private void clearHighlightFrame(){
240        if (_highlightFrame != null) {
241            _highlightFrame.dispose();
242        }
243        _highlightFrame=null;
244    }
245
246
247    public void resetCaptureButtonActionPerformed(ActionEvent e) {
248        for (CbusEventRecorder recorder : recorders) {
249            recorder.capture.setSelected(true);
250        }
251    }
252
253    public void filterButtonActionPerformed(ActionEvent e) {
254        // log.debug("Cbus Console filter button action performed");
255
256        if ( _console != null ) {
257            _console.displayPane.filterButton.doClick();
258            return;
259        }
260
261        if (_filterFrame == null) {
262            _filterFrame = new CbusFilterFrame(_console,this);
263            _filterFrame.initComponents();
264        } else {
265            _filterFrame.setState(Frame.NORMAL);
266        }
267        _filterFrame.setVisible(true);
268    }
269
270    public void highlightButtonActionPerformed(ActionEvent e) {
271        // log.debug("Cbus Console filter button action performed");
272        if ( _console != null ) {
273            _console.displayPane.highlightButton.doClick();
274            return;
275        }
276        if (_highlightFrame == null) {
277            _highlightFrame = new CbusEventHighlightFrame(null,this);
278            _highlightFrame.initComponents();
279
280        } else {
281            _highlightFrame.setState(Frame.NORMAL);
282        }
283        _highlightFrame.setVisible(true);
284    }
285
286    public void setHighlighter( CbusEventHighlightFrame highlightFrame){
287        _highlightFrame = highlightFrame;
288    }
289
290    public void setFilter( CbusFilterFrame filterFrame){
291        _filterFrame = filterFrame;
292    }
293
294    /**
295     * Class to build one NamedBean
296     */
297    private class MakeNamedBean extends JPanel {
298
299        private JTextField f1 = new JTextField(15);
300        private JTextField f2 = new JTextField(15);
301        private JTextField f3 = new JTextField(15);
302
303        private final JButton bc;
304
305        JToggleButton b1 = new JToggleButton(Bundle.getMessage("ButtonCaptureNext"));
306        JToggleButton b2 = new JToggleButton(Bundle.getMessage("ButtonCaptureNext"));
307        JToggleButton b3 = new JToggleButton(Bundle.getMessage("ButtonCaptureNext"));
308
309        private final JToggleButton[] captureNextButtons = new JToggleButton[]{b1,b2,b3};
310        private final JTextField[] fields = new JTextField[]{f1,f2,f3};
311
312        /**
313         * Create CBUS NamedBean using a JPanel for user interaction.
314         *
315         * @param name1 string for Label 1 in configuration pane
316         * @param name2 string for Label 2 in configuration pane
317         */
318        MakeNamedBean(String name1, String name2) {
319            // actions
320            bc = new JButton(Bundle.getMessage("ButtonCreate"));
321            bc.addActionListener((ActionEvent e) -> {
322                if (f2.getText().isEmpty()) {
323                    create(f1.getText());
324                } else {
325                    create(f1.getText() + ";" + f2.getText());
326                }
327            });
328
329            initGui(name1, name2);
330        }
331
332        private void initGui(String name1, String name2){
333
334            // GUI
335            setLayout(new GridBagLayout());
336            GridBagConstraints c = new GridBagConstraints();
337            c.gridwidth = 1;
338            c.gridheight = 1;
339
340            c.gridx = 0;
341            c.gridy = 0;
342            c.anchor = GridBagConstraints.EAST;
343            add(new JLabel(Bundle.getMessage(name1)), c);
344
345            c.gridx = 1;
346            c.gridy = 0;
347            c.anchor = GridBagConstraints.WEST;
348            add(f1, c);
349
350            c.gridx = 2;
351            c.gridy = 0;
352            c.anchor = GridBagConstraints.WEST;
353            add(b1, c);
354            b1.setToolTipText(Bundle.getMessage("CaptureNextTooltip"));
355
356            c.gridx = 0;
357            c.gridy = 1;
358            c.anchor = GridBagConstraints.EAST;
359            add(new JLabel(Bundle.getMessage(name2)), c);
360
361            c.gridx = 1;
362            c.gridy = 1;
363            c.anchor = GridBagConstraints.EAST;
364            add(f2, c);
365
366            c.gridx = 2;
367            c.gridy = 1;
368            c.anchor = GridBagConstraints.WEST;
369            add(b2, c);
370            b2.setToolTipText(Bundle.getMessage("CaptureNextTooltip"));
371
372            c.gridx = 1;
373            c.gridy = 2;
374            c.anchor = GridBagConstraints.WEST;
375            add(bc, c);
376            bc.setToolTipText(Bundle.getMessage("CreateTooltip"));
377        }
378
379        void create(String name) {
380        }
381
382        public void processFrame(AbstractMessage m){
383
384            int high = (_highlightFrame != null) ? _highlightFrame.highlight(m) : -1;
385            for (int i=0; i < 3; i++){
386
387                if (captureNextButtons[i].isSelected()) {
388                    fields[i].setText(CbusMessage.toAddress(m));
389                    captureNextButtons[i].setSelected(false);
390                    if ( high > -1 ) {
391                        fields[i].setBackground(CbusEventHighlightFrame.highlightColors[high]);
392                    } else {
393                        fields[i].setBackground(Color.WHITE);
394                    }
395                }
396            }
397        }
398    }
399
400    /**
401     * Class to handle recording and presenting one event.
402     */
403    private class CbusEventRecorder extends JPanel implements FocusListener {
404
405        CbusEventRecorder() {
406            super();
407
408            init();
409            event.setEditable(false);
410            event.setDragEnabled(true);
411            event.setBackground(Color.WHITE);
412            capture.setSelected(true);
413
414        }
415
416        final void init() {
417            event.addFocusListener(this);
418            this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
419            add(event);
420            add(capture);
421        }
422
423        JCheckBox capture = new JCheckBox(Bundle.getMessage("MsgCaptureNext"));
424        JTextField event = new JTextField(15);
425
426        boolean waiting() {
427            return capture.isSelected();
428        }
429
430        public void processFrame(AbstractMessage m) {
431            if (capture.isSelected()) {
432                event.setText(CbusMessage.toAddress(m));
433                capture.setSelected(false);
434                int high = (_highlightFrame != null) ? _highlightFrame.highlight(m) : -1;
435                if ( high > -1 ) {
436                    event.setBackground(CbusEventHighlightFrame.highlightColors[high]);
437                } else {
438                    event.setBackground(Color.WHITE);
439                }
440            }
441        }
442
443        @Override
444        public void focusGained(FocusEvent fe) {
445            JTextField txt = (JTextField)fe.getComponent();
446            txt.selectAll();
447        }
448
449        @Override
450        public void focusLost(FocusEvent e) {
451        }
452
453    }
454
455    /**
456     * Nested class to create one of these using old-style defaults.
457     */
458    static public class Default extends jmri.jmrix.can.swing.CanNamedPaneAction {
459        public Default() {
460            super(Bundle.getMessage("CapConfigTitle"),
461                    new jmri.util.swing.sdi.JmriJFrameInterface(),
462                    ConfigToolPane.class.getName(),
463                    jmri.InstanceManager.getDefault(CanSystemConnectionMemo.class));
464        }
465    }
466
467    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConfigToolPane.class);
468
469}