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