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