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() < lines.size() - 1) { 110 writer.pageBreak(); 111 } 112 // check for normal page break 113 if (writer.getCurrentLineNumber() != 0 && 114 writer.getLinesPerPage() - writer.getCurrentLineNumber() < lines.size()) { 115 // eliminate blank line after normal page break 116 String s = lines.get(lines.size() -1); 117 if (s.isBlank()) { 118 lines.remove(lines.size() - 1); 119 } 120 } 121 122 Color color = null; 123 boolean printingColor = false; 124 for (String line : lines) { 125 // determine if there's a line separator 126 if (printHorizontialLineSeparator(writer, line)) { 127 color = null; 128 continue; 129 } 130 // color text? 131 if (line.contains(TEXT_COLOR_START)) { 132 color = getTextColor(line); 133 if (line.contains(TEXT_COLOR_END)) { 134 printingColor = false; 135 } else { 136 // printing multiple lines in color 137 printingColor = true; 138 } 139 // could be a color change when using two column format 140 if (line.contains(Character.toString(VERTICAL_LINE_CHAR))) { 141 String s = line.substring(0, line.indexOf(VERTICAL_LINE_CHAR)); 142 s = getTextColorString(s); 143 writer.write(color, s); // 1st half of line printed 144 // get the new color and text 145 line = line.substring(line.indexOf(VERTICAL_LINE_CHAR)); 146 color = getTextColor(line); 147 // pad out string 148 line = tabString(getTextColorString(line), s.length()); 149 } else { 150 // simple case only one color 151 line = getTextColorString(line); 152 } 153 } else if (line.contains(TEXT_COLOR_END)) { 154 printingColor = false; 155 line = getTextColorString(line); 156 } else if (!printingColor) { 157 color = null; 158 } 159 160 printVerticalLineSeparator(writer, line); 161 line = line.replace(VERTICAL_LINE_CHAR, SPACE); 162 163 if (color != null) { 164 writer.write(color, line + NEW_LINE); 165 continue; 166 } 167 writer.write(line); 168 // no line feed if last line of file, eliminates blank page 169 if (!lastBlock || 170 writer.getCurrentLineNumber() < writer.getLinesPerPage() - 1) { 171 writer.write(NEW_LINE); 172 } 173 } 174 lines.clear(); 175 } 176 177 /* 178 * Returns true if horizontal line was printed, or line length = 0 179 */ 180 private static boolean printHorizontialLineSeparator(HardcopyWriter writer, String line) { 181 boolean horizontialLineSeparatorFound = true; 182 if (line.length() > 0) { 183 for (int i = 0; i < line.length(); i++) { 184 if (line.charAt(i) != HORIZONTAL_LINE_CHAR) { 185 horizontialLineSeparatorFound = false; 186 break; 187 } 188 } 189 if (horizontialLineSeparatorFound) { 190 writer.write(writer.getCurrentLineNumber(), 0, writer.getCurrentLineNumber(), 191 line.length() + 1); 192 } 193 } 194 return horizontialLineSeparatorFound; 195 } 196 197 private static void printVerticalLineSeparator(HardcopyWriter writer, String line) { 198 for (int i = 0; i < line.length(); i++) { 199 if (line.charAt(i) == VERTICAL_LINE_CHAR) { 200 // make a frame (two column format) 201 if (Setup.isTabEnabled()) { 202 writer.write(writer.getCurrentLineNumber(), 0, writer.getCurrentLineNumber() + 1, 0); 203 writer.write(writer.getCurrentLineNumber(), line.length() + 1, 204 writer.getCurrentLineNumber() + 1, line.length() + 1); 205 } 206 writer.write(writer.getCurrentLineNumber(), i + 1, writer.getCurrentLineNumber() + 1, 207 i + 1); 208 } 209 } 210 } 211 212 private final static Logger log = LoggerFactory.getLogger(TrainPrintManifest.class); 213}