001package jmri.jmrit.operations.rollingstock.engines.gui; 002 003import java.awt.event.ActionEvent; 004import java.util.List; 005 006import javax.swing.*; 007import javax.swing.event.TableModelEvent; 008import javax.swing.event.TableModelListener; 009import javax.swing.table.TableColumnModel; 010 011import jmri.InstanceManager; 012import jmri.jmrit.operations.OperationsFrame; 013import jmri.jmrit.operations.OperationsXml; 014import jmri.jmrit.operations.rollingstock.engines.Engine; 015import jmri.jmrit.operations.rollingstock.engines.EngineManager; 016import jmri.jmrit.operations.rollingstock.engines.tools.*; 017import jmri.jmrit.operations.setup.Control; 018import jmri.jmrit.operations.setup.Setup; 019import jmri.swing.JTablePersistenceManager; 020import jmri.util.swing.JmriJOptionPane; 021 022/** 023 * Frame for adding and editing the engine roster for operations. 024 * 025 * @author Bob Jacobsen Copyright (C) 2001 026 * @author Daniel Boudreau Copyright (C) 2008, 2011, 2012, 2013, 2025 027 */ 028public class EnginesTableFrame extends OperationsFrame implements TableModelListener { 029 030 public EnginesTableModel enginesTableModel; 031 public JTable enginesTable; // public for testing 032 boolean showAllLocos = true; 033 JScrollPane enginesPane; 034 EngineManager engineManager = InstanceManager.getDefault(EngineManager.class); 035 036 // labels 037 JLabel numEngines = new JLabel(); 038 JLabel textEngines = new JLabel(Bundle.getMessage("engines")); 039 JLabel textSep1 = new JLabel(" "); 040 041 // radio buttons 042 JRadioButton sortByNumber = new JRadioButton(Bundle.getMessage("Number")); 043 JRadioButton sortByRoad = new JRadioButton(Bundle.getMessage("Road")); 044 JRadioButton sortByModel = new JRadioButton(Bundle.getMessage("Model")); 045 JRadioButton sortByConsist = new JRadioButton(Bundle.getMessage("Consist")); 046 JRadioButton sortByLocation = new JRadioButton(Bundle.getMessage("Location")); 047 JRadioButton sortByDestination = new JRadioButton(Bundle.getMessage("Destination")); 048 JRadioButton sortByTrain = new JRadioButton(Bundle.getMessage("Train")); 049 JRadioButton sortByMoves = new JRadioButton(Bundle.getMessage("Moves")); 050 JRadioButton sortByBuilt = new JRadioButton(Bundle.getMessage("Built")); 051 JRadioButton sortByOwner = new JRadioButton(Bundle.getMessage("Owner")); 052 JRadioButton sortByValue = new JRadioButton(Setup.getValueLabel()); 053 JRadioButton sortByRfid = new JRadioButton(Setup.getRfidLabel()); 054 JRadioButton sortByDcc = new JRadioButton(Bundle.getMessage("DccAddress")); 055 JRadioButton sortByLast = new JRadioButton(Bundle.getMessage("Last")); 056 JRadioButton sortByPickup = new JRadioButton(Bundle.getMessage("Pickup")); 057 JRadioButton sortByComment = new JRadioButton(Bundle.getMessage("Comment")); 058 ButtonGroup group = new ButtonGroup(); 059 060 // major buttons 061 JButton addButton = new JButton(Bundle.getMessage("TitleEngineAdd")); 062 JButton findButton = new JButton(Bundle.getMessage("Find")); 063 JButton saveButton = new JButton(Bundle.getMessage("ButtonSave")); 064 065 JTextField findEngineTextBox = new JTextField(6); 066 067 public EnginesTableFrame(boolean showAllLocos, String locationName, String trackName) { 068 super(Bundle.getMessage("TitleEnginesTable")); 069 this.showAllLocos = showAllLocos; 070 071 // general GUI config 072 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 073 074 // Set up the jtable in a Scroll Pane.. 075 enginesTableModel = new EnginesTableModel(showAllLocos, locationName, trackName); 076 enginesTable = new JTable(enginesTableModel); 077 enginesPane = new JScrollPane(enginesTable); 078 enginesPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 079 enginesTableModel.initTable(enginesTable, this); 080 081 // load the number of engines and listen for changes 082 updateNumEngines(); 083 enginesTableModel.addTableModelListener(this); 084 085 // Set up the control panel 086 // row 1 087 JPanel cp1 = new JPanel(); 088 cp1.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SortBy"))); 089 090 cp1.add(sortByNumber); 091 cp1.add(sortByRoad); 092 cp1.add(sortByModel); 093 cp1.add(sortByConsist); 094 cp1.add(sortByLocation); 095 cp1.add(sortByDestination); 096 cp1.add(sortByTrain); 097 JPanel movep = new JPanel(); 098 movep.setBorder(BorderFactory.createTitledBorder("")); 099 movep.add(sortByMoves); 100 movep.add(sortByBuilt); 101 movep.add(sortByOwner); 102 if (Setup.isValueEnabled()) { 103 movep.add(sortByValue); 104 } 105 if (Setup.isRfidEnabled()) { 106 movep.add(sortByRfid); 107 } 108 movep.add(sortByDcc); 109 movep.add(sortByPickup); 110 movep.add(sortByLast); 111 movep.add(sortByComment); 112 cp1.add(movep); 113 114 // row 2 115 JPanel cp2 = new JPanel(); 116 cp2.setLayout(new BoxLayout(cp2, BoxLayout.X_AXIS)); 117 118 JPanel cp2Add = new JPanel(); 119 cp2Add.setBorder(BorderFactory.createTitledBorder("")); 120 addButton.setToolTipText(Bundle.getMessage("TipAddButton")); 121 cp2Add.add(numEngines); 122 cp2Add.add(textEngines); 123 cp2Add.add(textSep1); 124 cp2Add.add(addButton); 125 cp2.add(cp2Add); 126 127 JPanel cp2Find = new JPanel(); 128 cp2Find.setBorder(BorderFactory.createTitledBorder("")); 129 findButton.setToolTipText(Bundle.getMessage("findEngine")); 130 findEngineTextBox.setToolTipText(Bundle.getMessage("findEngine")); 131 cp2Find.add(findButton); 132 cp2Find.add(findEngineTextBox); 133 cp2.add(cp2Find); 134 135 JPanel cp2Save = new JPanel(); 136 cp2Save.setBorder(BorderFactory.createTitledBorder("")); 137 cp2Save.add(saveButton); 138 cp2.add(cp2Save); 139 140 // place controls in scroll pane 141 JPanel controlPanel = new JPanel(); 142 controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS)); 143 controlPanel.add(cp1); 144 controlPanel.add(cp2); 145 146 // some tool tips 147 sortByLast.setToolTipText(Bundle.getMessage("TipLastMoved")); 148 149 JScrollPane controlPane = new JScrollPane(controlPanel); 150 151 getContentPane().add(enginesPane); 152 getContentPane().add(controlPane); 153 154 // setup buttons 155 addButtonAction(addButton); 156 addButtonAction(findButton); 157 addButtonAction(saveButton); 158 159 sortByNumber.setSelected(true); 160 addRadioButtonAction(sortByNumber); 161 addRadioButtonAction(sortByRoad); 162 addRadioButtonAction(sortByModel); 163 addRadioButtonAction(sortByConsist); 164 addRadioButtonAction(sortByLocation); 165 addRadioButtonAction(sortByDestination); 166 addRadioButtonAction(sortByTrain); 167 addRadioButtonAction(sortByMoves); 168 addRadioButtonAction(sortByBuilt); 169 addRadioButtonAction(sortByOwner); 170 addRadioButtonAction(sortByValue); 171 addRadioButtonAction(sortByRfid); 172 addRadioButtonAction(sortByDcc); 173 addRadioButtonAction(sortByPickup); 174 addRadioButtonAction(sortByLast); 175 addRadioButtonAction(sortByComment); 176 177 findEngineTextBox.addActionListener(this::textBoxActionPerformed); 178 179 group.add(sortByNumber); 180 group.add(sortByRoad); 181 group.add(sortByModel); 182 group.add(sortByConsist); 183 group.add(sortByLocation); 184 group.add(sortByDestination); 185 group.add(sortByTrain); 186 group.add(sortByMoves); 187 group.add(sortByBuilt); 188 group.add(sortByOwner); 189 group.add(sortByValue); 190 group.add(sortByRfid); 191 group.add(sortByDcc); 192 group.add(sortByPickup); 193 group.add(sortByLast); 194 group.add(sortByComment); 195 196 // sort by location 197 if (!showAllLocos) { 198 sortByLocation.doClick(); 199 if (locationName != null) { 200 String title = Bundle.getMessage("TitleEnginesTable") + " " + locationName; 201 if (trackName != null) { 202 title = title + " " + trackName; 203 } 204 setTitle(title); 205 } 206 } 207 208 sortByDcc.setToolTipText(Bundle.getMessage("TipDccAddressFromRoster")); 209 210 // build menu 211 JMenuBar menuBar = new JMenuBar(); 212 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 213 toolMenu.add(new EngineRosterMenu(Bundle.getMessage("TitleEngineRoster"), EngineRosterMenu.MAINMENU, this)); 214 toolMenu.addSeparator(); 215 toolMenu.add(new ShowCheckboxesEnginesTableAction(enginesTableModel)); 216 toolMenu.add(new ResetCheckboxesEnginesTableAction(enginesTableModel)); 217 toolMenu.addSeparator(); 218 toolMenu.add(new NceConsistEngineAction()); 219 toolMenu.addSeparator(); 220 toolMenu.add(new EnginesSetFrameAction(enginesTable)); 221 menuBar.add(toolMenu); 222 menuBar.add(new jmri.jmrit.operations.OperationsMenu()); 223 setJMenuBar(menuBar); 224 addHelpMenu("package.jmri.jmrit.operations.Operations_Locomotives", true); // NOI18N 225 226 initMinimumSize(); 227 228 addHorizontalScrollBarKludgeFix(controlPane, controlPanel); 229 230 // create ShutDownTasks 231 createShutDownTask(); 232 } 233 234 @Override 235 public void radioButtonActionPerformed(ActionEvent ae) { 236 log.debug("radio button activated"); 237 // clear any sorts by column 238 clearTableSort(enginesTable); 239 if (ae.getSource() == sortByNumber) { 240 enginesTableModel.setSort(enginesTableModel.SORTBY_NUMBER); 241 } 242 if (ae.getSource() == sortByRoad) { 243 enginesTableModel.setSort(enginesTableModel.SORTBY_ROAD); 244 } 245 if (ae.getSource() == sortByModel) { 246 enginesTableModel.setSort(enginesTableModel.SORTBY_MODEL); 247 } 248 if (ae.getSource() == sortByConsist) { 249 enginesTableModel.setSort(enginesTableModel.SORTBY_CONSIST); 250 } 251 if (ae.getSource() == sortByLocation) { 252 enginesTableModel.setSort(enginesTableModel.SORTBY_LOCATION); 253 } 254 if (ae.getSource() == sortByDestination) { 255 enginesTableModel.setSort(enginesTableModel.SORTBY_DESTINATION); 256 } 257 if (ae.getSource() == sortByTrain) { 258 enginesTableModel.setSort(enginesTableModel.SORTBY_TRAIN); 259 } 260 if (ae.getSource() == sortByMoves) { 261 enginesTableModel.setSort(enginesTableModel.SORTBY_MOVES); 262 } 263 if (ae.getSource() == sortByBuilt) { 264 enginesTableModel.setSort(enginesTableModel.SORTBY_BUILT); 265 } 266 if (ae.getSource() == sortByOwner) { 267 enginesTableModel.setSort(enginesTableModel.SORTBY_OWNER); 268 } 269 if (ae.getSource() == sortByValue) { 270 enginesTableModel.setSort(enginesTableModel.SORTBY_VALUE); 271 } 272 if (ae.getSource() == sortByRfid) { 273 enginesTableModel.setSort(enginesTableModel.SORTBY_RFID); 274 } 275 if (ae.getSource() == sortByPickup) { 276 enginesTableModel.setSort(enginesTableModel.SORTBY_PICKUP); 277 } 278 if (ae.getSource() == sortByLast) { 279 enginesTableModel.setSort(enginesTableModel.SORTBY_LAST); 280 } 281 if (ae.getSource() == sortByDcc) { 282 enginesTableModel.setSort(enginesTableModel.SORTBY_DCC_ADDRESS); 283 } 284 if (ae.getSource() == sortByComment) { 285 enginesTableModel.setSort(enginesTableModel.SORTBY_COMMENT); 286 } 287 } 288 289 public List<Engine> getSortByList() { 290 return enginesTableModel.getSelectedEngineList(); 291 } 292 293 EngineEditFrame engineEditFrame = null; 294 295 // add, save or find button 296 @Override 297 public void buttonActionPerformed(ActionEvent ae) { 298 // log.debug("engine button activated"); 299 if (ae.getSource() == findButton) { 300 findEngine(); 301 return; 302 } 303 if (ae.getSource() == addButton) { 304 if (engineEditFrame != null) { 305 engineEditFrame.dispose(); 306 } 307 engineEditFrame = new EngineEditFrame(); 308 engineEditFrame.initComponents(); 309 } 310 if (ae.getSource() == saveButton) { 311 if (enginesTable.isEditing()) { 312 log.debug("locomotives table edit true"); 313 enginesTable.getCellEditor().stopCellEditing(); 314 } 315 OperationsXml.save(); 316 if (Setup.isCloseWindowOnSaveEnabled()) { 317 dispose(); 318 } 319 } 320 } 321 322 public void textBoxActionPerformed(ActionEvent ae) { 323 findEngine(); 324 } 325 326 private void findEngine() { 327 int rowindex = enginesTableModel.findEngineByRoadNumber(findEngineTextBox.getText()); 328 if (rowindex < 0) { 329 JmriJOptionPane.showMessageDialog(this, 330 Bundle.getMessage("engineWithRoadNumNotFound", findEngineTextBox.getText()), 331 Bundle.getMessage("engineCouldNotFind"), JmriJOptionPane.INFORMATION_MESSAGE); 332 return; 333 334 } 335 // clear any sorts by column 336 clearTableSort(enginesTable); 337 enginesTable.changeSelection(rowindex, 0, false, false); 338 } 339 340 protected int[] getCurrentTableColumnWidths() { 341 TableColumnModel tcm = enginesTable.getColumnModel(); 342 int[] widths = new int[tcm.getColumnCount()]; 343 for (int i = 0; i < tcm.getColumnCount(); i++) { 344 widths[i] = tcm.getColumn(i).getWidth(); 345 } 346 return widths; 347 } 348 349 @Override 350 public void dispose() { 351 enginesTableModel.removeTableModelListener(this); 352 enginesTableModel.dispose(); 353 if (engineEditFrame != null) { 354 engineEditFrame.dispose(); 355 } 356 InstanceManager.getOptionalDefault(JTablePersistenceManager.class).ifPresent(tpm -> { 357 tpm.stopPersisting(enginesTable); 358 }); 359 super.dispose(); 360 } 361 362 @Override 363 public void tableChanged(TableModelEvent e) { 364 if (Control.SHOW_PROPERTY) { 365 log.debug("Table changed"); 366 } 367 updateNumEngines(); 368 } 369 370 private void updateNumEngines() { 371 String count = filterList(engineManager.getList()); 372 if (showAllLocos) { 373 numEngines.setText(count); 374 } else { 375 String showCount = filterList(getSortByList()); 376 numEngines.setText(showCount + "/" + count); 377 } 378 } 379 380 // only count real engines, ignore clones 381 private String filterList(List<Engine> list) { 382 int count = 0; 383 for (Engine eng : list) { 384 if (!eng.isClone()) { 385 count++; 386 } 387 } 388 return Integer.toString(count); 389 } 390 391 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(EnginesTableFrame.class); 392}