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