001package jmri.jmrit.operations.rollingstock.cars.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.locations.schedules.ScheduleManager;
015import jmri.jmrit.operations.locations.tools.ModifyLocationsAction;
016import jmri.jmrit.operations.rollingstock.cars.Car;
017import jmri.jmrit.operations.rollingstock.cars.CarManager;
018import jmri.jmrit.operations.rollingstock.cars.tools.*;
019import jmri.jmrit.operations.setup.Control;
020import jmri.jmrit.operations.setup.Setup;
021import jmri.jmrit.operations.trains.tools.TrainsByCarTypeAction;
022import jmri.swing.JTablePersistenceManager;
023import jmri.util.swing.JmriJOptionPane;
024
025/**
026 * Frame for adding and editing the car roster for operations.
027 *
028 * @author Bob Jacobsen Copyright (C) 2001
029 * @author Daniel Boudreau Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013,
030 *         2014, 2025
031 */
032public class CarsTableFrame extends OperationsFrame implements TableModelListener {
033
034    public CarsTableModel carsTableModel;
035    public JTable carsTable;
036    boolean showAllCars;
037    CarManager carManager = InstanceManager.getDefault(CarManager.class);
038
039    // labels
040    JLabel numCars = new JLabel();
041    JLabel textCars = new JLabel(Bundle.getMessage("cars"));
042    JLabel textSep1 = new JLabel("      ");
043
044    // radio buttons
045    JRadioButton sortByNumber = new JRadioButton(Bundle.getMessage("Number"));
046    JRadioButton sortByRoad = new JRadioButton(Bundle.getMessage("Road"));
047    JRadioButton sortByType = new JRadioButton(Bundle.getMessage("Type"));
048    JRadioButton sortByColor = new JRadioButton(Bundle.getMessage("Color"));
049    JRadioButton sortByLoad = new JRadioButton(Bundle.getMessage("Load"));
050    JRadioButton sortByKernel = new JRadioButton(Bundle.getMessage("Kernel"));
051    JRadioButton sortByLocation = new JRadioButton(Bundle.getMessage("Location"));
052    JRadioButton sortByDestination = new JRadioButton(Bundle.getMessage("Destination"));
053    JRadioButton sortByFinalDestination = new JRadioButton(Bundle.getMessage("FD"));
054    JRadioButton sortByRwe = new JRadioButton(Bundle.getMessage("RWE"));
055    JRadioButton sortByRwl = new JRadioButton(Bundle.getMessage("RWL"));
056    JRadioButton sortByRoute = new JRadioButton(Bundle.getMessage("Route"));
057    JRadioButton sortByDivision = new JRadioButton(Bundle.getMessage("Division"));
058    JRadioButton sortByTrain = new JRadioButton(Bundle.getMessage("Train"));
059    JRadioButton sortByMoves = new JRadioButton(Bundle.getMessage("Moves"));
060    JRadioButton sortByBuilt = new JRadioButton(Bundle.getMessage("Built"));
061    JRadioButton sortByOwner = new JRadioButton(Bundle.getMessage("Owner"));
062    JRadioButton sortByValue = new JRadioButton(Setup.getValueLabel());
063    JRadioButton sortByRfid = new JRadioButton(Setup.getRfidLabel());
064    JRadioButton sortByWait = new JRadioButton(Bundle.getMessage("Wait"));
065    JRadioButton sortByPickup = new JRadioButton(Bundle.getMessage("Pickup"));
066    JRadioButton sortByLast = new JRadioButton(Bundle.getMessage("Last"));
067    JRadioButton sortByComment = new JRadioButton(Bundle.getMessage("Comment"));
068    ButtonGroup group = new ButtonGroup();
069
070    // major buttons
071    JButton addButton = new JButton(Bundle.getMessage("TitleCarAdd"));
072    JButton findButton = new JButton(Bundle.getMessage("Find"));
073    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
074
075    JTextField findCarTextBox = new JTextField(6);
076
077    public CarsTableFrame(boolean showAllCars, String locationName, String trackName) {
078        super(Bundle.getMessage("TitleCarsTable"));
079        this.showAllCars = showAllCars;
080        // general GUI configuration
081        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
082
083        // Set up the table in a Scroll Pane..
084        carsTableModel = new CarsTableModel(showAllCars, locationName, trackName);
085        carsTable = new JTable(carsTableModel);
086        JScrollPane carsPane = new JScrollPane(carsTable);
087        carsPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
088        carsTableModel.initTable(carsTable, this);
089
090        // load the number of cars and listen for changes
091        updateNumCars();
092        carsTableModel.addTableModelListener(this);
093
094        // Set up the control panel
095        // row 1
096        JPanel cp1 = new JPanel();
097        cp1.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SortBy")));
098        cp1.add(sortByNumber);
099        cp1.add(sortByRoad);
100        cp1.add(sortByType);
101
102        JPanel clp = new JPanel();
103        clp.setBorder(BorderFactory.createTitledBorder(""));  
104        clp.add(sortByLoad);
105        clp.add(sortByColor);
106        cp1.add(clp);
107        cp1.add(sortByKernel);
108        cp1.add(sortByLocation);
109
110        JPanel destp = new JPanel();
111        destp.setBorder(BorderFactory.createTitledBorder(""));
112        destp.add(sortByDestination);
113        destp.add(sortByFinalDestination);
114        destp.add(sortByRwe);
115        destp.add(sortByRwl);
116        destp.add(sortByRoute);
117        cp1.add(destp);
118        cp1.add(sortByDivision);
119        cp1.add(sortByTrain);
120
121        JPanel movep = new JPanel();
122        movep.setBorder(BorderFactory.createTitledBorder(""));
123        movep.add(sortByMoves);
124        movep.add(sortByBuilt);
125        movep.add(sortByOwner);
126        if (Setup.isValueEnabled()) {
127            movep.add(sortByValue);
128        }
129        if (Setup.isRfidEnabled()) {
130            movep.add(sortByRfid);
131        }
132        if (InstanceManager.getDefault(ScheduleManager.class).numEntries() > 0) {
133            movep.add(sortByWait);
134            movep.add(sortByPickup);
135        }
136        movep.add(sortByLast);
137        movep.add(sortByComment);
138        cp1.add(movep);
139
140        // row 2
141        JPanel cp2 = new JPanel();
142        cp2.setLayout(new BoxLayout(cp2, BoxLayout.X_AXIS));
143
144        JPanel cp2Add = new JPanel();
145        cp2Add.setBorder(BorderFactory.createTitledBorder(""));
146        addButton.setToolTipText(Bundle.getMessage("TipAddButton"));
147        cp2Add.add(numCars);
148        cp2Add.add(textCars);
149        cp2Add.add(textSep1);
150        cp2Add.add(addButton);
151        cp2.add(cp2Add);
152
153        JPanel cp2Find = new JPanel();
154        cp2Find.setBorder(BorderFactory.createTitledBorder(""));
155        findButton.setToolTipText(Bundle.getMessage("findCar"));
156        findCarTextBox.setToolTipText(Bundle.getMessage("findCar"));
157        cp2Find.add(findButton);
158        cp2Find.add(findCarTextBox);
159        cp2.add(cp2Find);
160
161        JPanel cp2Save = new JPanel();
162        cp2Save.setBorder(BorderFactory.createTitledBorder(""));
163        cp2Save.add(saveButton);
164        cp2.add(cp2Save);
165
166        // place controls in scroll pane
167        JPanel controlPanel = new JPanel();
168        controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
169        controlPanel.add(cp1);
170        controlPanel.add(cp2);
171
172        // some tool tips
173        sortByFinalDestination.setToolTipText(Bundle.getMessage("FinalDestination"));
174        sortByRwe.setToolTipText(Bundle.getMessage("ReturnWhenEmpty"));
175        sortByRwl.setToolTipText(Bundle.getMessage("ReturnWhenLoaded"));
176        sortByPickup.setToolTipText(Bundle.getMessage("TipPickup"));
177        sortByLast.setToolTipText(Bundle.getMessage("TipLastMoved"));
178
179        JScrollPane controlPane = new JScrollPane(controlPanel);
180
181        getContentPane().add(carsPane);
182        getContentPane().add(controlPane);
183
184        // setup buttons
185        addButtonAction(addButton);
186        addButtonAction(findButton);
187        addButtonAction(saveButton);
188
189        sortByNumber.setSelected(true);
190        addRadioButtonAction(sortByNumber);
191        addRadioButtonAction(sortByRoad);
192        addRadioButtonAction(sortByType);
193        addRadioButtonAction(sortByColor);
194        addRadioButtonAction(sortByLoad);
195        addRadioButtonAction(sortByKernel);
196        addRadioButtonAction(sortByLocation);
197        addRadioButtonAction(sortByDestination);
198        addRadioButtonAction(sortByFinalDestination);
199        addRadioButtonAction(sortByRwe);
200        addRadioButtonAction(sortByRwl);
201        addRadioButtonAction(sortByRoute);
202        addRadioButtonAction(sortByDivision);
203        addRadioButtonAction(sortByTrain);
204        addRadioButtonAction(sortByMoves);
205        addRadioButtonAction(sortByBuilt);
206        addRadioButtonAction(sortByOwner);
207        addRadioButtonAction(sortByValue);
208        addRadioButtonAction(sortByRfid);
209        addRadioButtonAction(sortByWait);
210        addRadioButtonAction(sortByPickup);
211        addRadioButtonAction(sortByLast);
212        addRadioButtonAction(sortByComment);
213
214        findCarTextBox.addActionListener(this::textBoxActionPerformed);
215
216        group.add(sortByNumber);
217        group.add(sortByRoad);
218        group.add(sortByType);
219        group.add(sortByColor);
220        group.add(sortByLoad);
221        group.add(sortByKernel);
222        group.add(sortByLocation);
223        group.add(sortByDestination);
224        group.add(sortByFinalDestination);
225        group.add(sortByRwe);
226        group.add(sortByRwl);
227        group.add(sortByRoute);
228        group.add(sortByDivision);
229        group.add(sortByTrain);
230        group.add(sortByMoves);
231        group.add(sortByBuilt);
232        group.add(sortByOwner);
233        group.add(sortByValue);
234        group.add(sortByRfid);
235        group.add(sortByWait);
236        group.add(sortByPickup);
237        group.add(sortByLast);
238        group.add(sortByComment);
239
240        // sort by location
241        if (!showAllCars) {
242            sortByLocation.doClick();
243            if (locationName != null) {
244                String title = Bundle.getMessage("TitleCarsTable") + " " + locationName;
245                if (trackName != null) {
246                    title = title + " " + trackName;
247                }
248                setTitle(title);
249            }
250        }
251
252        // build menu
253        JMenuBar menuBar = new JMenuBar();
254        JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools"));
255        toolMenu.add(new CarRosterMenu(Bundle.getMessage("TitleCarRoster"), CarRosterMenu.MAINMENU, this));
256        toolMenu.addSeparator();
257        toolMenu.add(new ShowCheckboxesCarsTableAction(carsTableModel));
258        toolMenu.add(new ResetCheckboxesCarsTableAction(carsTableModel));
259        toolMenu.addSeparator();
260        toolMenu.add(new ModifyLocationsAction());
261        toolMenu.add(new TrainsByCarTypeAction());
262        toolMenu.addSeparator();
263        toolMenu.add(new PrintCarLoadsAction(false));
264        toolMenu.add(new PrintCarLoadsAction(true));
265        toolMenu.addSeparator();
266        toolMenu.add(new CarsSetFrameAction(carsTable));
267        menuBar.add(toolMenu);
268        menuBar.add(new jmri.jmrit.operations.OperationsMenu());
269        setJMenuBar(menuBar);
270        addHelpMenu("package.jmri.jmrit.operations.Operations_Cars", true); // NOI18N
271
272        initMinimumSize();
273
274        addHorizontalScrollBarKludgeFix(controlPane, controlPanel);
275
276        // create ShutDownTasks
277        createShutDownTask();
278    }
279
280    @Override
281    public void radioButtonActionPerformed(ActionEvent ae) {
282        log.debug("radio button activated");
283        // clear any sorts by column
284        clearTableSort(carsTable);
285        if (ae.getSource() == sortByNumber) {
286            carsTableModel.setSort(carsTableModel.SORTBY_NUMBER);
287        }
288        if (ae.getSource() == sortByRoad) {
289            carsTableModel.setSort(carsTableModel.SORTBY_ROAD);
290        }
291        if (ae.getSource() == sortByType) {
292            carsTableModel.setSort(carsTableModel.SORTBY_TYPE);
293        }
294        if (ae.getSource() == sortByColor) {
295            carsTableModel.setSort(carsTableModel.SORTBY_COLOR);
296        }
297        if (ae.getSource() == sortByLoad) {
298            carsTableModel.setSort(carsTableModel.SORTBY_LOAD);
299        }
300        if (ae.getSource() == sortByKernel) {
301            carsTableModel.setSort(carsTableModel.SORTBY_KERNEL);
302        }
303        if (ae.getSource() == sortByLocation) {
304            carsTableModel.setSort(carsTableModel.SORTBY_LOCATION);
305        }
306        if (ae.getSource() == sortByDestination) {
307            carsTableModel.setSort(carsTableModel.SORTBY_DESTINATION);
308        }
309        if (ae.getSource() == sortByFinalDestination) {
310            carsTableModel.setSort(carsTableModel.SORTBY_FINALDESTINATION);
311        }
312        if (ae.getSource() == sortByRwe) {
313            carsTableModel.setSort(carsTableModel.SORTBY_RWE);
314        }
315        if (ae.getSource() == sortByRwl) {
316            carsTableModel.setSort(carsTableModel.SORTBY_RWL);
317        }
318        if (ae.getSource() == sortByRoute) {
319            carsTableModel.setSort(carsTableModel.SORTBY_ROUTE);
320        }
321        if (ae.getSource() == sortByDivision) {
322            carsTableModel.setSort(carsTableModel.SORTBY_DIVISION);
323        }
324        if (ae.getSource() == sortByTrain) {
325            carsTableModel.setSort(carsTableModel.SORTBY_TRAIN);
326        }
327        if (ae.getSource() == sortByMoves) {
328            carsTableModel.setSort(carsTableModel.SORTBY_MOVES);
329        }
330        if (ae.getSource() == sortByBuilt) {
331            carsTableModel.setSort(carsTableModel.SORTBY_BUILT);
332        }
333        if (ae.getSource() == sortByOwner) {
334            carsTableModel.setSort(carsTableModel.SORTBY_OWNER);
335        }
336        if (ae.getSource() == sortByValue) {
337            carsTableModel.setSort(carsTableModel.SORTBY_VALUE);
338        }
339        if (ae.getSource() == sortByRfid) {
340            carsTableModel.setSort(carsTableModel.SORTBY_RFID);
341        }
342        if (ae.getSource() == sortByWait) {
343            carsTableModel.setSort(carsTableModel.SORTBY_WAIT);
344        }
345        if (ae.getSource() == sortByPickup) {
346            carsTableModel.setSort(carsTableModel.SORTBY_PICKUP);
347        }
348        if (ae.getSource() == sortByLast) {
349            carsTableModel.setSort(carsTableModel.SORTBY_LAST);
350        }
351        if (ae.getSource() == sortByComment) {
352            carsTableModel.setSort(carsTableModel.SORTBY_COMMENT);
353        }
354    }
355
356    public List<Car> getSortByList() {
357        return carsTableModel.carList;
358    }
359
360    CarEditFrame f = null;
361
362    // add, find or save button
363    @Override
364    public void buttonActionPerformed(ActionEvent ae) {
365        // log.debug("car button activated");
366        if (ae.getSource() == findButton) {
367            findCar();
368            return;
369        }
370        if (ae.getSource() == addButton) {
371            if (f != null) {
372                f.dispose();
373            }
374            f = new CarEditFrame();
375            f.initComponents(); // default is add car
376        }
377        if (ae.getSource() == saveButton) {
378            if (carsTable.isEditing()) {
379                log.debug("cars table edit true");
380                carsTable.getCellEditor().stopCellEditing();
381            }
382            OperationsXml.save();
383            if (Setup.isCloseWindowOnSaveEnabled()) {
384                dispose();
385            }
386        }
387    }
388
389    public void textBoxActionPerformed(ActionEvent ae) {
390        findCar();
391    }
392
393    private void findCar() {
394        int rowindex = carsTableModel.findCarByRoadNumber(findCarTextBox.getText());
395        if (rowindex < 0) {
396            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("carWithRoadNumNotFound",
397                    findCarTextBox.getText()), Bundle.getMessage("carCouldNotFind"),
398                    JmriJOptionPane.INFORMATION_MESSAGE);
399            return;
400        }
401        // clear any sorts by column
402        clearTableSort(carsTable);
403        carsTable.changeSelection(rowindex, 0, false, false);
404    }
405
406    protected int[] getCurrentTableColumnWidths() {
407        TableColumnModel tcm = carsTable.getColumnModel();
408        int[] widths = new int[tcm.getColumnCount()];
409        for (int i = 0; i < tcm.getColumnCount(); i++) {
410            widths[i] = tcm.getColumn(i).getWidth();
411        }
412        return widths;
413    }
414
415    @Override
416    public void dispose() {
417        carsTableModel.removeTableModelListener(this);
418        carsTableModel.dispose();
419        if (f != null) {
420            f.dispose();
421        }
422        InstanceManager.getOptionalDefault(JTablePersistenceManager.class).ifPresent(tpm -> {
423            tpm.stopPersisting(carsTable);
424        });
425        super.dispose();
426    }
427
428    @Override
429    public void tableChanged(TableModelEvent e) {
430        if (Control.SHOW_PROPERTY) {
431            log.debug("Table changed");
432        }
433        updateNumCars();
434    }
435
436    private void updateNumCars() {
437        String count = filterCarList(InstanceManager.getDefault(CarManager.class).getList());
438        if (showAllCars) {
439            numCars.setText(count);
440        } else {
441            String showCount = filterCarList(getSortByList());
442            numCars.setText(showCount + "/" + count);
443        }
444    }
445
446    // only count real cars, ignore clones
447    private String filterCarList(List<Car> list) {
448        int count = 0;
449        for (Car car : list) {
450            if (!car.isClone()) {
451                count++;
452            }
453        }
454        return Integer.toString(count);
455    }
456
457    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CarsTableFrame.class);
458
459}