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