001package jmri.jmrit.roster; 002 003import java.awt.Font; 004import java.awt.Frame; 005import java.awt.event.ActionEvent; 006import java.awt.geom.Rectangle2D; 007import java.io.IOException; 008import java.util.ArrayList; 009import java.util.Arrays; 010import java.util.List; 011import jmri.beans.BeanUtil; 012import jmri.jmrit.roster.rostergroup.RosterGroupSelector; 013import jmri.jmrit.roster.swing.RosterFrame; 014import jmri.util.davidflanagan.HardcopyWriter; 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018/** 019 * Action to print a very compact summary listing of the Roster contents. 020 * <p> 021 * This uses the older style printing, for compatibility with Java 1.1.8 in 022 * Macintosh MRJ 023 * 024 * @author Bob Jacobsen Copyright (C) 2003 025 * @author Dennis Miller Copyright (C) 2005 026 * @author Egbert Broerse Copyright (C) 2018 027 */ 028public class PrintListAction extends jmri.util.swing.JmriAbstractAction { 029 030 public PrintListAction(String s, jmri.util.swing.WindowInterface wi) { 031 super(s, wi); 032 isPreview = true; 033 } 034 035 public PrintListAction(String s, javax.swing.Icon i, jmri.util.swing.WindowInterface wi) { 036 super(s, i, wi); 037 isPreview = true; 038 } 039 040 public PrintListAction(String actionName, Frame frame, boolean preview) { 041 super(actionName); 042 mFrame = frame; 043 isPreview = preview; 044 } 045 046 public void setPreview(boolean preview) { 047 isPreview = preview; 048 } 049 050 /** 051 * Frame hosting the printing. 052 */ 053 Frame mFrame = new Frame(); 054 055 /** 056 * Variable to set whether this is to be printed or previewed. 057 */ 058 boolean isPreview; 059 060 @Override 061 public void actionPerformed(ActionEvent e) { 062 // obtain a HardcopyWriter to do this 063 Roster r = Roster.getDefault(); 064 String title = Bundle.getMessage("TitleDecoderProRoster"); 065 String rosterGroup = r.getDefaultRosterGroup(); 066 // rosterGroup may legitimately be null 067 // but getProperty returns null if the property cannot be found, so 068 // we test that the property exists before attempting to get its value 069 if (BeanUtil.hasProperty(wi, RosterGroupSelector.SELECTED_ROSTER_GROUP)) { 070 rosterGroup = (String) BeanUtil.getProperty(wi, RosterGroupSelector.SELECTED_ROSTER_GROUP); 071 } 072 if (rosterGroup == null) { 073 title = title + " " + Bundle.getMessage("ALLENTRIES"); 074 } else { 075 title = title + 076 " " + 077 Bundle.getMessage("TitleGroup") + 078 " " + 079 Bundle.getMessage("TitleEntries", rosterGroup); 080 } 081 try (HardcopyWriter writer = new HardcopyWriter(mFrame, title, "SansSerif", null, 9, 082 .5 * 72, .5 * 72, .5 * 72, .5 * 72, isPreview, null, null, null, null, null);) { 083 084 // add the icon 085 writer.writeDecoderProIcon(); 086 087 // Loop through the Roster, printing a 1 line list entry as needed 088 List<RosterEntry> l; 089 090 if (BeanUtil.hasProperty(wi, "allRosterEntries")) { 091 l = Arrays.asList(((RosterFrame) wi).getAllRosterEntries()); 092 } else { 093 l = r.matchingList(null, null, null, null, null, null, null); // take all 094 } 095 log.debug("Roster list size: {}", l.size()); 096 097 // print table column headers, match column order + widths with RosterEntry#PrintEntryLine 098 // fields copied from RosterTableModel#getColumnName(int) 099 List<HardcopyWriter.Column> columns = new ArrayList<>(); 100 columns.add(new HardcopyWriter.Column(0, 15, HardcopyWriter.Align.LEFT)); // ID 101 columns.add(new HardcopyWriter.Column(0, 5, HardcopyWriter.Align.RIGHT)); // DCC Address 102 columns.add(new HardcopyWriter.Column(0, 7, HardcopyWriter.Align.LEFT)); // Road name 103 columns.add(new HardcopyWriter.Column(0, 6, HardcopyWriter.Align.LEFT)); // Road number 104 columns.add(new HardcopyWriter.Column(0, 6, HardcopyWriter.Align.LEFT)); // Manufacturer 105 columns.add(new HardcopyWriter.Column(0, 10, HardcopyWriter.Align.LEFT)); // Model 106 columns.add(new HardcopyWriter.Column(0, 10, HardcopyWriter.Align.LEFT)); // Decoder model 107 columns.add(new HardcopyWriter.Column(0, 12, HardcopyWriter.Align.LEFT)); // Protocol 108 columns.add(new HardcopyWriter.Column(0, 6, HardcopyWriter.Align.LEFT)); // Owner 109 columns.add(new HardcopyWriter.Column(0, 10, HardcopyWriter.Align.LEFT)); // Date updated 110 111 columns = HardcopyWriter.Column.stretchColumns(columns, 112 (int) writer.getPrintablePagesizePoints().getWidth(), 113 writer.getFontSize() / 2); 114 115 // If the paper is very wide, we may need to reduce the width of some columns 116 // so to make the other columns a bit larger 117 List<String> dccAddress = new ArrayList<>(); 118 List<String> protocols = new ArrayList<>(); 119 for (RosterEntry re : l) { 120 dccAddress.add(re.getDccAddress()); 121 protocols.add(re.getProtocol().toString()); 122 } 123 124 Rectangle2D dccAddressBounds = writer.measure(dccAddress); 125 Rectangle2D protocolsBounds = writer.measure(protocols); 126 127 boolean changed = false; 128 129 if (Math.ceil(dccAddressBounds.getWidth()) < columns.get(1).getWidth()) { 130 columns.get(1).setWidth((int) Math.ceil(dccAddressBounds.getWidth())); 131 changed = true; 132 } 133 if (Math.ceil(protocolsBounds.getWidth()) < columns.get(7).getWidth()) { 134 columns.get(7).setWidth((int) Math.ceil(protocolsBounds.getWidth())); 135 changed = true; 136 } 137 138 if (changed) { 139 columns = HardcopyWriter.Column.stretchColumns(columns, 140 (int) writer.getPrintablePagesizePoints().getWidth(), 141 writer.getFontSize() / 2); 142 } 143 144 writer.setColumns(columns); 145 String headerText = ""; 146 // IDCOL (= Filename) 147 headerText += Bundle.getMessage("FieldID") + "\t"; 148 // ADDRESSCOL: 149 headerText += Bundle.getMessage("FieldDCCAddress") + "\t"; 150 // ROADNAMECOL: 151 headerText += Bundle.getMessage("FieldRoadName") + "\t"; 152 // ROADNUMBERCOL: 153 headerText += Bundle.getMessage("FieldRoadNumber") + "\t"; 154 // MFGCOL: 155 headerText += Bundle.getMessage("FieldManufacturer") + "\t"; 156 // MODELCOL: 157 headerText += Bundle.getMessage("FieldModel") + "\t"; 158 // DECODERCOL: 159 headerText += Bundle.getMessage("FieldDecoderModel") + "\t"; 160 // PROTOCOL: 161 headerText += Bundle.getMessage("FieldProtocol") + "\t"; 162 // OWNERCOL: 163 headerText += Bundle.getMessage("FieldOwner") + "\t"; 164 // DATEUPDATECOL: 165 headerText += Bundle.getMessage("FieldDateUpdated") + "\n"; 166 167 int currentPageNumber = -1; 168 169 for (RosterEntry re : l) { 170 if (currentPageNumber != writer.getPageNum()) { 171 currentPageNumber = writer.getPageNum(); 172 try { 173 // start a new line 174 writer.write("\n", 0, 1); 175 writer.setFont(null, Font.BOLD, null); 176 writer.write(headerText); 177 writer.setFont(null, Font.PLAIN, null); 178 writer.leaveVerticalSpace(writer.getLineHeight()/2); 179 } catch (IOException ex) { 180 log.warn("error during printing", ex); 181 } 182 } 183 if (rosterGroup != null) { 184 if (re.getAttribute(Roster.getRosterGroupProperty(rosterGroup)) != null && 185 re.getAttribute(Roster.getRosterGroupProperty(rosterGroup)).equals("yes")) { 186 re.printEntryLine(writer); 187 } 188 } else { 189 re.printEntryLine(writer); 190 } 191 } 192 193 // and force completion of the printing 194 // writer.close(); not needed when using try / catch 195 } catch (HardcopyWriter.PrintCanceledException ex) { 196 log.debug("Print cancelled"); 197 } 198 } 199 200 // never invoked, because we overrode actionPerformed above 201 @Override 202 public jmri.util.swing.JmriPanel makePanel() { 203 throw new IllegalArgumentException("Should not be invoked"); 204 } 205 206 @Override 207 public void setParameter(String parameter, String value) { 208 parameter = parameter.toLowerCase(); 209 value = value.toLowerCase(); 210 if (parameter.equals("ispreview")) { 211 isPreview = value.equals("true"); 212 } 213 } 214 215 private final static Logger log = LoggerFactory.getLogger(PrintListAction.class); 216 217}