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