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