001package jmri.jmrix.openlcb.swing;
002
003import java.awt.event.WindowEvent;
004import java.awt.event.ActionEvent;
005import java.awt.event.ActionListener;
006
007import javax.swing.JButton;
008import javax.swing.JFormattedTextField;
009import javax.swing.JPanel;
010import javax.swing.JTextField;
011import javax.swing.Timer;
012
013import jmri.ShutDownTask;
014import jmri.jmrix.can.CanSystemConnectionMemo;
015import jmri.util.JmriJFrame;
016import jmri.util.swing.WrapLayout;
017
018import org.openlcb.NodeID;
019import org.openlcb.OlcbInterface;
020import org.openlcb.cdi.impl.ConfigRepresentation;
021import org.openlcb.cdi.swing.CdiPanel;
022
023/**
024 * Shared code for creating UI elements from different places in the application.
025 * <p>
026 * Created by bracz on 11/21/16.
027 */
028
029public class ClientActions {
030    private final OlcbInterface iface;
031    private final CanSystemConnectionMemo memo;
032
033    public ClientActions(OlcbInterface iface, CanSystemConnectionMemo memo) {
034        this.iface = iface;
035        this.memo = memo;
036    }
037
038    CdiPanel cdiPanel;
039    ShutDownTask shutDownTask;
040    
041    public void openCdiWindow(NodeID destNode, String description) {
042//        final java.util.ArrayList<JButton> readList = new java.util.ArrayList<>();
043        final java.util.ArrayList<JButton> sensorButtonList = new java.util.ArrayList<>();
044        final java.util.ArrayList<JButton> turnoutButtonList = new java.util.ArrayList<>();
045
046        JmriJFrame f = new JmriJFrame();
047        f.setTitle(Bundle.getMessage("CdiPanelConfigure", description));
048        f.setLayout(new javax.swing.BoxLayout(f.getContentPane(), javax.swing.BoxLayout.Y_AXIS));
049        f.addHelpMenu("package.jmri.jmrix.openlcb.swing.networktree.NetworkTreePane_CDItool", true);
050        
051        cdiPanel = new CdiPanel(){
052            // override and extend window closing behavior
053            @Override
054            protected void targetWindowClosingEvent(WindowEvent evt) { // evt is ignored here
055                log.trace("overridden targetWindowClosingEvent runs");
056                super.targetWindowClosingEvent(evt);
057            }
058            // when actually closing the window, also deregister the safety shutdown class
059            @Override
060            public void release() {
061                super.release();
062                jmri.InstanceManager.getDefault(jmri.ShutDownManager.class).deregister(shutDownTask);
063            }
064        };
065        f.add(cdiPanel);
066        cdiPanel.setEventTable(iface.getNodeStore().getSimpleNodeIdent(destNode).getUserName(),
067                iface.getEventTable());
068                
069        // Add a shutdown task to handle "Cancel" selections should there be unsaved
070        // changed at Shutdown
071        jmri.InstanceManager.getDefault(jmri.ShutDownManager.class).register(
072            shutDownTask = new ShutDownTask() {
073                @Override
074                public String getName() { return "CDI Window Check"; }
075                @Override
076                public Boolean call() {
077                    log.trace("call( checks contents)");
078                    boolean result = cdiPanel.checkOnWindowClosing(); // true to continue shutdown, false to not
079                    if (result) {
080                        // you don't want a second check on automatic window closing during shutdown
081                        cdiPanel.setWindowCloseCheckAlreadyHandled();
082                    }
083                    return result; 
084                }
085
086                @Override
087                public void propertyChange(java.beans.PropertyChangeEvent e) {
088                    // don't care if somebody else cancels
089                }
090                
091                @Override
092                public void run() {
093                    // we're shutting down, nothing to do 
094                }
095        });
096        
097        // create an object to add "New Sensor" buttons
098        CdiPanel.GuiItemFactory factory = new CdiPanel.GuiItemFactory() {
099            private boolean haveButtons = false;
100            @Override
101            public JButton handleReadButton(JButton button) {
102//                readList.add(button);
103                return button;
104            }
105
106            @Override
107            public JButton handleWriteButton(JButton button) {
108                return button;
109            }
110
111            @Override
112            public void handleGroupPaneStart(JPanel pane) {
113                this.gpane = pane;
114                evt1 = null;
115                evt2 = null;
116                desc = null;
117            }
118
119            @Override
120            public void handleGroupPaneEnd(JPanel pane) {
121                if (gpane != null && evt1 != null && evt2 != null && desc != null) {
122                    JPanel p = new JPanel();
123                    p.setLayout(new WrapLayout());
124                    p.setAlignmentX(-1.0f);
125                    pane.add(p);
126                    JButton button = new JButton(Bundle.getMessage("CdiPanelMakeSensor"));
127                    p.add(button);
128                    sensorButtonList.add(button);
129                    button.addActionListener(new java.awt.event.ActionListener() {
130                        @Override
131                        public void actionPerformed(java.awt.event.ActionEvent e) {
132                            jmri.Sensor sensor = jmri.InstanceManager.sensorManagerInstance()
133                                    .provideSensor(memo.getSystemPrefix() + "S" + mevt1.getText() + ";" + mevt2.getText());
134                            if (mdesc.getText().length() > 0) {
135                                sensor.setUserName(mdesc.getText());
136                            }
137                            log.info("make sensor MS{};{} [{}]", mevt1.getText(), mevt2.getText(), mdesc.getText());
138                        }
139
140                        final JTextField mdesc = desc;
141                        final JFormattedTextField mevt1 = evt1;
142                        final JFormattedTextField mevt2 = evt2;
143                    });
144                    button = new JButton(Bundle.getMessage("CdiPanelMakeTurnout"));
145                    p.add(button);
146                    turnoutButtonList.add(button);
147                    button.addActionListener(new java.awt.event.ActionListener() {
148                        @Override
149                        public void actionPerformed(java.awt.event.ActionEvent e) {
150                            jmri.Turnout turnout = jmri.InstanceManager.turnoutManagerInstance()
151                                    .provideTurnout(memo.getSystemPrefix() + "T" + mevt1.getText() + ";" + mevt2.getText());
152                            if (mdesc.getText().length() > 0) {
153                                turnout.setUserName(mdesc.getText());
154                            }
155                            log.info("make turnout MT{};{} [{}]", mevt1.getText(), mevt2.getText(), mdesc.getText());
156                        }
157
158                        final JTextField mdesc = desc;
159                        final JFormattedTextField mevt1 = evt1;
160                        final JFormattedTextField mevt2 = evt2;
161                    });
162                    if (!haveButtons) {
163                        haveButtons = true;
164                        cdiPanel.addButtonToFooter(buttonForList(sensorButtonList, Bundle.getMessage("CdiPanelMakeAllSensors")));
165                        cdiPanel.addButtonToFooter(buttonForList(turnoutButtonList, Bundle.getMessage("CdiPanelMakeAllTurnouts")));
166                    }
167                    gpane = null;
168                    evt1 = null;
169                    evt2 = null;
170                    desc = null;
171                }
172            }
173
174            @Override
175            public JFormattedTextField handleEventIdTextField(JFormattedTextField field) {
176                if (evt1 == null) {
177                    evt1 = field;
178                } else if (evt2 == null) {
179                    evt2 = field;
180                } else {
181                    gpane = null;  // flag too many
182                }
183                return field;
184            }
185
186            @Override
187            public JTextField handleStringValue(JTextField value) {
188                desc = value;
189                return value;
190            }
191
192            @Override
193            /**
194             * Make a sensor from a single Event ID.
195             * Set the user name from the CDI description (if available)
196             * {@inheritDoc}
197             */
198            public void makeSensor(String ev, String mdesc) {
199                jmri.Sensor sensor =
200                        jmri.InstanceManager.sensorManagerInstance()
201                                .provideSensor(memo.getSystemPrefix() + "S" + ev);
202                if (mdesc.length() > 0) {
203                    sensor.setUserName(mdesc);
204                }
205                log.debug("make sensor MS{} [{}]", ev, mdesc);
206            }
207
208            JPanel gpane = null;
209            JTextField desc = null;
210            JFormattedTextField evt1 = null;
211            JFormattedTextField evt2 = null;
212        };
213        ConfigRepresentation rep = iface.getConfigForNode(destNode);
214
215        cdiPanel.initComponents(rep, factory);
216
217        f.pack();
218        f.setVisible(true);
219    }
220
221    JButton buttonForList(final java.util.ArrayList<JButton> list, String label) {
222        JButton b = new JButton(label);
223        b.addActionListener(e -> {
224            int delay = 0; //milliseconds
225            for (final JButton b1 : list) {
226
227                ActionListener taskPerformer = new ActionListener() {
228                    @Override
229                    public void actionPerformed(ActionEvent evt) {
230                        target.doClick();
231                    }
232                    final JButton target = b1;
233                };
234                Timer t = new Timer(delay, taskPerformer);
235                t.setRepeats(false);
236                t.start();
237                delay = delay + 150;
238            }
239        });
240        return b;
241    }
242
243    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ClientActions.class);
244}