001package jmri.jmrit.operations.trains; 002 003import java.awt.*; 004import java.awt.JobAttributes.SidesType; 005import java.io.*; 006import java.nio.charset.StandardCharsets; 007import java.util.ArrayList; 008import java.util.List; 009 010import javax.swing.ImageIcon; 011import javax.swing.JLabel; 012 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016import jmri.jmrit.operations.setup.Setup; 017import jmri.jmrit.operations.trains.trainbuilder.TrainCommon; 018import jmri.util.davidflanagan.HardcopyWriter; 019 020/** 021 * Used for train Manifests and switch lists. 022 * 023 * @author Daniel Boudreau (C) 2025 024 */ 025public class TrainPrintManifest extends TrainCommon { 026 027 static final char SPACE = ' '; 028 029 /** 030 * Print or preview a train Manifest or switch list. 031 * 032 * @param file File to be printed or previewed 033 * @param name Title of document 034 * @param isPreview true if preview 035 * @param fontName optional font to use when printing document 036 * @param logoURL optional pathname for logo 037 * @param printerName optional default printer name 038 * @param orientation Setup.LANDSCAPE, Setup.PORTRAIT, or Setup.HANDHELD 039 * @param fontSize font size 040 * @param isPrintHeader when true print page header 041 * @param sidesType two sides long or short can be null 042 */ 043 public static void printReport(File file, String name, boolean isPreview, String fontName, String logoURL, 044 String printerName, String orientation, int fontSize, boolean isPrintHeader, SidesType sidesType) { 045 // obtain a HardcopyWriter to do this 046 047 boolean isLandScape = false; 048 double margin = .5; 049 Dimension pagesize = null; // HardcopyWritter provides default page 050 // sizes for portrait and landscape 051 if (orientation.equals(Setup.LANDSCAPE)) { 052 margin = .65; 053 isLandScape = true; 054 } 055 if (orientation.equals(Setup.HANDHELD) || orientation.equals(Setup.HALFPAGE)) { 056 isPrintHeader = false; 057 // add margins to page size 058 pagesize = new Dimension(getPageSize(orientation).width + PAPER_MARGINS.width, 059 getPageSize(orientation).height + PAPER_MARGINS.height); 060 } 061 try (HardcopyWriter writer = new HardcopyWriter(new Frame(), name, fontSize, margin, 062 margin, .5, .5, isPreview, printerName, isLandScape, isPrintHeader, sidesType, pagesize); 063 BufferedReader in = new BufferedReader(new InputStreamReader( 064 new FileInputStream(file), StandardCharsets.UTF_8));) { 065 066 // set font 067 if (!fontName.isEmpty()) { 068 writer.setFontName(fontName); 069 } 070 071 if (logoURL != null && !logoURL.equals(Setup.NONE)) { 072 ImageIcon icon = new ImageIcon(logoURL); 073 if (icon.getIconWidth() == -1) { 074 log.error("Logo not found: {}", logoURL); 075 } else { 076 writer.write(icon.getImage(), new JLabel(icon)); 077 } 078 } 079 080 List<String> lines = new ArrayList<>(); 081 String line; 082 while (true) { 083 line = in.readLine(); 084 if (line == null) { 085 if (isPreview) { 086 // need to do this in case the input file was empty to create preview 087 writer.write(" "); 088 } 089 break; 090 } 091 lines.add(line); 092 if (line.isBlank()) { 093 print(writer, lines, false); 094 } 095 } 096 print(writer, lines, true); 097 } catch (FileNotFoundException e) { 098 log.error("Build file doesn't exist", e); 099 } catch (HardcopyWriter.PrintCanceledException ex) { 100 log.debug("Print canceled"); 101 } catch (IOException e) { 102 log.warn("Exception printing: {}", e.getLocalizedMessage()); 103 } 104 } 105 106 private static void print(HardcopyWriter writer, List<String> lines, boolean lastBlock) throws IOException { 107 if (Setup.isPrintNoPageBreaksEnabled() && 108 writer.getCurrentLineNumber() != 0 && 109 writer.getLinesPerPage() - writer.getCurrentLineNumber() + 1 < lines.size()) { 110 writer.pageBreak(); 111 } 112 // check for exact page break 113 if (writer.getLinesPerPage() - writer.getCurrentLineNumber() + 1 == lines.size()) { 114 // eliminate blank line after page break 115 String s = lines.get(lines.size() -1); 116 if (s.isBlank()) { 117 lines.remove(lines.size() - 1); 118 } 119 } 120 121 Color color = null; 122 boolean printingColor = false; 123 for (String line : lines) { 124 // determine if there's a line separator 125 if (printHorizontialLineSeparator(writer, line)) { 126 color = null; 127 continue; 128 } 129 // color text? 130 if (line.contains(TEXT_COLOR_START)) { 131 color = getTextColor(line); 132 if (line.contains(TEXT_COLOR_END)) { 133 printingColor = false; 134 } else { 135 // printing multiple lines in color 136 printingColor = true; 137 } 138 // could be a color change when using two column format 139 if (line.contains(Character.toString(VERTICAL_LINE_CHAR))) { 140 String s = line.substring(0, line.indexOf(VERTICAL_LINE_CHAR)); 141 s = getTextColorString(s); 142 writer.write(color, s); // 1st half of line printed 143 // get the new color and text 144 line = line.substring(line.indexOf(VERTICAL_LINE_CHAR)); 145 color = getTextColor(line); 146 // pad out string 147 line = tabString(getTextColorString(line), s.length()); 148 } else { 149 // simple case only one color 150 line = getTextColorString(line); 151 } 152 } else if (line.contains(TEXT_COLOR_END)) { 153 printingColor = false; 154 line = getTextColorString(line); 155 } else if (!printingColor) { 156 color = null; 157 } 158 159 printVerticalLineSeparator(writer, line); 160 line = line.replace(VERTICAL_LINE_CHAR, SPACE); 161 162 if (color != null) { 163 writer.write(color, line + NEW_LINE); 164 continue; 165 } 166 writer.write(line); 167 // no line feed if last line of file, eliminates blank page 168 if (!lastBlock || 169 writer.getCurrentLineNumber() < writer.getLinesPerPage() - 1) { 170 writer.write(NEW_LINE); 171 } 172 } 173 lines.clear(); 174 } 175 176 /* 177 * Returns true if horizontal line was printed, or line length = 0 178 */ 179 private static boolean printHorizontialLineSeparator(HardcopyWriter writer, String line) { 180 boolean horizontialLineSeparatorFound = true; 181 if (line.length() > 0) { 182 for (int i = 0; i < line.length(); i++) { 183 if (line.charAt(i) != HORIZONTAL_LINE_CHAR) { 184 horizontialLineSeparatorFound = false; 185 break; 186 } 187 } 188 if (horizontialLineSeparatorFound) { 189 writer.write(writer.getCurrentLineNumber(), 0, writer.getCurrentLineNumber(), 190 line.length() + 1); 191 } 192 } 193 return horizontialLineSeparatorFound; 194 } 195 196 private static void printVerticalLineSeparator(HardcopyWriter writer, String line) { 197 for (int i = 0; i < line.length(); i++) { 198 if (line.charAt(i) == VERTICAL_LINE_CHAR) { 199 // make a frame (two column format) 200 if (Setup.isTabEnabled()) { 201 writer.write(writer.getCurrentLineNumber(), 0, writer.getCurrentLineNumber() + 1, 0); 202 writer.write(writer.getCurrentLineNumber(), line.length() + 1, 203 writer.getCurrentLineNumber() + 1, line.length() + 1); 204 } 205 writer.write(writer.getCurrentLineNumber(), i + 1, writer.getCurrentLineNumber() + 1, 206 i + 1); 207 } 208 } 209 } 210 211 private final static Logger log = LoggerFactory.getLogger(TrainPrintManifest.class); 212}