001package jmri.jmrit.symbolicprog;
002
003import java.awt.event.ActionListener;
004import java.util.List;
005import javax.swing.BoxLayout;
006import javax.swing.JButton;
007import javax.swing.JComboBox;
008import javax.swing.JLabel;
009import javax.swing.JPanel;
010import javax.swing.border.EmptyBorder;
011
012import jmri.GlobalProgrammerManager;
013import jmri.Programmer;
014import jmri.jmrit.decoderdefn.DecoderFile;
015import jmri.jmrit.progsupport.ProgModeSelector;
016import jmri.jmrit.roster.IdentifyLoco;
017import jmri.jmrit.roster.Roster;
018import jmri.jmrit.roster.RosterEntry;
019import jmri.jmrit.roster.swing.RosterEntrySelectorPanel;
020import jmri.util.swing.JmriJOptionPane;
021
022/**
023 * Provide GUI controls to select a known loco via the Roster.
024 * <p>
025 * When the "open programmer" button is pushed, i.e. the user is ready to
026 * continue, the startProgrammer method is invoked. This should be overridden
027 * (e.g. in a local anonymous class) to create the programmer frame you're
028 * interested in.
029 *
030 * @author Bob Jacobsen Copyright (C) 2001, 2002
031 */
032abstract public class KnownLocoSelPane extends LocoSelPane {
033
034    public KnownLocoSelPane(JLabel s, boolean ident, ProgModeSelector selector) {
035        mCanIdent = ident;
036        mStatusLabel = s;
037        this.selector = selector;
038        init();
039    }
040
041    public KnownLocoSelPane(boolean ident) {
042        this(null, ident, null);
043    }
044
045    boolean mCanIdent;
046
047    JComboBox<String> programmerBox;
048    ProgModeSelector selector;
049
050    protected void init() {
051        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
052        JPanel pane2a = new JPanel();
053        pane2a.setLayout(new BoxLayout(pane2a, BoxLayout.X_AXIS));
054        pane2a.add(new JLabel(java.util.ResourceBundle.getBundle("jmri/jmrit/symbolicprog/SymbolicProgBundle").getString("UseExisting")));
055
056        if (mCanIdent) {
057            JButton idloco = new JButton(java.util.ResourceBundle.getBundle("jmri/jmrit/symbolicprog/SymbolicProgBundle").getString("ReadAndSelect"));
058            idloco.addActionListener(new ActionListener() {
059                @Override
060                public void actionPerformed(java.awt.event.ActionEvent e) {
061                    if (log.isDebugEnabled()) {
062                        log.debug("Identify locomotive pressed");
063                    }
064                    startIdentify();
065                }
066            });
067            pane2a.add(idloco);
068            pane2a.setAlignmentX(JLabel.LEFT_ALIGNMENT);
069        }
070        add(pane2a);
071
072        locoBox = new RosterEntrySelectorPanel();
073        locoBox.setNonSelectedItem("Locomotive");
074        add(locoBox);
075
076        addProgrammerBox();
077
078        JButton go2 = new JButton(Bundle.getMessage("OpenProgrammer"));
079        go2.getAccessibleContext().setAccessibleName(Bundle.getMessage("OpenProgrammer"));
080        go2.addActionListener(new ActionListener() {
081            @Override
082            public void actionPerformed(java.awt.event.ActionEvent e) {
083                if (log.isDebugEnabled()) {
084                    log.debug("Open programmer pressed");
085                }
086                openButton();
087            }
088        });
089        add(go2);
090        setBorder(new EmptyBorder(6, 6, 6, 6));
091    }
092
093    /**
094     * Add the GUI for selecting a specific programmer
095     */
096    private void addProgrammerBox() {
097        JPanel pane3a = new JPanel();
098        pane3a.setLayout(new BoxLayout(pane3a, BoxLayout.X_AXIS));
099        pane3a.add(new JLabel(Bundle.getMessage("ProgrammerFormat")));
100
101        // create the programmer box
102        programmerBox = new JComboBox<String>(ProgDefault.findListOfProgFiles());
103        programmerBox.setSelectedIndex(0);
104        if (ProgDefault.getDefaultProgFile() != null) {
105            programmerBox.setSelectedItem(ProgDefault.getDefaultProgFile());
106        }
107        pane3a.add(programmerBox);
108        // pane3a.setAlignmentX(JLabel.RIGHT_ALIGNMENT);
109        add(pane3a);
110    }
111
112    JLabel mStatusLabel = null;
113
114    private void startIdentify() {
115        // start identifying a loco
116        final KnownLocoSelPane me = this;
117        Programmer p = null;
118        if (selector != null && selector.isSelected()) p = selector.getProgrammer();
119        if (p == null) {
120            log.warn("Selector did not provide a programmer, use default");
121            p = jmri.InstanceManager.getDefault(GlobalProgrammerManager.class).getGlobalProgrammer();
122        }
123        IdentifyLoco id = new IdentifyLoco(p) {
124            private KnownLocoSelPane who = me;
125
126            @Override
127            protected void done(int dccAddress) {
128                // if Done, updated the selected decoder
129                who.selectLoco(dccAddress);
130            }
131
132            @Override
133            protected void message(String m) {
134                if (mStatusLabel != null) {
135                    mStatusLabel.setText(m);
136                }
137            }
138
139            @Override
140            public void error() {
141            }
142        };
143        id.start();
144    }
145
146    protected void selectLoco(int dccAddress) {
147        // locate that loco
148        List<RosterEntry> l = Roster.getDefault().matchingList(null, null, Integer.toString(dccAddress),
149                null, null, null, null);
150        if (log.isDebugEnabled()) {
151            log.debug("selectLoco found {} matches", l.size());
152        }
153        if (l.size() > 0) {
154            RosterEntry r = l.get(0);
155            String id = r.getId();
156            if (log.isDebugEnabled()) {
157                log.debug("Loco id is {}", id);
158            }
159            String group = locoBox.getSelectedRosterGroup();
160            if (group != null && !group.equals(Roster.ALLENTRIES)) {
161                List<RosterEntry> entries = Roster.getDefault().getEntriesWithAttributeKeyValue(Roster.getRosterGroupProperty(group), "yes");
162                if (entries.contains(r)) {
163                    locoBox.setSelectedRosterEntry(r);
164                } else {
165                    locoBox.setSelectedRosterEntryAndGroup(r, Roster.ALLENTRIES);
166                }
167            } else {
168                locoBox.setSelectedRosterEntry(r);
169            }
170        } else {
171            log.warn("Read address {}, but no such loco in roster", dccAddress);
172        }
173    }
174
175    private RosterEntrySelectorPanel locoBox = null;
176
177    /**
178     * handle pushing the open programmer button by finding names, then calling
179     * a template method
180     */
181    protected void openButton() {
182
183        if (locoBox.getSelectedRosterEntries().length != 0) {
184            RosterEntry re = locoBox.getSelectedRosterEntries()[0];
185            startProgrammer(null, re, (String) programmerBox.getSelectedItem());
186        } else {
187            JmriJOptionPane.showMessageDialog(this,
188                    Bundle.getMessage("LocoMustSelected"),
189                    Bundle.getMessage("NoSelection"),
190                    JmriJOptionPane.ERROR_MESSAGE);
191        }
192    }
193
194
195    /*
196     * Start the programming operation(s).
197     * @param decoderFile contains decoder definition
198     * @param r contains locomotive-specific roster information
199     * @param programmerName used to find the right programmer for the operation.
200     */
201    abstract protected void startProgrammer(DecoderFile decoderFile, RosterEntry r,
202            String programmerName);
203
204    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(KnownLocoSelPane.class);
205
206}