001package jmri.jmrix.can.cbus.swing.eventtable; 002 003import java.awt.Font; 004import java.awt.Frame; 005import java.awt.event.ActionEvent; 006import java.io.IOException; 007import javax.annotation.Nonnull; 008import javax.swing.AbstractAction; 009import jmri.jmrix.can.cbus.eventtable.CbusEventTableDataModel; 010import jmri.util.davidflanagan.HardcopyWriter; 011 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015/** 016 * Print or Print Preview Action for CBUS Event Table 017 */ 018public class CbusEventTablePrintAction extends AbstractAction { 019 020 private final static int[] whichPrintColumns = {CbusEventTableDataModel.NODE_COLUMN, 021 CbusEventTableDataModel.EVENT_COLUMN,CbusEventTableDataModel.NAME_COLUMN, 022 CbusEventTableDataModel.NODENAME_COLUMN,CbusEventTableDataModel.COMMENT_COLUMN}; 023 024 private final String _title; 025 private final CbusEventTableDataModel _model; 026 private final boolean _preview; 027 028 /** 029 * Create a new Save to CSV Action. 030 * 031 * @param actionName Action Name 032 * @param model Table Model to use. 033 * @param title Page Title. 034 * @param preview True to preview, false to print. 035 */ 036 public CbusEventTablePrintAction(String actionName, @Nonnull CbusEventTableDataModel model, 037 @Nonnull String title, boolean preview ){ 038 super(actionName); 039 _model = model; 040 _title = title; 041 _preview = preview; 042 043 } 044 045 /** 046 * {@inheritDoc} 047 */ 048 @Override 049 public void actionPerformed(ActionEvent e) { 050 051 jmri.util.ThreadingUtil.runOnGUIEventually( () -> { 052 HardcopyWriter writer; 053 try { 054 writer = new HardcopyWriter(new Frame(), _title, 10, .8, .5, .5, .5, _preview); 055 } catch (HardcopyWriter.PrintCanceledException ex) { 056 // log.debug("Preview cancelled"); 057 return; 058 } 059 writer.increaseLineSpacing(20); 060 printTable(writer); // close() is taken care of in printTable() 061 writer.close(); 062 }); 063 } 064 065 /** 066 * Self print or print preview the table. 067 * <p> 068 * Copied from BeanTableDataModel modified to print variable column widths. 069 * Final column with size zero runs to extent of page width. 070 * <p> 071 * Printed with headings and vertical lines between each column. Data is 072 * word wrapped within a column. 073 * 074 * @param w the writer to print to 075 */ 076 private void printTable(HardcopyWriter w ) { 077 078 // [AC] variable column sizes 079 080 // column header labels 081 String[] columnStrings = new String[whichPrintColumns.length]; 082 083 int[] columnWidth = new int[whichPrintColumns.length]; 084 // in a test, thats 86 chars on a line 085 086 colWidthLoop(columnStrings, columnWidth, w); 087 088 // Draw horizontal dividing line 089 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), 090 w.getCharactersPerLine()); 091 092 w.setFontStyle(Font.BOLD); 093 printColumns(w, columnStrings, columnWidth); 094 w.setFontStyle(0); 095 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), 096 w.getCharactersPerLine()); 097 098 getEachRow(w, columnStrings, columnWidth); 099 100 101 } 102 103 private void colWidthLoop(String[] columnStrings, int[] columnWidth, HardcopyWriter w){ 104 int columnTotal = 0; 105 for (int i = 0; i < whichPrintColumns.length; i++) { 106 // Put each column header in the array 107 columnStrings[i] = _model.getColumnName(whichPrintColumns[i]); 108 109 int columnworkedon=whichPrintColumns[i]; 110 111 if (getColumnWidth(columnworkedon) == 0) { 112 // Fill to end of line 113 columnWidth[i] = w.getCharactersPerLine() - columnTotal; 114 } else { 115 columnWidth[i] = getColumnWidth(columnworkedon); 116 columnTotal = columnTotal + columnWidth[i] + 1; 117 } 118 } 119 } 120 121 private void getEachRow(HardcopyWriter w, String[] columnStrings, int[] columnWidth){ 122 123 // now print each row of data 124 // create a base string the width of the column 125 for (int i = 0; i < _model.getRowCount(); i++) { 126 for (int k = 0; k < whichPrintColumns.length; k++) { 127 128 int j=whichPrintColumns[k]; 129 130 //check for special, non string contents 131 if (_model.getValueAt(i, j) instanceof Integer) { 132 columnStrings[k] = (_model.getValueAt(i, j)).toString(); 133 } else { 134 columnStrings[k] = (String) _model.getValueAt(i, j); 135 } 136 } 137 138 printColumns(w, columnStrings, columnWidth); 139 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), 140 w.getCharactersPerLine()); 141 } 142 } 143 144 // [AC] modified to take an array of column widths 145 private void printColumns(HardcopyWriter w, String columnStrings[], int columnWidth[]) { 146 String columnString = ""; 147 StringBuilder lineString = new StringBuilder(); 148 String spaces; 149 // loop through each column 150 boolean complete = false; 151 while (!complete) { 152 complete = true; 153 for (int i = 0; i < columnStrings.length; i++) { 154 // create a base string the width of the column 155 StringBuilder buf = new StringBuilder(); 156 for (int j = 0; j < columnWidth[i]; j++) { 157 buf.append(" "); 158 } 159 spaces = buf.toString(); 160 // if the column string is too wide, cut it at word boundary (valid delimiters are space, - and _) 161 // Use the intial part of the text, pad it with spaces and place the remainder back in the array 162 // for further processing on next line. 163 // If column string isn't too wide, pad it to column width with spaces if needed 164 if (columnStrings[i].length() > columnWidth[i]) { 165 boolean noWord = true; 166 for (int k = columnWidth[i]; k >= 1; k--) { 167 if (columnStrings[i].substring(k - 1, k).equals(" ") 168 || columnStrings[i].substring(k - 1, k).equals("-") 169 || columnStrings[i].substring(k - 1, k).equals("_")) { 170 columnString = columnStrings[i].substring(0, k) 171 + spaces.substring(k); 172 columnStrings[i] = columnStrings[i].substring(k); 173 noWord = false; 174 complete = false; 175 break; 176 } 177 // log.debug("1050 columnString {}",columnString); 178 } 179 180 // log.debug("1053 noword is {} ",noWord); 181 if (noWord) { // not breakable, hard break 182 columnString = columnStrings[i].substring(0, columnWidth[i]); 183 columnStrings[i] = columnStrings[i].substring(columnWidth[i]); 184 complete = false; 185 } 186 } else { 187 columnString = columnStrings[i] + spaces.substring(columnStrings[i].length()); // pad with spaces 188 columnStrings[i] = ""; 189 } 190 lineString.append(columnString).append(" "); 191 } 192 try { 193 w.write(lineString.toString()); 194 //write vertical dividing lines 195 int column = 0; 196 for (int i = 0; i < whichPrintColumns.length; i++) { 197 w.write(w.getCurrentLineNumber(), column, w.getCurrentLineNumber() + 1, column); 198 column = column + columnWidth[i] + 1; 199 // log.debug("1167 i is {} column is {} columnWidth[i] is {} ", i, column, columnWidth[i]); 200 } 201 w.write(w.getCurrentLineNumber(), w.getCharactersPerLine(), 202 w.getCurrentLineNumber() + 1, w.getCharactersPerLine()); 203 w.write("\n"); 204 } catch (IOException e) { 205 log.warn("error during printing", e); 206 } 207 } 208 } 209 210 211 /** 212 * Returns int of column width. 213 * <p> 214 * Just used for printing. 215 * in a test, there is 86 chars on a line 216 * -1 is invalid 217 * 0 is final column extend to end 218 * 219 * @param col int col number 220 * @return print width 221 */ 222 private static int getColumnWidth(int col) { 223 switch (col) { 224 case CbusEventTableDataModel.NAME_COLUMN: 225 return 14; 226 case CbusEventTableDataModel.COMMENT_COLUMN: 227 return 0; // 0 to get writer recognize it as the last column, will fill with spaces 228 default: 229 return 8; 230 } 231 } 232 233 private final static Logger log = LoggerFactory.getLogger(CbusEventTablePrintAction.class); 234 235}