001package jmri.jmrix.nce.macro;
002
003import java.awt.*;
004
005import javax.swing.JComponent;
006import javax.swing.JLabel;
007
008import jmri.jmrix.nce.*;
009import jmri.util.swing.JmriJOptionPane;
010
011/**
012 * Pane for user input of NCE macros.
013 *
014 * @author Bob Jacobsen Copyright (C) 2001
015 * @author Dan Boudreau Copyright (C) 2007 Cloned into a Panel by
016 * @author kcameron
017 */
018public class NceMacroGenPanel extends jmri.jmrix.nce.swing.NcePanel implements jmri.jmrix.nce.NceListener {
019
020    // member declarations
021    javax.swing.JLabel jLabel1 = new javax.swing.JLabel(Bundle.getMessage("MacroLabel"));
022    javax.swing.JLabel macroText = new javax.swing.JLabel(Bundle.getMessage("ReplyLabel"));
023    javax.swing.JLabel macroReply = new javax.swing.JLabel();
024    javax.swing.JButton sendButton = new javax.swing.JButton(Bundle.getMessage("Send"));
025    javax.swing.JTextField packetTextField = new javax.swing.JTextField(4);
026
027    // for padding out panel
028    JLabel space1 = new JLabel("                  ");
029    JLabel space3 = new JLabel("                       ");
030
031    private NceTrafficController tc = null;
032
033    public NceMacroGenPanel() {
034        super();
035    }
036
037    /**
038     * {@inheritDoc}
039     */
040    @Override
041    public void initContext(Object context) {
042        if (context instanceof NceSystemConnectionMemo) {
043            initComponents((NceSystemConnectionMemo) context);
044        }
045    }
046
047    /**
048     * {@inheritDoc}
049     */
050    @Override
051    public String getHelpTarget() {
052        return "package.jmri.jmrix.nce.macro.NceMacroEditFrame";
053    }
054
055    /**
056     * {@inheritDoc}
057     */
058    @Override
059    public String getTitle() {
060        StringBuilder x = new StringBuilder();
061        if (memo != null) {
062            x.append(memo.getUserName());
063        } else {
064            x.append("NCE_");
065        }
066        x.append(": ");
067        x.append(Bundle.getMessage("TitleNceMacroGen"));
068        return x.toString();
069    }
070
071    /**
072     * The minimum frame size for font size 16
073     */
074    @Override
075    public Dimension getMinimumDimension() {
076        return new Dimension(200, 200);
077    }
078
079    /**
080     * {@inheritDoc}
081     */
082    @Override
083    public void initComponents(NceSystemConnectionMemo memo) {
084        this.memo = memo;
085        tc = memo.getNceTrafficController();
086        // the following code sets the frame's initial state
087
088        // set initial state
089        macroReply.setText(Bundle.getMessage("unknown"));
090
091        // load tool tips
092        sendButton.setToolTipText(Bundle.getMessage("toolTipExecuteMacro"));
093        packetTextField.setToolTipText(Bundle.getMessage("toolTipEnterMacro", 255));
094
095        packetTextField.setMaximumSize(new Dimension(packetTextField
096                .getMaximumSize().width, packetTextField.getPreferredSize().height));
097
098        setLayout(new GridBagLayout());
099        setPreferredSize(new Dimension(300, 100));
100
101        addItem(jLabel1, 0, 0);
102        addItem(packetTextField, 2, 0);
103        addItem(macroText, 0, 1);
104        addItem(macroReply, 2, 1);
105        //addItem(space1, 0, 2);
106        //addItem(space2, 1, 2);
107        addItem(space3, 2, 2);
108        addItem(sendButton, 0, 3);
109
110        sendButton.addActionListener(new java.awt.event.ActionListener() {
111            @Override
112            public void actionPerformed(java.awt.event.ActionEvent e) {
113                sendButtonActionPerformed(e);
114            }
115        });
116    }
117
118    public void sendButtonActionPerformed(java.awt.event.ActionEvent e) {
119        String input = packetTextField.getText();
120        // TODO check input + feedback on error. Too easy to cause NPE
121        // Send Macro
122        NceMessage m = createMacroCmd(input);
123        if (m == null) {
124            macroReply.setText(Bundle.getMessage("error"));
125            JmriJOptionPane.showMessageDialog(this,
126                    Bundle.getMessage("EnterMacroNumber", 255),
127                    Bundle.getMessage("NceMacro"),
128                    JmriJOptionPane.ERROR_MESSAGE);
129            return;
130        }
131        macroReply.setText(Bundle.getMessage("waiting"));
132        tc.sendNceMessage(m, this);
133
134        // Unfortunately, the new command doesn't tell us if the macro is empty
135        // so we send old command for status
136        NceMessage m2 = createOldMacroCmd(input);
137        tc.sendNceMessage(m2, this);
138    }
139
140    @Override
141    public void message(NceMessage m) {
142    }  // ignore replies
143
144    @Override
145    public void reply(NceReply r) {
146        if (r.getNumDataElements() == NceMessage.REPLY_1) {
147
148            int recChar = r.getElement(0);
149            if (recChar == NceMessage.NCE_OKAY) {
150                macroReply.setText(Bundle.getMessage("okay"));
151            }
152            if (recChar == '0') {
153                macroReply.setText(Bundle.getMessage("macroEmpty"));
154            }
155
156        } else {
157            macroReply.setText(Bundle.getMessage("error"));
158        }
159    }
160
161    NceMessage createMacroCmd(String s) {
162
163        int macroNum = 0;
164        try {
165            macroNum = Integer.parseInt(s);
166        } catch (NumberFormatException e) {
167            return null;
168        }
169
170        if (macroNum < 0 || macroNum > 255) {
171            return null;
172        }
173
174        if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) {
175
176            // NCE always responds with okay (!) if macro number is in range.
177            // We need to send this version of macro command to cause turnout
178            // state to change in NCE CS
179            NceMessage m = new NceMessage(5);
180            m.setElement(0, NceMessage.SEND_ACC_SIG_MACRO_CMD);   // Macro cmd
181            m.setElement(1, 0x00);   // addr_h
182            m.setElement(2, 0x01);   // addr_l
183            m.setElement(3, 0x01);   // Macro cmd
184            m.setElement(4, macroNum);  // Macro #
185            m.setBinary(true);
186            m.setReplyLen(NceMessage.REPLY_1);
187            return m;
188
189        } else {
190
191            // NCE responds with okay (!) if macro exist, (0) if not
192            NceMessage m = new NceMessage(2);
193            m.setElement(0, NceMessage.MACRO_CMD);   // Macro cmd
194            m.setElement(1, macroNum);  // Macro #
195            m.setBinary(true);
196            m.setReplyLen(NceMessage.REPLY_1);
197            return m;
198        }
199    }
200
201    NceMessage createOldMacroCmd(String s) {
202
203        int macroNum = 0;
204        try {
205            macroNum = Integer.parseInt(s);
206        } catch (NumberFormatException e) {
207            return null;
208        }
209
210        if (macroNum < 0 || macroNum > 255) {
211            return null;
212        }
213
214        // NCE responds with okay (!) if macro exist, ('0') if not
215        NceMessage m = new NceMessage(2);
216        m.setElement(0, NceMessage.MACRO_CMD); // Macro cmd
217        m.setElement(1, macroNum); // Macro #
218        m.setBinary(true);
219        m.setReplyLen(NceMessage.REPLY_1);
220        return m;
221    }
222
223    private void addItem(JComponent c, int x, int y) {
224        GridBagConstraints gc = new GridBagConstraints();
225        gc.gridx = x;
226        gc.gridy = y;
227        gc.weightx = 100.0;
228        gc.weighty = 100.0;
229        add(c, gc);
230    }
231
232    /**
233     * Nested class to create one of these using old-style defaults.
234     */
235    static public class Default extends jmri.jmrix.nce.swing.NceNamedPaneAction {
236
237        public Default() {
238            super("Open NCE Send Macro Window",
239                    new jmri.util.swing.sdi.JmriJFrameInterface(),
240                    NceMacroGenPanel.class.getName(),
241                    jmri.InstanceManager.getDefault(NceSystemConnectionMemo.class));
242        }
243    }
244
245}