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; 011import jmri.GlobalProgrammerManager; 012import jmri.InstanceManager; 013import jmri.Programmer; 014import jmri.jmrit.decoderdefn.DecoderFile; 015import jmri.jmrit.decoderdefn.DecoderIndexFile; 016import jmri.jmrit.decoderdefn.IdentifyDecoder; 017import jmri.jmrit.progsupport.ProgModeSelector; 018import jmri.jmrit.roster.Roster; 019import jmri.jmrit.roster.RosterEntry; 020import jmri.jmrit.roster.swing.GlobalRosterEntryComboBox; 021import org.slf4j.Logger; 022import org.slf4j.LoggerFactory; 023 024/** 025 * Provide GUI controls to select a decoder for a new loco and/or copy an 026 * existing config. 027 * <p> 028 * The user can select either a loco to copy, or a new decoder type or both. 029 * <p> 030 * When the "open programmer" button is pushed, i.e. the user is ready to 031 * continue, the startProgrammer method is invoked. This should be overridden 032 * (e.g. in a local anonymous class) to create the programmer frame you're 033 * interested in. 034 * 035 * @author Bob Jacobsen Copyright (C) 2001, 2002 036 * @author Howard G. Penny Copyright (C) 2005 037 * @see jmri.jmrit.decoderdefn.IdentifyDecoder 038 * @see jmri.jmrit.roster.IdentifyLoco 039 */ 040public class NewLocoSelPane extends jmri.util.swing.JmriPanel { 041 042 public NewLocoSelPane(JLabel s, ProgModeSelector selector) { 043 _statusLabel = s; 044 this.selector = selector; 045 init(); 046 } 047 048 public NewLocoSelPane() { 049 init(); 050 } 051 052 ProgModeSelector selector; 053 054 public void init() { 055 JLabel last; 056 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 057 add(last = new JLabel(java.util.ResourceBundle.getBundle("jmri/jmrit/symbolicprog/SymbolicProgBundle").getString("NewLocoProgTrack"))); 058 last.setBorder(new EmptyBorder(6, 0, 6, 0)); 059 add(new JLabel(java.util.ResourceBundle.getBundle("jmri/jmrit/symbolicprog/SymbolicProgBundle").getString("CopySettings"))); 060 061 locoBox = new GlobalRosterEntryComboBox(); 062 locoBox.addActionListener(new ActionListener() { 063 @Override 064 public void actionPerformed(java.awt.event.ActionEvent e) { 065 if (log.isDebugEnabled()) { 066 log.debug("Locomotive selected changed"); 067 } 068 matchDecoderToLoco(); 069 } 070 }); 071 add(locoBox); 072 073 JPanel pane1a = new JPanel(); 074 pane1a.setLayout(new BoxLayout(pane1a, BoxLayout.X_AXIS)); 075 pane1a.add(new JLabel(java.util.ResourceBundle.getBundle("jmri/jmrit/symbolicprog/SymbolicProgBundle").getString("LabelDecoderInstalled"))); 076 JButton iddecoder = new JButton(java.util.ResourceBundle.getBundle("jmri/jmrit/symbolicprog/SymbolicProgBundle").getString("IdentifyDecoder")); 077 iddecoder.addActionListener(new ActionListener() { 078 @Override 079 public void actionPerformed(java.awt.event.ActionEvent e) { 080 if (log.isDebugEnabled()) { 081 log.debug("identify decoder pressed"); 082 } 083 startIdentify(); 084 } 085 }); 086 pane1a.add(iddecoder); 087 pane1a.setAlignmentX(JLabel.LEFT_ALIGNMENT); 088 add(pane1a); 089 090 decoderBox = InstanceManager.getDefault(DecoderIndexFile.class).matchingComboBox(null, null, null, null, null, null); 091 add(decoderBox); 092 093 // Open programmer button 094 JButton go1 = new JButton(java.util.ResourceBundle.getBundle("jmri/jmrit/symbolicprog/SymbolicProgBundle").getString("IdentifyDecoder")); 095 go1.addActionListener(new ActionListener() { 096 @Override 097 public void actionPerformed(java.awt.event.ActionEvent e) { 098 if (log.isDebugEnabled()) { 099 log.debug("Open programmer pressed"); 100 } 101 openButton(); 102 } 103 }); 104 add(go1); 105 setBorder(new EmptyBorder(6, 6, 6, 6)); 106 } 107 108 JLabel _statusLabel = null; 109 110 private void startIdentify() { 111 // start identifying a decoder 112 final NewLocoSelPane me = this; 113 Programmer p = null; 114 if (selector != null && selector.isSelected()) p = selector.getProgrammer(); 115 if (p == null) { 116 log.warn("Selector did not provide a programmer, use default"); 117 p = jmri.InstanceManager.getDefault(GlobalProgrammerManager.class).getGlobalProgrammer(); 118 } 119 IdentifyDecoder id = new IdentifyDecoder(p) { 120 private NewLocoSelPane who = me; 121 122 @Override 123 protected void done(int mfg, int model, int productID) { 124 // if Done, updated the selected decoder 125 who.selectDecoder(mfg, model, productID); 126 } 127 128 @Override 129 protected void message(String m) { 130 if (_statusLabel != null) { 131 _statusLabel.setText(m); 132 } 133 } 134 135 @Override 136 public void error() { 137 } 138 }; 139 id.start(); 140 } 141 142 private void selectDecoder(int mfgID, int modelID, int productID) { 143 JComboBox<String> temp = null; 144 145 // if productID present, try with that 146 if (productID != -1) { 147 String sz_productID = Integer.toString(productID); 148 temp = InstanceManager.getDefault(DecoderIndexFile.class).matchingComboBox(null, null, Integer.toString(mfgID), Integer.toString(modelID), sz_productID, null); 149 if (temp.getItemCount() == 0) { 150 log.debug("selectDecoder found no items with product ID {}", productID); 151 temp = null; 152 } else { 153 log.debug("selectDecoder found {} matches with productID {}", temp.getItemCount(), productID); 154 } 155 } 156 157 // try without product ID if needed 158 if (temp == null) { // i.e. if no match previously 159 temp = InstanceManager.getDefault(DecoderIndexFile.class).matchingComboBox(null, null, Integer.toString(mfgID), Integer.toString(modelID), null, null); 160 if (log.isDebugEnabled()) { 161 log.debug("selectDecoder without productID found {} matches", temp.getItemCount()); 162 } 163 } 164 165 // install all those in the JComboBox in place of the longer, original list 166 if (temp.getItemCount() > 0) { 167 decoderBox.setModel(temp.getModel()); 168 decoderBox.setSelectedIndex(0); 169 } else { 170 log.warn("Decoder says {} {} decoder, but no such decoder defined", mfgID, modelID); 171 } 172 } 173 174 private void matchDecoderToLoco() { 175 if (((String) locoBox.getSelectedItem()).equals("<none>")) { 176 return; 177 } 178 RosterEntry r = Roster.getDefault().entryFromTitle((String) locoBox.getSelectedItem()); 179 String decoderModel = r.getDecoderModel(); 180 String decoderFamily = r.getDecoderFamily(); 181 if (log.isDebugEnabled()) { 182 log.debug("selected loco uses decoder {} {}", decoderFamily, decoderModel); 183 } 184 // locate a decoder like that. 185 List<DecoderFile> l = InstanceManager.getDefault(DecoderIndexFile.class).matchingDecoderList(null, decoderFamily, null, null, null, decoderModel); 186 if (log.isDebugEnabled()) { 187 log.debug("found {} matches", l.size()); 188 } 189 if (l.size() > 0) { 190 DecoderFile d = l.get(0); 191 String title = d.titleString(); 192 if (log.isDebugEnabled()) { 193 log.debug("Decoder file title {}", title); 194 } 195 for (int i = 0; i < decoderBox.getItemCount(); i++) { 196 if (title.equals(decoderBox.getItemAt(i))) { 197 decoderBox.setSelectedIndex(i); 198 } 199 } 200 } else { 201 log.warn("Loco uses {} {} decoder, but no such decoder defined", decoderFamily, decoderModel); 202 } 203 } 204 205 private JComboBox<Object> locoBox = null; 206 private JComboBox<String> decoderBox = null; 207 208 /** 209 * Handle pushing the open programmer button by finding names, then calling 210 * a template method 211 */ 212 protected void openButton() { 213 214 // find the decoderFile object 215 DecoderFile decoderFile = InstanceManager.getDefault(DecoderIndexFile.class).fileFromTitle((String) decoderBox.getSelectedItem()); 216 if (log.isDebugEnabled()) { 217 log.debug("decoder file: {}", decoderFile.getFileName()); 218 } 219 220 // create a dummy RosterEntry with the decoder info 221 RosterEntry re = new RosterEntry(); 222 re.setDecoderFamily(decoderFile.getFamily()); 223 re.setDecoderModel(decoderFile.getModel()); 224 re.setId(Bundle.getMessage("LabelNewDecoder")); 225 // note we're leaving the filename information as null 226 // add the new roster entry to the in-memory roster 227 Roster.getDefault().addEntry(re); 228 229 startProgrammer(decoderFile, re); 230 } 231 232 /** 233 * Meant to be overridden to start the desired type of programmer 234 * 235 * @param decoderFile selected file, passed to eventual implementation 236 * @param r RosterEntry defining this locomotive, to be filled in 237 * later 238 */ 239 protected void startProgrammer(DecoderFile decoderFile, RosterEntry r) { 240 log.error("startProgrammer method in NewLocoSelPane should have been overridden"); 241 } 242 243 private final static Logger log = LoggerFactory.getLogger(NewLocoSelPane.class); 244 245}