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