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