001package jmri.jmrit.symbolicprog; 002 003import java.awt.Font; 004import java.awt.event.ActionEvent; 005import java.util.Locale; 006 007import javax.swing.AbstractAction; 008 009import jmri.jmrit.roster.RosterEntry; 010import jmri.jmrit.symbolicprog.tabbedframe.PaneProgFrame; 011import jmri.util.davidflanagan.HardcopyWriter; 012 013/** 014 * Action to print the information in the CV table. 015 * <p> 016 * This uses the older style printing, for compatibility with Java 1.1.8 in 017 * Macintosh MRJ 018 * 019 * @author Bob Jacobsen Copyright (C) 2003; D Miller Copyright 2003, 2005 020 */ 021public class PrintCvAction extends AbstractAction { 022 023 static final int TABLE_COLS = 3; 024 025 public PrintCvAction(String actionName, CvTableModel pModel, 026 PaneProgFrame pParent, boolean preview, RosterEntry pRoster) { 027 super(actionName); 028 mModel = pModel; 029 mFrame = pParent; 030 isPreview = preview; 031 mRoster = pRoster; 032 } 033 034 /** 035 * Frame hosting the printing 036 */ 037 private final PaneProgFrame mFrame; 038 private final CvTableModel mModel; 039 private final RosterEntry mRoster; 040 /** 041 * Variable to set whether this is to be printed or previewed 042 */ 043 private final boolean isPreview; 044 045 public void printInfoSection(HardcopyWriter w) { 046 // Write out the icon 047 w.writeDecoderProIcon(); 048 w.setFont(null, Font.BOLD, null); 049 050 mRoster.printEntry(w); 051 w.setFont(null, Font.PLAIN, null); 052 } 053 054 @Override 055 public void actionPerformed(ActionEvent e) { 056 057 // obtain a HardcopyWriter to do this 058 HardcopyWriter writer; 059 try { 060 writer = new HardcopyWriter(mFrame, mFrame.getRosterEntry().getId(), null, null, 10, 061 .8 * 72, .5 * 72, .5 * 72, .5 * 72, isPreview, null, null, null, null, null); 062 063 // print the decoder info section, etc 064 printInfoSection(writer); 065 String s = "\n\n"; 066 writer.write(s); 067 068 //Initialize some variables to define the CV table size 069 int cvCount = mModel.getRowCount(); 070 int tableLeft = 1; 071 int tableRight = TABLE_COLS * 24 + 1; // ISSUE: this is wrong 072 int tableTopPos; 073 int tableBottomPos; 074 int tableHeightPoints = (cvCount / TABLE_COLS) * writer.getLineHeight(); 075 if (cvCount % TABLE_COLS > 0) { 076 tableHeightPoints += writer.getLineHeight(); 077 } 078 079 int tableHeightRows = tableHeightPoints / writer.getLineHeight(); 080 081 /* 082 * Start drawing the table of CVs. Set up the table with 4 columns 083 * of CV/Value pairs and Draw the table borders and lines. Each 084 * column width is 16 characters, including the starting vertical 085 * line, but not the ending one. Therefore the total table width is 086 * 64+1 characters The colummn headings take 2 lines 4 columns of 20 087 * gives 80 CVs possible. NMRA specs only define about 70 CVs 088 * including all the optional ones plus some Manufacturer ones. 80 089 * should be enough, although more can be added by increasing the 090 * tableHeight value 091 */ 092 093 /* 094 * ISSUE: this is wrong as it doesn't take into account what happens when the table is printed on multiple pages. 095 * The table is drawn as if it were on a single page, but it may not be. In particular the vertical lines only 096 * appear on the first page, and *maybe* we ought to put the column headings on the subsequent pages too. 097 */ 098 //Set the top row and draw top line to start the table of CVs 099 tableTopPos = writer.getCurrentVPos(); 100 101 //set the bottom of the table 102 tableBottomPos = tableTopPos + tableHeightPoints + 2; 103 104 float useCharWidth = writer.getCharWidth(); 105 106 writer.writeLine(tableTopPos, (int) (tableLeft * useCharWidth), tableTopPos, (int) (tableRight * useCharWidth)); 107 108 //Draw vertical lines for columns 109 for (int i = 1; i < 76; i += 24) { 110 writer.writeLine(tableTopPos, (int) (i * useCharWidth), tableBottomPos, (int) (i * useCharWidth)); // ISSUE: this is wrong 111 } 112 113 //Draw remaining horozontal lines 114 writer.writeLine(tableTopPos + 2 * writer.getLineHeight(), (int) (tableLeft * useCharWidth), tableTopPos + 2 * writer.getLineHeight(), (int) (tableRight * useCharWidth)); 115 writer.writeLine(tableBottomPos, (int) (tableLeft * useCharWidth), tableBottomPos, (int) (tableRight * useCharWidth)); 116 117 writer.setFont(null, Font.BOLD, null); //set font to Bold 118 // print a simple heading with I18N 119 // pad with spaces to column width, 3 x insert Value as var %1 120 s = String.format("%1$21s%1$24s%1$24s", Bundle.getMessage("Value")); 121 writer.write(s); 122 s = "\n"; 123 writer.write(s); 124 // NOI18N 125 s = " CV Dec Hex CV Dec Hex CV Dec Hex\n"; 126 writer.write(s); 127 writer.setFont(null, Font.PLAIN, null); //set font back to Normal 128 129 /* 130 * Create array to hold CV/Value strings to allow reformatting and 131 * sorting. Same size as the table drawn above (4 132 * columns*tableHeight; heading rows not included 133 */ 134 String[] cvStrings = new String[TABLE_COLS * tableHeightRows]; 135 136 //blank the array 137 for (int i = 0; i < cvStrings.length; i++) { 138 cvStrings[i] = ""; 139 } 140 141 // get each CV and value 142 for (int i = 0; i < mModel.getRowCount(); i++) { 143 CvValue cv = mModel.getCvByRow(i); 144 int value = cv.getValue(); 145 146 //convert and pad numbers as needed 147 String numString = String.format("%12s", cv.number()); 148 String valueString = Integer.toString(value); 149 String valueStringHex = Integer.toHexString(value).toUpperCase(Locale.ENGLISH); 150 if (value < 16) { 151 valueStringHex = "0" + valueStringHex; 152 } 153 for (int j = 1; j < 3; j++) { 154 if (valueString.length() < 3) { 155 valueString = " " + valueString; 156 } 157 } 158 //Create composite string of CV and its decimal and hex values 159 s = " " + numString + " " + valueString + " " + valueStringHex + " "; 160 161 //populate printing array - still treated as a single column 162 cvStrings[i] = s; 163 } 164 165 //sort the array in CV order (just the members with values) 166 String temp; 167 boolean swap; 168 do { 169 swap = false; 170 for (int i = 0; i < mModel.getRowCount() - 1; i++) { 171 if (cvSortOrderVal(cvStrings[i + 1].substring(0, 15).trim()) < cvSortOrderVal( 172 cvStrings[i].substring(0, 15).trim())) { 173 temp = cvStrings[i + 1]; 174 cvStrings[i + 1] = cvStrings[i]; 175 cvStrings[i] = temp; 176 swap = true; 177 } 178 } 179 } while (swap); 180 181 //Print the array in three columns 182 for (int i = 0; i < tableHeightRows; i++) { 183 s = cvStrings[i] + cvStrings[i + tableHeightRows] + cvStrings[i + tableHeightRows * 2] + "\n"; 184 writer.write(s); 185 } 186 //write an extra character to work around the 187 //last character truncation bug with HardcopyWriter 188 //s = " \n"; 189 //writer.write(s, 0, s.length()); 190 } catch (java.io.IOException ex1) { 191 log.error("IO exception while printing"); 192 return; 193 } catch (HardcopyWriter.PrintCanceledException ex2) { 194 log.debug("Print cancelled"); 195 return; 196 } 197 198 writer.close(); 199 } 200 201 /** 202 * Returns a representation of a CV name as a long integer sort order value. 203 * <p> 204 * The value itself is not meaningful, but is used in comparisons when 205 * sorting. 206 * 207 * @param cvName cv name string to parse. 208 * @return the sort order value. 209 */ 210 public static long cvSortOrderVal(String cvName) { 211 final int MAX_CVMNUM_SPACE = 1200; 212 213 // Split the string by any non-numeric character 214 String[] cvNumStrings = cvName.split("\\D+"); 215 long sortVal = 0; 216 for (int i = 0; i < (cvNumStrings.length); i++) { 217 sortVal = (sortVal * MAX_CVMNUM_SPACE) + Integer.parseInt(cvNumStrings[i]); 218 } 219 return sortVal; 220 } 221 222 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PrintCvAction.class); 223 224}