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