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