001package jmri.jmrit.operations.rollingstock.cars.tools;
002
003import java.awt.*;
004import java.io.IOException;
005import java.util.List;
006
007import javax.swing.*;
008
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011
012import jmri.InstanceManager;
013import jmri.jmrit.operations.OperationsFrame;
014import jmri.jmrit.operations.OperationsPanel;
015import jmri.jmrit.operations.locations.LocationManager;
016import jmri.jmrit.operations.rollingstock.cars.*;
017import jmri.jmrit.operations.setup.Control;
018import jmri.jmrit.operations.setup.Setup;
019import jmri.jmrit.operations.trains.TrainCommon;
020import jmri.util.davidflanagan.HardcopyWriter;
021
022/**
023 * Prints a summary of the car roster
024 * <p>
025 * This uses the older style printing, for compatibility with Java 1.1.8 in
026 * MacIntosh MRJ
027 *
028 * @author Bob Jacobsen Copyright (C) 2003
029 * @author Daniel Boudreau Copyright (C) 2023
030 */
031
032public class PrintCarRosterFrame extends OperationsFrame {
033
034    boolean _isPreview;
035    CarsTableFrame _ctf;
036
037    JComboBox<String> sortByComboBox = new JComboBox<>();
038    JComboBox<String> manifestOrientationComboBox = new JComboBox<>();
039    JComboBox<Integer> fontSizeComboBox = new JComboBox<>();
040
041    JCheckBox printCarsWithLocation = new JCheckBox(Bundle.getMessage("PrintCarsWithLocation"));
042    JCheckBox printCarLength = new JCheckBox(Bundle.getMessage("PrintCarLength"));
043    JCheckBox printCarWeight = new JCheckBox(Bundle.getMessage("PrintCarWeight"));
044    JCheckBox printCarColor = new JCheckBox(Bundle.getMessage("PrintCarColor"));
045    JCheckBox printCarOwner = new JCheckBox(Bundle.getMessage("PrintCarOwner"));
046    JCheckBox printCarBuilt = new JCheckBox(Bundle.getMessage("PrintCarBuilt"));
047    JCheckBox printCarLoad = new JCheckBox(Bundle.getMessage("PrintCarLoad"));
048    JCheckBox printCarKernel = new JCheckBox(Bundle.getMessage("PrintKernel"));
049    JCheckBox printCarValue = new JCheckBox(
050            Bundle.getMessage("PrintCar", Setup.getValueLabel()));
051    JCheckBox printCarRfid = new JCheckBox(
052            Bundle.getMessage("PrintCar", Setup.getRfidLabel()));
053    JCheckBox printCarLast = new JCheckBox(Bundle.getMessage("PrintCarLastMoved"));
054    JCheckBox printCarWait = new JCheckBox(Bundle.getMessage("PrintCarWait"));
055    JCheckBox printCarPickup = new JCheckBox(Bundle.getMessage("PrintCarPickup"));
056    JCheckBox printCarLocation = new JCheckBox(Bundle.getMessage("PrintCarLocation"));
057    JCheckBox printCarTrain = new JCheckBox(Bundle.getMessage("PrintCarTrain"));
058    JCheckBox printCarDestination = new JCheckBox(Bundle.getMessage("PrintCarDestination"));
059    JCheckBox printCarFinalDestination = new JCheckBox(Bundle.getMessage("PrintCarFinalDestination"));
060    JCheckBox printCarRWE = new JCheckBox(Bundle.getMessage("PrintCarReturnWhenEmpty"));
061    JCheckBox printCarRWL = new JCheckBox(Bundle.getMessage("PrintCarReturnWhenLoaded"));
062    JCheckBox printDivision = new JCheckBox(Bundle.getMessage("PrintCarDivision"));
063    JCheckBox printCarStatus = new JCheckBox(Bundle.getMessage("PrintCarStatus"));
064    JCheckBox printCarComment = new JCheckBox(Bundle.getMessage("PrintCarComment"));
065    JCheckBox printSpace = new JCheckBox(Bundle.getMessage("PrintSpace"));
066    JCheckBox printPage = new JCheckBox(Bundle.getMessage("PrintPage"));
067
068    JButton okayButton = new JButton(Bundle.getMessage("ButtonOK"));
069
070    public PrintCarRosterFrame(boolean isPreview, CarsTableFrame carsTableFrame) {
071        super();
072        _isPreview = isPreview;
073        _ctf = carsTableFrame;
074
075        // create panel
076        JPanel pSortBy = new JPanel();
077        pSortBy.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SortBy")));
078        pSortBy.add(sortByComboBox);
079        addComboBoxAction(sortByComboBox);
080
081        JPanel pOrientation = new JPanel();
082        pOrientation.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOrientation")));
083        pOrientation.add(manifestOrientationComboBox);
084
085        manifestOrientationComboBox.addItem(Setup.PORTRAIT);
086        manifestOrientationComboBox.addItem(Setup.LANDSCAPE);
087
088        JPanel pFontSize = new JPanel();
089        pFontSize.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutFontSize")));
090        pFontSize.add(fontSizeComboBox);
091
092        OperationsPanel.loadFontSizeComboBox(fontSizeComboBox);
093        fontSizeComboBox.setSelectedItem(Control.reportFontSize);
094
095        JPanel pPanel = new JPanel();
096        pPanel.setLayout(new GridBagLayout());
097        JScrollPane panePanel = new JScrollPane(pPanel);
098        panePanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("PrintOptions")));
099        addItemLeft(pPanel, printCarsWithLocation, 0, 0);
100        addItemLeft(pPanel, printCarLength, 0, 1);
101        addItemLeft(pPanel, printCarWeight, 0, 2);
102        addItemLeft(pPanel, printCarColor, 0, 3);
103        addItemLeft(pPanel, printCarLoad, 0, 4);
104        addItemLeft(pPanel, printCarKernel, 0, 5);
105        addItemLeft(pPanel, printCarOwner, 0, 6);
106        addItemLeft(pPanel, printCarBuilt, 0, 7);
107        addItemLeft(pPanel, printCarLast, 0, 8);
108        addItemLeft(pPanel, printCarWait, 0, 9);
109        addItemLeft(pPanel, printCarPickup, 0, 10);
110        if (Setup.isValueEnabled()) {
111            addItemLeft(pPanel, printCarValue, 0, 11);
112        }
113        if (Setup.isRfidEnabled()) {
114            addItemLeft(pPanel, printCarRfid, 0, 12);
115        }
116        addItemLeft(pPanel, printCarLocation, 0, 13);
117        addItemLeft(pPanel, printCarTrain, 0, 14);
118        addItemLeft(pPanel, printCarDestination, 0, 15);
119        addItemLeft(pPanel, printCarFinalDestination, 0, 16);
120        addItemLeft(pPanel, printCarRWE, 0, 17);
121        addItemLeft(pPanel, printCarRWL, 0, 18);
122        addItemLeft(pPanel, printDivision, 0, 19);
123        addItemLeft(pPanel, printCarStatus, 0, 20);
124        addItemLeft(pPanel, printCarComment, 0, 21);
125        addItemLeft(pPanel, printSpace, 0, 22);
126        addItemLeft(pPanel, printPage, 0, 23);
127
128        // set defaults
129        printCarsWithLocation.setSelected(false);
130        printCarLength.setSelected(true);
131        printCarWeight.setSelected(false);
132        printCarColor.setSelected(true);
133        printCarLoad.setSelected(false);
134        printCarKernel.setSelected(false);
135        printCarOwner.setSelected(false);
136        printCarBuilt.setSelected(false);
137        printCarLast.setSelected(false);
138        printCarWait.setSelected(false);
139        printCarPickup.setSelected(false);
140        printCarValue.setSelected(false);
141        printCarRfid.setSelected(false);
142        printCarLocation.setSelected(true);
143        printCarTrain.setSelected(false);
144        printCarDestination.setSelected(false);
145        printCarFinalDestination.setSelected(false);
146        printCarRWE.setSelected(false);
147        printCarRWL.setSelected(false);
148        printDivision.setSelected(false);
149        printCarStatus.setSelected(false);
150        printCarComment.setSelected(false);
151        printSpace.setSelected(false);
152        printPage.setSelected(false);
153
154        // add tool tips
155        printSpace.setToolTipText(Bundle.getMessage("TipSelectSortByLoc"));
156        printPage.setToolTipText(Bundle.getMessage("TipSelectSortByLoc"));
157
158        JPanel pButtons = new JPanel();
159        pButtons.setLayout(new GridBagLayout());
160        pButtons.add(okayButton);
161        pButtons.setBorder(BorderFactory.createTitledBorder(""));
162        addButtonAction(okayButton);
163
164        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
165        getContentPane().add(pSortBy);
166        getContentPane().add(pOrientation);
167        getContentPane().add(pFontSize);
168        getContentPane().add(panePanel);
169        getContentPane().add(pButtons);
170
171        initMinimumSize(new Dimension(Control.panelWidth300, Control.panelHeight500));
172
173        if (_isPreview) {
174            setTitle(Bundle.getMessage("MenuItemPreview"));
175        } else {
176            setTitle(Bundle.getMessage("MenuItemPrint"));
177        }
178        loadSortByComboBox(sortByComboBox);
179        updateLocationCheckboxes();
180    }
181
182    private void loadSortByComboBox(JComboBox<String> box) {
183        box.removeAllItems();
184        for (int i = _ctf.carsTableModel.SORTBY_NUMBER; i <= _ctf.carsTableModel.SORTBY_COMMENT; i++) {
185            box.addItem(_ctf.carsTableModel.getSortByName(i));
186        }
187        box.setSelectedItem(_ctf.carsTableModel.getSortByName());
188    }
189
190    @Override
191    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
192        setVisible(false);
193        printCars();
194    }
195
196    @Override
197    public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
198        updateLocationCheckboxes();
199    }
200
201    private void updateLocationCheckboxes() {
202        if (sortByComboBox.getSelectedItem() != null &&
203                sortByComboBox.getSelectedItem()
204                        .equals(_ctf.carsTableModel.getSortByName(_ctf.carsTableModel.SORTBY_LOCATION))) {
205            printSpace.setEnabled(true);
206            printPage.setEnabled(true);
207        } else {
208            printSpace.setEnabled(false);
209            printPage.setEnabled(false);
210            printSpace.setSelected(false);
211            printPage.setSelected(false);
212        }
213    }
214
215    int numberCharPerLine;
216
217    private void printCars() {
218        boolean landscape = false;
219        if (manifestOrientationComboBox.getSelectedItem() != null &&
220                manifestOrientationComboBox.getSelectedItem().equals(Setup.LANDSCAPE)) {
221            landscape = true;
222        }
223
224        int fontSize = (int) fontSizeComboBox.getSelectedItem();
225
226        // obtain a HardcopyWriter to do this
227        try (HardcopyWriter writer = new HardcopyWriter(new Frame(), Bundle.getMessage("TitleCarRoster"), fontSize, .5,
228                .5, .5, .5, _isPreview, "", landscape, true, null)) {
229
230            numberCharPerLine = writer.getCharactersPerLine();
231
232            printHeader(writer);
233
234            printRoster(writer);
235
236        } catch (HardcopyWriter.PrintCanceledException ex) {
237            log.debug("Print cancelled");
238        } catch (IOException we) {
239            log.error("Error printing car roster");
240        }
241    }
242
243    private void printHeader(HardcopyWriter writer) throws IOException {
244        String s = padAttribute(Bundle.getMessage("Number"), Control.max_len_string_print_road_number) +
245                padAttribute(Bundle.getMessage("Road"),
246                        InstanceManager.getDefault(CarRoads.class).getMaxNameLength()) +
247                padAttribute(Bundle.getMessage("Type"),
248                        InstanceManager.getDefault(CarTypes.class).getMaxFullNameLength()) +
249                (printCarLength.isSelected() ? Bundle.getMessage("Len") + "  " : "") +
250                (printCarWeight.isSelected() ? "     " : "") +
251                (printCarColor.isSelected()
252                        ? padAttribute(Bundle.getMessage("Color"),
253                                InstanceManager.getDefault(CarColors.class).getMaxNameLength())
254                        : "") +
255                (printCarLoad.isSelected()
256                        ? padAttribute(Bundle.getMessage("Load"),
257                                InstanceManager.getDefault(CarLoads.class).getMaxNameLength())
258                        : "") +
259                (printCarKernel.isSelected() ? padAttribute(("Kernel"), Control.max_len_string_attibute) : "") +
260                (printCarOwner.isSelected()
261                        ? padAttribute(Bundle.getMessage("Owner"),
262                                InstanceManager.getDefault(CarOwners.class).getMaxNameLength())
263                        : "") +
264                (printCarBuilt.isSelected() ? Bundle.getMessage("Built") + " " : "") +
265                (printCarLast.isSelected() ? Bundle.getMessage("LastMoved") + " " : "") +
266                (printCarWait.isSelected() ? Bundle.getMessage("Wait") + " " : "") +
267                (printCarPickup.isSelected() ? padAttribute(Bundle.getMessage("Pickup"), 10) : "") +
268                (printCarValue.isSelected() ? padAttribute(Setup.getValueLabel(), Control.max_len_string_attibute)
269                        : "") +
270                (printCarRfid.isSelected() ? padAttribute(Setup.getRfidLabel(), Control.max_len_string_attibute)
271                        : "") +
272                (printCarLocation.isSelected()
273                        ? padAttribute(Bundle.getMessage("Location"),
274                                InstanceManager.getDefault(LocationManager.class)
275                                        .getMaxLocationAndTrackNameLength() +
276                                        3)
277                        : "") +
278                (printCarTrain.isSelected()
279                        ? padAttribute(Bundle.getMessage("Train"), Control.max_len_string_train_name / 2)
280                        : "") +
281                (printCarDestination.isSelected()
282                        ? padAttribute(Bundle.getMessage("Destination"),
283                                InstanceManager.getDefault(LocationManager.class)
284                                        .getMaxLocationAndTrackNameLength() +
285                                        3)
286                        : "") +
287                (printCarFinalDestination.isSelected()
288                        ? padAttribute(Bundle.getMessage("FinalDestination"),
289                                InstanceManager.getDefault(LocationManager.class)
290                                        .getMaxLocationAndTrackNameLength() +
291                                        3)
292                        : "") +
293                (printCarRWE.isSelected()
294                        ? padAttribute(Bundle.getMessage("ReturnWhenEmpty"),
295                                InstanceManager.getDefault(LocationManager.class)
296                                        .getMaxLocationAndTrackNameLength() +
297                                        3)
298                        : "") +
299                (printCarRWL.isSelected()
300                        ? padAttribute(Bundle.getMessage("ReturnWhenLoaded"),
301                                InstanceManager.getDefault(LocationManager.class)
302                                        .getMaxLocationAndTrackNameLength() +
303                                        3)
304                        : "") +
305                (printDivision.isSelected() ? Bundle.getMessage("HomeDivision") + " " : "") +
306                (printCarStatus.isSelected() ? Bundle.getMessage("Status") + " " : "") +
307                (printCarComment.isSelected() ? Bundle.getMessage("Comment") : "");
308        if (s.length() > numberCharPerLine) {
309            s = s.substring(0, numberCharPerLine);
310            writer.write(Bundle.getMessage("ErrorTextPage") + NEW_LINE);
311        }
312        writer.write(s + NEW_LINE);
313    }
314
315    private void printRoster(HardcopyWriter writer) throws IOException {
316        // Loop through the Roster, printing as needed
317        String location = "";
318        String number;
319        String road;
320        String type;
321        String length = "";
322        String weight = "";
323        String color = "";
324        String owner = "";
325        String built = "";
326        String load = "";
327        String kernel = "";
328        String train = "";
329        String destination = "";
330        String finalDestination = "";
331        String returnWhenEmpty = "";
332        String returnWhenLoaded = "";
333        String division = "";
334        String value = "";
335        String rfid = "";
336        String last = "";
337        String wait = "";
338        String schedule = "";
339        String status = "";
340        String comment = "";
341        String previousLocation = null;
342        List<Car> cars = _ctf.carsTableModel.getCarList(sortByComboBox.getSelectedIndex());
343        for (Car car : cars) {
344            if (printCarsWithLocation.isSelected() && car.getLocation() == null) {
345                continue; // car doesn't have a location skip
346            }
347            location = "";
348            destination = "";
349            finalDestination = "";
350            returnWhenEmpty = "";
351            returnWhenLoaded = "";
352
353            if (printCarLocation.isSelected()) {
354                if (car.getLocation() != null) {
355                    location = car.getLocationName().trim() + " - " + car.getTrackName().trim();
356                }
357                location = padAttribute(location,
358                        InstanceManager.getDefault(LocationManager.class).getMaxLocationAndTrackNameLength() +
359                                3);
360            }
361            // Page break between locations?
362            if (previousLocation != null &&
363                    !car.getLocationName().trim().equals(previousLocation) &&
364                    printPage.isSelected()) {
365                writer.pageBreak();
366                printHeader(writer);
367            } // Add a line between locations?
368            else if (previousLocation != null &&
369                    !car.getLocationName().trim().equals(previousLocation) &&
370                    printSpace.isSelected()) {
371                writer.write(NEW_LINE);
372            }
373            previousLocation = car.getLocationName().trim();
374
375            // car number
376            number = padAttribute(car.getNumber().trim(), Control.max_len_string_print_road_number);
377            // car road
378            road = padAttribute(car.getRoadName().trim(),
379                    InstanceManager.getDefault(CarRoads.class).getMaxNameLength());
380            // car type
381            type = padAttribute(car.getTypeName().trim(),
382                    InstanceManager.getDefault(CarTypes.class).getMaxFullNameLength());
383
384            if (printCarLength.isSelected()) {
385                length = padAttribute(car.getLength().trim(), Control.max_len_string_length_name);
386            }
387            if (printCarWeight.isSelected()) {
388                weight = padAttribute(car.getWeight().trim(), Control.max_len_string_weight_name);
389            }
390            if (printCarColor.isSelected()) {
391                color = padAttribute(car.getColor().trim(),
392                        InstanceManager.getDefault(CarColors.class).getMaxNameLength());
393            }
394            if (printCarLoad.isSelected()) {
395                load = padAttribute(car.getLoadName().trim(),
396                        InstanceManager.getDefault(CarLoads.class).getMaxNameLength());
397            }
398            if (printCarKernel.isSelected()) {
399                kernel = padAttribute(car.getKernelName().trim(), Control.max_len_string_attibute);
400            }
401            if (printCarOwner.isSelected()) {
402                owner = padAttribute(car.getOwnerName().trim(),
403                        InstanceManager.getDefault(CarOwners.class).getMaxNameLength());
404            }
405            if (printCarBuilt.isSelected()) {
406                built = padAttribute(car.getBuilt().trim(), Control.max_len_string_built_name);
407            }
408            if (printCarLast.isSelected()) {
409                last = padAttribute(car.getLastDate().split(" ")[0], 10);
410            }
411            if (printCarWait.isSelected()) {
412                wait = padAttribute(Integer.toString(car.getWait()), 4);
413            }
414            if (printCarPickup.isSelected()) {
415                schedule = padAttribute(car.getPickupScheduleName(), 10);
416            }
417            if (printCarValue.isSelected()) {
418                value = padAttribute(car.getValue().trim(), Control.max_len_string_attibute);
419            }
420            if (printCarRfid.isSelected()) {
421                rfid = padAttribute(car.getRfid().trim(), Control.max_len_string_attibute);
422            }
423            // pad out train to half of its maximum length
424            if (printCarTrain.isSelected()) {
425                train = padAttribute(car.getTrainName().trim(), Control.max_len_string_train_name / 2);
426            }
427            if (printCarDestination.isSelected()) {
428                if (car.getDestination() != null) {
429                    destination =
430                            car.getDestinationName().trim() + " - " + car.getDestinationTrackName().trim();
431                }
432                destination = padAttribute(destination,
433                        InstanceManager.getDefault(LocationManager.class).getMaxLocationAndTrackNameLength() +
434                                3);
435            }
436            if (printCarFinalDestination.isSelected()) {
437                if (car.getFinalDestination() != null) {
438                    finalDestination = car.getFinalDestinationName().trim();
439                    if (car.getFinalDestinationTrack() != null) {
440                        finalDestination = finalDestination +
441                                " - " +
442                                car.getFinalDestinationTrackName().trim();
443                    }
444                }
445                finalDestination = padAttribute(finalDestination,
446                        InstanceManager.getDefault(LocationManager.class).getMaxLocationAndTrackNameLength() +
447                                3);
448            }
449            if (printCarRWE.isSelected()) {
450                if (car.getReturnWhenEmptyDestination() != null) {
451                    returnWhenEmpty = car.getReturnWhenEmptyDestinationName().trim() +
452                            " - " +
453                            car.getReturnWhenEmptyDestTrackName().trim();
454                }
455                returnWhenEmpty = padAttribute(returnWhenEmpty,
456                        InstanceManager.getDefault(LocationManager.class).getMaxLocationAndTrackNameLength() +
457                                3);
458            }
459            if (printCarRWL.isSelected()) {
460                if (car.getReturnWhenLoadedDestination() != null) {
461                    returnWhenLoaded = car.getReturnWhenLoadedDestinationName().trim() +
462                            " - " +
463                            car.getReturnWhenLoadedDestTrackName().trim();
464                }
465                returnWhenLoaded = padAttribute(returnWhenLoaded,
466                        InstanceManager.getDefault(LocationManager.class).getMaxLocationAndTrackNameLength() +
467                                3);
468            }
469            if (printDivision.isSelected()) {
470                division = padAttribute(car.getDivisionName(), Bundle.getMessage("HomeDivision").length());
471            }
472            if (printCarStatus.isSelected()) {
473                status = padAttribute(car.getStatus(), Bundle.getMessage("Status").length());
474            }
475            // comment gets trimmed by line length
476            if (printCarComment.isSelected()) {
477                comment = car.getComment().trim();
478            }
479
480            String s = number +
481                    road +
482                    type +
483                    length +
484                    weight +
485                    color +
486                    load +
487                    kernel +
488                    owner +
489                    built +
490                    last +
491                    wait +
492                    schedule +
493                    value +
494                    rfid +
495                    location +
496                    train +
497                    destination +
498                    finalDestination +
499                    returnWhenEmpty +
500                    returnWhenLoaded +
501                    division +
502                    status +
503                    comment;
504
505            if (s.length() > numberCharPerLine) {
506                s = s.substring(0, numberCharPerLine);
507            }
508            writer.write(s + NEW_LINE);
509        }
510    }
511
512    private String padAttribute(String attribute, int length) {
513        return TrainCommon.padAndTruncate(attribute, length) + TrainCommon.SPACE;
514    }
515
516    private final static Logger log = LoggerFactory.getLogger(PrintCarRosterFrame.class);
517}