001package jmri.jmrit.operations.trains.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.routes.Route;
017import jmri.jmrit.operations.routes.RouteLocation;
018import jmri.jmrit.operations.setup.Control;
019import jmri.jmrit.operations.setup.Setup;
020import jmri.jmrit.operations.trains.Train;
021import jmri.jmrit.operations.trains.TrainManager;
022import jmri.jmrit.operations.trains.gui.TrainsTableFrame;
023import jmri.jmrit.operations.trains.gui.TrainsTableModel;
024import jmri.jmrit.operations.trains.trainbuilder.TrainCommon;
025import jmri.util.davidflanagan.HardcopyWriter;
026
027/**
028 * Prints a summary of a train or trains. The trains list is controlled by the
029 * "Show All" checkbox and the "Build" checkboxes in the TrainsTableFrame.
030 * <p>
031 * This uses the older style printing, for compatibility with Java 1.1.8 in
032 * Macintosh MRJ
033 *
034 * @author Bob Jacobsen Copyright (C) 2003
035 * @author Dennis Miller Copyright (C) 2005
036 * @author Daniel Boudreau Copyright (C) 2009, 2023
037 */
038public class PrintTrainsFrame extends OperationsFrame {
039
040    static final String TAB = "\t"; // NOI18N
041    static final char FORM_FEED = '\f'; // NOI18N
042
043    public static final int MAX_NAME_LENGTH = Control.max_len_string_train_name - 10;
044
045    boolean _isPreview;
046    Train _train;
047    TrainsTableFrame _trainsTableFrame;
048
049    JComboBox<String> sortByComboBox = new JComboBox<>();
050    JComboBox<String> manifestOrientationComboBox = new JComboBox<>();
051    JComboBox<Integer> fontSizeComboBox = new JComboBox<>();
052
053    JCheckBox printSummary = new JCheckBox(Bundle.getMessage("PrintSummary"));
054    JCheckBox printDetails = new JCheckBox(Bundle.getMessage("PrintDetails"));
055    JButton okayButton = new JButton(Bundle.getMessage("ButtonOK"));
056
057    public PrintTrainsFrame(boolean isPreview, Train train) {
058        _isPreview = isPreview;
059        _train = train;
060        printTrain();
061    }
062
063    public PrintTrainsFrame(boolean isPreview, TrainsTableFrame trainsTableFrame) {
064        _isPreview = isPreview;
065        _trainsTableFrame = trainsTableFrame;
066
067        // create panel
068        JPanel pSortBy = new JPanel();
069        pSortBy.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SortBy")));
070        pSortBy.add(sortByComboBox);
071
072        loadSortByComboBox(sortByComboBox);
073        addComboBoxAction(sortByComboBox);
074
075        JPanel pOrientation = new JPanel();
076        pOrientation.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOrientation")));
077        pOrientation.add(manifestOrientationComboBox);
078
079        manifestOrientationComboBox.addItem(Setup.PORTRAIT);
080        manifestOrientationComboBox.addItem(Setup.LANDSCAPE);
081        //        manifestOrientationComboBox.setSelectedItem(Setup.LANDSCAPE);
082
083        JPanel pFontSize = new JPanel();
084        pFontSize.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutFontSize")));
085        pFontSize.add(fontSizeComboBox);
086
087        OperationsPanel.loadFontSizeComboBox(fontSizeComboBox);
088        fontSizeComboBox.setSelectedItem(Control.reportFontSize);
089
090        // create panel
091        JPanel pPanel = new JPanel();
092        pPanel.setLayout(new GridBagLayout());
093        pPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("PrintOptions")));
094        addItemLeft(pPanel, printSummary, 0, 0);
095        addItemLeft(pPanel, printDetails, 0, 1);
096
097        printSummary.setSelected(true);
098        printDetails.setSelected(true);
099
100        // add tool tips
101        JPanel pButtons = new JPanel();
102        pButtons.setLayout(new GridBagLayout());
103        pButtons.add(okayButton);
104        addButtonAction(okayButton);
105
106        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
107        getContentPane().add(pSortBy);
108        getContentPane().add(pOrientation);
109        getContentPane().add(pFontSize);
110        getContentPane().add(pPanel);
111        getContentPane().add(pButtons);
112        setPreferredSize(null);
113        if (_isPreview) {
114            setTitle(Bundle.getMessage("MenuItemPreview"));
115        } else {
116            setTitle(Bundle.getMessage("MenuItemPrint"));
117        }
118        initMinimumSize(new Dimension(Control.panelWidth300, Control.panelHeight250));
119    }
120
121    @Override
122    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
123        setVisible(false);
124        printTrains();
125    }
126
127    private void printTrains() {
128        if (!printSummary.isSelected() && !printDetails.isSelected()) {
129            return;
130        }
131
132        // obtain a HardcopyWriter to do this
133        boolean isLandscape = false;
134        if (manifestOrientationComboBox.getSelectedItem() != null &&
135                manifestOrientationComboBox.getSelectedItem().equals(Setup.LANDSCAPE)) {
136            isLandscape = true;
137        }
138
139        int fontSize = (int) fontSizeComboBox.getSelectedItem();
140        try (HardcopyWriter writer = new HardcopyWriter(new Frame(), Bundle.getMessage("TitleTrainsTable"),
141                fontSize, .5, .5, .5, .5, _isPreview, "", isLandscape, true, null, null);) {
142
143            List<Train> trains = _trainsTableFrame.getSortByList((String) sortByComboBox.getSelectedItem());
144
145            if (printSummary.isSelected()) {
146                printSummaryTrains(writer, trains, _trainsTableFrame);
147                if (printDetails.isSelected()) {
148                    writer.write(FORM_FEED); // new page
149                }
150            }
151
152            if (printDetails.isSelected()) {
153                // now do the details for each train
154                for (Train train : trains) {
155                    if ((train.isBuildEnabled() || _trainsTableFrame.showAllBox.isSelected()) &&
156                            train.getRoute() != null) {
157                        List<RouteLocation> route = train.getRoute().getLocationsBySequenceList();
158                        // determine if another detailed summary can fit on the same page
159                        if (writer.getLinesPerPage() - writer.getCurrentLineNumber() < route.size() +
160                                getNumberOfLines(writer, Bundle.getMessage("Comment") + ": " + train.getComment()) +
161                                NUMBER_OF_HEADER_LINES) {
162                            writer.write(FORM_FEED);
163                        } else if (writer.getCurrentLineNumber() > 0) {
164                            writer.write(NEW_LINE);
165                        }
166                        printTrain(writer, train);
167                    }
168                }
169            }
170        } catch (HardcopyWriter.PrintCanceledException ex) {
171            log.debug("Print canceled");
172        } catch (IOException e1) {
173            log.error("Exception in print train details: {}", e1.getLocalizedMessage());
174        }
175    }
176
177    private void printSummaryTrains(HardcopyWriter writer, List<Train> trains, TrainsTableFrame trainsTableFrame)
178            throws IOException {
179        int maxLineLength = writer.getCharactersPerLine() - 1;
180        int maxTrainNameLength = InstanceManager.getDefault(TrainManager.class).getMaxTrainNameLength();
181        int maxLocationNameLength = InstanceManager.getDefault(LocationManager.class).getMaxLocationNameLength();
182        String s = Bundle.getMessage("Time") +
183                "  " +
184                truncate(Bundle.getMessage("Name"), maxTrainNameLength) +
185                truncate(Bundle.getMessage("Description")) +
186                truncate(Bundle.getMessage("Route")) +
187                truncate(Bundle.getMessage("Departs"), maxLocationNameLength) +
188                truncate(Bundle.getMessage("Terminates"), maxLocationNameLength);
189        writer.write(truncate(s, maxLineLength) + NEW_LINE);
190        for (Train train : trains) {
191            if (train.isBuildEnabled() || trainsTableFrame.showAllBox.isSelected()) {
192                String name = truncate(train.getName(), maxTrainNameLength);
193                String desc = truncate(train.getDescription());
194                String route = truncate(train.getTrainRouteName());
195                String departs = truncate(train.getTrainDepartsName(), maxLocationNameLength);
196                String terminates = truncate(train.getTrainTerminatesName(), maxLocationNameLength);
197
198                s = train.getDepartureTime() +
199                        " " +
200                        name +
201                        desc +
202                        route +
203                        departs +
204                        terminates;
205                writer.write(truncate(s, maxLineLength) + NEW_LINE);
206            }
207        }
208    }
209
210    private String truncate(String string) {
211        return truncate(string, MAX_NAME_LENGTH);
212    }
213
214    private String truncate(String string, int length) {
215        return TrainCommon.padAndTruncate(string, length) + TrainCommon.SPACE;
216    }
217
218    private void printTrain() {
219        if (_train == null) {
220            return;
221        }
222        // obtain a HardcopyWriter to do this
223        try (HardcopyWriter writer = new HardcopyWriter(new Frame(), Bundle.getMessage("TitleTrain", _train.getName()),
224                Control.reportFontSize, .5, .5, .5, .5, _isPreview)) {
225
226            printTrain(writer, _train);
227        } catch (HardcopyWriter.PrintCanceledException ex) {
228            log.debug("Print canceled");
229        } catch (IOException ex) {
230            log.error("Exception in print train: {}", ex.getLocalizedMessage());
231        }
232    }
233
234    // 7 lines of header plus NEW_LINE at start
235    private static final int NUMBER_OF_HEADER_LINES = 8;
236
237    private void printTrain(HardcopyWriter writer, Train train) throws IOException {
238        String s = Bundle.getMessage("Name") + ": " + train.getName() + NEW_LINE;
239        writer.write(s);
240        s = Bundle.getMessage("Description") + ": " + train.getDescription() + NEW_LINE;
241        writer.write(s);
242        s = Bundle.getMessage("Departs") + ": " + train.getTrainDepartsName() + NEW_LINE;
243        writer.write(s);
244        s = Bundle.getMessage("DepartTime") + ": " + train.getDepartureTime() + NEW_LINE;
245        writer.write(s);
246        s = Bundle.getMessage("Terminates") + ": " + train.getTrainTerminatesName() + NEW_LINE;
247        writer.write(s);
248
249        writer.write(NEW_LINE);
250
251        s = Bundle.getMessage("Route") + ": " + train.getTrainRouteName() + NEW_LINE;
252        writer.write(s);
253        Route route = train.getRoute();
254        if (route != null) {
255            for (RouteLocation rl : route.getLocationsBySequenceList()) {
256                s = TAB + rl.getName() + NEW_LINE;
257                writer.write(s);
258            }
259        }
260        if (!train.getComment().equals(Train.NONE)) {
261            s = Bundle.getMessage("Comment") + ": " + train.getComment() + NEW_LINE;
262            writer.write(s);
263        }
264    }
265
266    private void loadSortByComboBox(JComboBox<String> box) {
267        box.addItem(TrainsTableModel.IDCOLUMNNAME);
268        box.addItem(TrainsTableModel.TIMECOLUMNNAME);
269        box.addItem(TrainsTableModel.NAMECOLUMNNAME);
270        box.addItem(TrainsTableModel.DESCRIPTIONCOLUMNNAME);
271        box.addItem(TrainsTableModel.ROUTECOLUMNNAME);
272        box.addItem(TrainsTableModel.DEPARTSCOLUMNNAME);
273        box.addItem(TrainsTableModel.TERMINATESCOLUMNNAME);
274        box.addItem(TrainsTableModel.STATUSCOLUMNNAME);
275
276        box.setSelectedItem(_trainsTableFrame.getSortBy());
277    }
278
279    private int getNumberOfLines(HardcopyWriter writer, String string) {
280        String[] lines = string.split(NEW_LINE);
281        int count = lines.length;
282        // any long lines that exceed the page width?
283        for (String line : lines) {
284            int add = line.length() / writer.getCharactersPerLine();
285            count = count + add;
286        }
287        return count;
288    }
289
290    private final static Logger log = LoggerFactory.getLogger(PrintTrainsFrame.class);
291}