001package jmri.jmrit.roster;
002
003import java.awt.Frame;
004import java.awt.event.ActionEvent;
005import java.io.IOException;
006import java.util.Arrays;
007import java.util.List;
008import javax.swing.ImageIcon;
009import javax.swing.JLabel;
010import jmri.beans.BeanUtil;
011import jmri.jmrit.roster.rostergroup.RosterGroupSelector;
012import jmri.jmrit.roster.swing.RosterFrame;
013import jmri.util.FileUtil;
014import jmri.util.StringUtil;
015import jmri.util.davidflanagan.HardcopyWriter;
016import org.slf4j.Logger;
017import org.slf4j.LoggerFactory;
018
019/**
020 * Action to print a very compact summary listing of the Roster contents.
021 * <p>
022 * This uses the older style printing, for compatibility with Java 1.1.8 in
023 * Macintosh MRJ
024 *
025 * @author Bob Jacobsen Copyright (C) 2003
026 * @author Dennis Miller Copyright (C) 2005
027 * @author Egbert Broerse Copyright (C) 2018
028 */
029public class PrintListAction extends jmri.util.swing.JmriAbstractAction {
030
031    public PrintListAction(String s, jmri.util.swing.WindowInterface wi) {
032        super(s, wi);
033        isPreview = true;
034    }
035
036    public PrintListAction(String s, javax.swing.Icon i, jmri.util.swing.WindowInterface wi) {
037        super(s, i, wi);
038        isPreview = true;
039    }
040
041    public PrintListAction(String actionName, Frame frame, boolean preview) {
042        super(actionName);
043        mFrame = frame;
044        isPreview = preview;
045    }
046
047    public void setPreview(boolean preview) {
048        isPreview = preview;
049    }
050
051    /**
052     * Frame hosting the printing.
053     */
054    Frame mFrame = new Frame();
055
056    /**
057     * Variable to set whether this is to be printed or previewed.
058     */
059    boolean isPreview;
060
061    @Override
062    public void actionPerformed(ActionEvent e) {
063        // obtain a HardcopyWriter to do this
064        Roster r = Roster.getDefault();
065        String title = Bundle.getMessage("TitleDecoderProRoster");
066        String rosterGroup = r.getDefaultRosterGroup();
067        // rosterGroup may legitimately be null
068        // but getProperty returns null if the property cannot be found, so
069        // we test that the property exists before attempting to get its value
070        if (BeanUtil.hasProperty(wi, RosterGroupSelector.SELECTED_ROSTER_GROUP)) {
071            rosterGroup = (String) BeanUtil.getProperty(wi, RosterGroupSelector.SELECTED_ROSTER_GROUP);
072        }
073        if (rosterGroup == null) {
074            title = title + " " + Bundle.getMessage("ALLENTRIES");
075        } else {
076            title = title + " " + Bundle.getMessage("TitleGroup") + " " + Bundle.getMessage("TitleEntries", rosterGroup);
077        }
078        try ( HardcopyWriter writer = new HardcopyWriter(mFrame, title, 10, .5, .5, .5, .5, isPreview); ) {
079
080            // add the image
081            ImageIcon icon = new ImageIcon(FileUtil.findURL("resources/decoderpro.gif", FileUtil.Location.INSTALLED));
082            // we use an ImageIcon because it's guaranteed to have been loaded when ctor is complete
083            writer.write(icon.getImage(), new JLabel(icon));
084            // add a number of blank lines, so that the roster entry starts below the decoderpro logo
085            int height = icon.getImage().getHeight(null);
086            int blanks = (height - writer.getLineAscent()) / writer.getLineHeight();
087
088            try {
089                for (int i = 0; i < blanks; i++) {
090                    String s = "\n";
091                    writer.write(s, 0, s.length());
092                }
093            } catch (IOException ex) {
094                log.warn("error during printing", ex);
095            }
096
097            // Loop through the Roster, printing a 1 line list entry as needed
098            List<RosterEntry> l;
099
100            if ( BeanUtil.hasProperty(wi, "allRosterEntries")) {
101                l = Arrays.asList(((RosterFrame)wi).getAllRosterEntries());
102            } else {
103                l = r.matchingList(null, null, null, null, null, null, null); // take all
104            }
105            log.debug("Roster list size: {}", l.size());
106
107            // print table column headers, match column order + widths with RosterEntry#PrintEntryLine
108            // fields copied from RosterTableModel#getColumnName(int)
109            String headerText = "";
110            // IDCOL (= Filename)
111            headerText += StringUtil.padString(Bundle.getMessage("FieldID"), 15);
112            // ADDRESSCOL:
113            headerText += StringUtil.padString(Bundle.getMessage("FieldDCCAddress"), 6);
114            // ROADNAMECOL:
115            headerText += StringUtil.padString(Bundle.getMessage("FieldRoadName"), 6);
116            // ROADNUMBERCOL:
117            headerText += StringUtil.padString(Bundle.getMessage("FieldRoadNumber"), 6);
118            // MFGCOL:
119            headerText += StringUtil.padString(Bundle.getMessage("FieldManufacturer"), 6);
120            // MODELCOL:
121            headerText += StringUtil.padString(Bundle.getMessage("FieldModel"), 10);
122            // DECODERCOL:
123            headerText += StringUtil.padString(Bundle.getMessage("FieldDecoderModel"), 10);
124            // PROTOCOL:
125            headerText += StringUtil.padString(Bundle.getMessage("FieldProtocol"), 12);
126            // OWNERCOL:
127            headerText += StringUtil.padString(Bundle.getMessage("FieldOwner"), 6);
128            // DATEUPDATECOL:
129            headerText += StringUtil.padString(Bundle.getMessage("FieldDateUpdated"), 10);
130
131            try {
132                // start a new line
133                writer.write("\n", 0, 1);
134                writer.write(headerText);
135            } catch (IOException ex) {
136                log.warn("error during printing", ex);
137            }
138
139            for (RosterEntry re : l) {
140                if (rosterGroup != null) {
141                    if (re.getAttribute(Roster.getRosterGroupProperty(rosterGroup)) != null
142                            && re.getAttribute(Roster.getRosterGroupProperty(rosterGroup)).equals("yes")) {
143                        re.printEntryLine(writer);
144                    }
145                } else {
146                    re.printEntryLine(writer);
147                }
148            }
149
150            // and force completion of the printing
151            // writer.close(); not needed when using try / catch
152        } catch (HardcopyWriter.PrintCanceledException ex) {
153            log.debug("Print cancelled");
154        }
155    }
156
157    // never invoked, because we overrode actionPerformed above
158    @Override
159    public jmri.util.swing.JmriPanel makePanel() {
160        throw new IllegalArgumentException("Should not be invoked");
161    }
162
163    @Override
164    public void setParameter(String parameter, String value) {
165        parameter = parameter.toLowerCase();
166        value = value.toLowerCase();
167        if (parameter.equals("ispreview")) {
168            isPreview = value.equals("true");
169        }
170    }
171
172    private final static Logger log = LoggerFactory.getLogger(PrintListAction.class);
173
174}