| // FontViewer.java - Display system fonts, with a sample in each | // 0 |
| // FontViewer preface - comment, package, imports | // 1 |
| /** FontViewer.java | // 2 comments |
| * Show all the fonts that Java knows | // 3 comments |
| * and display a sample string in each | // 4 comments |
| * | // 5 comments |
| * @author zweibieren | // 6 comments |
| * Jan 13, 2010 5:25 PM | // 7 comments |
| */ | // 8 comments |
| // 9 comments |
| package com.physpics.fontviewer; | // 10 backbone |
| // 11 backbone |
| import java.io.*; | // 12 readcats|offline |
| import java.util.*; | // 13 stringmap|sort |
| import java.awt.*; | // 14 fontlist |
| import javax.swing.*; | // 15 backbone |
| import java.awt.event.*; | // 16 window |
| import java.net.*; | // 17 help |
| import javax.swing.table.*; | // 18 table |
| import java.util.regex.*; | // 19 readcats|styles |
| // 20 window |
| // end FontViewer preface - comment, package, imports | // 21 |
| // FontViewer class | // 22 |
| /** | // 23 comments |
| * View a string in all fonts on the system. | // 24 comments |
| * The window is laid out like this <pre> | // 25 comments |
| * S C TTT | // 26 comments |
| * LLLLLL! | // 27 comments |
| * LLLLLL! | // 28 comments |
| * LLLLLL! | // 29 comments |
| * | // 30 comments |
| * S, a JSpinner for choosing a font size | // 31 comments |
| * C, a JComboBox for choosing one of the four styles | // 32 comments |
| * TT, A JTextField for writing the text to be displayed in the fonts | // 33 comments |
| * LLL, a JTable where each row has: | // 34 comments |
| * "B" if font is bold | // 35 comments |
| * "I" if font is italic | // 36 comments |
| * font category, e.g., script or serif | // 37 comments |
| * a check box to mark candidate fonts | // 38 comments |
| * font name | // 39 comments |
| * the T text displayed in the named font | // 40 comments |
| * ! there is a vertical scrollbar for LLL | // 41 comments |
| * </pre> | // 42 comments |
| */ | // 43 comments |
| public class FontViewer extends JPanel { | // 44 backbone |
| public class FontViewer extends JPanel implements ActionListener { | // 45 backbone&menu |
| // 46 backbone |
| // FontViewer class variable declarations - globals for the visible window components | // 47 |
| static final Font[] fontList; // names of all fonts known to Java | // 48 fontlist |
| static { | // 49 fontlist |
| GraphicsEnvironment gEnv = | // 50 fontlist |
| GraphicsEnvironment.getLocalGraphicsEnvironment(); | // 51 fontlist |
| fontList = gEnv.getAllFonts(); | // 52 fontlist |
| } | // 53 fontlist |
| // 54 fontlist |
| static final String defaultSample // default string for fontsamples | // 55 sampletext|samples |
| // has all letters, two ligatures, common digrams & trigrams | // 56 sampletext|samples |
| = "Fred fixed the zoo flight's problems " | // 57 sampletext|samples |
| + "by quickly waiving his objections."; | // 58 sampletext|samples |
| String currentSample = defaultSample; | // 59 sampletext|samples |
| // 60 sampletext|samples |
| // default location to read categories | // 61 readcats |
| static final String catsDefaultFile = "resource:fontcategories.txt"; | // 62 readcats |
| // 63 readcats |
| static final Font labelFont // default font for screen text | // 64 window |
| = new Font("Dialog", Font.PLAIN, 14); | // 65 window |
| static final Font headerFont // font for column headers | // 66 table |
| = new Font("Dialog", Font.BOLD, 14); | // 67 table |
| static final String[] styleNames // for the style JComboBox | // 68 pickstyle |
| = {"Plain", "Bold", "Italic", "Bold Italic"}; | // 69 pickstyle |
| static final int[] styleValues | // 70 pickstyle |
| = new int[]{Font.PLAIN, Font.BOLD, | // 71 pickstyle |
| Font.ITALIC, Font.BOLD | Font.ITALIC}; | // 72 pickstyle |
| final static int INITIALFONTSIZE = 12; // initial fontsize for samples | // 73 picksize|table |
| // 74 table |
| // table row height is fontsize plus ADDFORROWHEIGHT | // 75 table |
| final static int ADDFORROWHEIGHT = 8; | // 76 table |
| // 77 table |
| // components of the window | // 78 window |
| JComboBox styles = new JComboBox(styleNames); | // 79 pickstyle |
| SpinnerNumberModel sizeModel // font sizes range | // 80 picksize |
| = new SpinnerNumberModel(INITIALFONTSIZE, 6, 40, 4); | // 81 picksize |
| JSpinner sizes; // choose from sizeModel | // 82 picksize |
| // 83 picksize |
| // the fonts listing | // 84 table |
| FontsTable mainTable; // one line per font | // 85 table |
| JScrollPane scrollTable; // scroller for mainTable | // 86 scroll|rowvis |
| int styleColIndex = -1; // STYLECOL index for style flags, B/I | // 87 styles |
| int catColIndex = -1; // CATCOL index for categories | // 88 cats |
| int fontColIndex = -1; // FONTCOL index for font names | // 89 fonts |
| int chkColIndex = -1; // CHECKCOL index for checkboxes | // 90 checkboxes |
| int sampleColIndex = -1; // SAMPLECOL index for sample text | // 91 samples |
| JTextField sampleEditor; | // 92 samples |
| DemoText sampleEditor; // editor for the sample text | // 93 sampletext |
| // 94 table |
| // borders for cells in the table | // 95 table |
| static final javax.swing.border.Border cellBorder | // 96 table |
| = BorderFactory.createEmptyBorder(0, 3, 0, 0); | // 97 table |
| static final javax.swing.border.Border borderBlue | // 98 table |
| = BorderFactory.createCompoundBorder( | // 99 table |
| BorderFactory.createLineBorder(Color.BLUE), | // 100 table |
| BorderFactory.createEmptyBorder(0, 2, 0, 0)); | // 101 table |
| // 102 table |
| // a row is offscreen when no more than SLIVER pixels are visible | // 103 rowvis |
| final static int SLIVER = 6; | // 104 rowvis |
| // 105 rowvis |
| // double buffering is turned off during fast scroll | // 106 fasterscroll |
| boolean needToRestoreDoubleBuffering = false; | // 107 fasterscroll |
| // 108 fasterscroll |
| javax.swing.Timer saveTask = null; | // 109 savecats&autosave |
| // 110 savecats&autosave |
| // end FontViewer class variable declarations - globals for the visible window components | // 111 |
| // FontViewer() constructor: create the window components | // 112 |
| /** Construct a FontViewer. | // 113 window |
| * @param catMap Map from font names to categories | // 114 window&stringmap |
| * This will establish values for CATCOL. | // 115 window&stringmap |
| */ | // 116 window |
| private FontViewer() { | // 117 offline |
| public FontViewer() { | // 118 window |
| public FontViewer(StringMap catMap) { | // 119 window&stringmap |
| // make the size chooser for the top row | // 120 picksize |
| sizes = new JSpinner(sizeModel); | // 121 picksize |
| sizes.setFont(labelFont); | // 122 picksize |
| sizes.addChangeListener( | // 123 picksize&samples |
| new javax.swing.event.ChangeListener() { | // 124 picksize&samples |
| @Override | // 125 picksize&samples |
| public void stateChanged(javax.swing.event.ChangeEvent e) { | // 126 picksize&samples |
| mainTable.refontTheSamples(); | // 127 picksize&samples |
| } | // 128 picksize&samples |
| }); | // 129 picksize&samples |
| // 130 picksize |
| // make the style chooser for the top row | // 131 pickstyle |
| styles.setFont(labelFont); | // 132 pickstyle |
| styles.addItemListener(new ItemListener() { | // 133 pickstyle&samples |
| @Override | // 134 pickstyle&samples |
| public void itemStateChanged(ItemEvent e) { | // 135 pickstyle&samples |
| mainTable.refontTheSamples(); | // 136 pickstyle&samples |
| } | // 137 pickstyle&samples |
| }); | // 138 pickstyle&samples |
| // 139 pickstyle |
| // make the sample text editor | // 140 sampletext |
| sampleEditor = new JTextField(defaultSample); | // 141 samples |
| sampleEditor = new DemoText(defaultSample); | // 142 sampletext |
| // 143 sampletext |
| // ENTER key in sampletext: so rebuild the SAMPLECOL | // 144 sampletext&samples |
| sampleEditor.addActionListener(new ActionListener() { | // 145 sampletext&samples |
| @Override | // 146 sampletext&samples |
| public void actionPerformed(ActionEvent e) { | // 147 sampletext&samples |
| mainTable.reviseSamples(); | // 148 sampletext&samples |
| } | // 149 sampletext&samples |
| }); | // 150 sampletext&samples |
| // 151 sampletext&samples |
| // make the table showing fonts | // 152 table |
| scrollTable = new JScrollPane( | // 153 scroll|rowvis |
| ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, | // 154 scroll|rowvis |
| ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER) { | // 155 scroll|rowvis |
| }; | // 156 scroll|rowvis |
| // 157 fasterscroll |
| scrollTable.setViewport(new JViewport() { | // 158 fasterscroll |
| @Override | // 159 fasterscroll |
| public void paint(Graphics g) { | // 160 fasterscroll |
| super.paint(g); | // 161 fasterscroll |
| if (needToRestoreDoubleBuffering) { | // 162 fasterscroll |
| needToRestoreDoubleBuffering = false; | // 163 fasterscroll |
| FontViewer.this.setDoubleBuffered(true); | // 164 fasterscroll |
| FontViewer.this.getRootPane().setDoubleBuffered(true); | // 165 fasterscroll |
| } | // 166 fasterscroll |
| } | // 167 fasterscroll |
| }); | // 168 fasterscroll |
| mainTable = new FontsTable(); | // 169 table |
| mainTable = new FontsTable(catMap); | // 170 table&readcats |
| scrollTable.setViewportView(mainTable); | // 171 scroll|rowvis |
| // 172 scroll|rowvis |
| scrollTable.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, | // 173 scrollcorner |
| mainTable. new FTCorner()); | // 174 scrollcorner |
| mainTable.refontTheSamples(); | // 175 samples |
| // 176 samples |
| scrollTable.getVerticalScrollBar().getModel() | // 177 fastscroll |
| .addChangeListener(mainTable.new FTChangeListener()); | // 178 fastscroll |
| // 179 fastscroll |
| // put things in the window | // 180 window |
| setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); | // 181 window |
| setLayout(new BorderLayout(6, 6)); // gaps of size 6 | // 182 window |
| Box top = Box.createHorizontalBox(); | // 183 top |
| top.add(Box.createHorizontalStrut(12)); | // 184 top |
| sizes.setBorder(BorderFactory.createTitledBorder("Font Size")); | // 185 picksize |
| top.add(sizes); | // 186 picksize |
| top.add(new TitledWidget("Font Size", sizes, true)); | // 187 picksize&titled |
| top.add(Box.createHorizontalStrut(12)); | // 188 top |
| styles.setBorder(BorderFactory.createTitledBorder("Font Style")); | // 189 pickstyle |
| top.add(styles); | // 190 pickstyle |
| top.add(new TitledWidget("Font Style", styles, true)); | // 191 pickstyle&titled |
| top.add(Box.createHorizontalStrut(12)); | // 192 top |
| sampleEditor.setBorder(BorderFactory.createTitledBorder("Sample Text")); | // 193 sampletext |
| top.add(sampleEditor); | // 194 sampletext |
| top.add(new TitledWidget("Sample Text", sampleEditor, false)); | // 195 sampletext&titled |
| top.add(Box.createHorizontalStrut(12)); | // 196 top |
| // 197 top |
| add(top, BorderLayout.NORTH); | // 198 top |
| add(mainTable, BorderLayout.CENTER); | // 199 table |
| add(scrollTable, BorderLayout.CENTER); | // 200 table&scroll |
| } // end FontViewer(...) | // 201 offline |
| } // end FontViewer(...) | // 202 window |
| // 203 window |
| // end FontViewer() constructor: create the window components | // 204 |
| // FontViewer.actionPerformed handle menu hits //=menu | // 205 |
| public void actionPerformed(ActionEvent e) { | // 206 menu |
| switch(e.getActionCommand().charAt(0)) { | // 207 menu |
| case 'S': // Save | // 208 menu |
| mainTable.cancelEditing(); | // 209 menu&canceledit |
| if (mainTable.catsMap.catDest == null | // 210 menu&filechooser |
| || ! mainTable.catsMap.mutable) | // 211 menu&filechooser |
| mainTable.catsMap.promptForCatDest(); | // 212 menu&filechooser |
| if (mainTable.catsMap.catDest != null) | // 213 menu&filechooser |
| mainTable.saveCats(); | // 214 menu&savecats |
| break; | // 215 menu |
| case 'A': // SaveAs | // 216 menu |
| mainTable.cancelEditing(); | // 217 menu&canceledit |
| mainTable.catsMap.promptForCatDest(); | // 218 menu&filechooser |
| if (mainTable.catsMap.catDest != null) | // 219 menu&filechooser |
| mainTable.saveCats(); | // 220 menu&savecats |
| break; | // 221 menu |
| case 'X': | // 222 menu&shut |
| Container top = getTopLevelAncestor(); | // 223 menu&shut |
| if (top instanceof Window) | // 224 menu&shut |
| ((Window)top).dispose(); //will throw windowClosing event | // 225 menu&shut |
| break; | // 226 menu&shut |
| case 'H': // Help | // 227 menu&help |
| Desktop dt = Desktop.getDesktop(); | // 228 menu&help |
| try { | // 229 menu&help |
| // FVHelp.html is in the same directory as FontViewer.jar | // 230 menu&help |
| // url is in form: file://path/FontViewer.jar!/com/... | // 231 menu&help |
| // desired URI is file://path/FVHelp.html | // 232 menu&help |
| String path = FontViewer.class | // 233 menu&help |
| .getResource("FontViewer.class").getPath(); | // 234 menu&help |
| String uri; | // 235 menu&help |
| int bangX = path.indexOf('!'); | // 236 menu&help |
| if (bangX >= 0) { | // 237 menu&help |
| // the usual case where FontViewer.class is in a jar | // 238 menu&help |
| int slashX = path.substring(0, bangX).lastIndexOf('/'); | // 239 menu&help |
| uri = path.substring(0,slashX); | // 240 menu&help |
| } | // 241 menu&help |
| else // not in a jar; probably debugging; use server version | // 242 menu&help |
| uri = "http://physpics.com/Java/apps/FontViewer"; | // 243 menu&help |
| dt.browse(new URI(uri+"/FVHelp.html")); | // 244 menu&help |
| } | // 245 menu&help |
| catch(IOException ioe) { ioe.printStackTrace(); } | // 246 menu&help |
| catch(URISyntaxException use) { use.printStackTrace(); } | // 247 menu&help |
| break; | // 248 menu&help |
| } | // 249 menu |
| } | // 250 menu |
| // 251 menu |
| // end FontViewer.actionPerformed handle menu hits //=menu | // 252 |
| // FontViewer.startSaving(): xreate periodic save task | // 253 |
| /** | // 254 savecats&autosave |
| * Start a thread that will periodically dispatch a save-categories task. | // 255 savecats&autosave |
| * It continues even if the StringMap is neither mutable nor changed; | // 256 savecats&autosave |
| * its resource burden is quite small. | // 257 savecats&autosave |
| * @param interval milliseconds between save tries | // 258 savecats&autosave |
| */ | // 259 savecats&autosave |
| public void startSaving(int interval) { | // 260 savecats&autosave |
| if (saveTask == null) { | // 261 savecats&autosave |
| ActionListener saveCatsTask= new ActionListener() { | // 262 savecats&autosave |
| @Override | // 263 savecats&autosave |
| public void actionPerformed(ActionEvent evt) { | // 264 savecats&autosave |
| if (mainTable.catsMap.changed | // 265 savecats&autosave |
| && mainTable.catsMap.catDest != null) | // 266 savecats&autosave |
| mainTable.saveCats(); | // 267 savecats&autosave |
| } | // 268 savecats&autosave |
| }; | // 269 savecats&autosave |
| saveTask = new javax.swing.Timer(interval, saveCatsTask); | // 270 savecats&autosave |
| } | // 271 savecats&autosave |
| saveTask.start(); | // 272 savecats&autosave |
| } | // 273 savecats&autosave |
| /** | // 274 savecats&autosave |
| * Stop(but do not discard) the task that is doing periodic saves. | // 275 savecats&autosave |
| */ | // 276 savecats&autosave |
| public void stopSaving() { | // 277 savecats&autosave |
| saveTask.stop(); | // 278 savecats&autosave |
| } | // 279 savecats&autosave |
| // end FontViewer.startSaving(): xreate periodic save task | // 280 |
| // FontViewer.printFontList(): print fontnames | // 281 |
| /** | // 282 offline |
| * Print the list of fonts | // 283 offline |
| * @param ps where to send the output | // 284 offline |
| */ | // 285 offline |
| static public void printFontList(PrintStream ps) { | // 286 offline |
| for (Font f : FontViewer.fontList) | // 287 offline |
| ps.println(f.getFontName()); | // 288 offline |
| } | // 289 offline |
| // 290 offline |
| // end FontViewer.printFontList(): print fontnames | // 291 |
| // 292 comments |
| // 293 titled|sampletext |
| // 294 titled|sampletext |
| //////////////////////////////// | // 295 titled|sampletext |
| // HELPER CLASSES | // 296 titled|sampletext |
| // 297 titled|sampletext |
| // TitledWidget - class : A JPanel with a title at top and a widget within | // 298 |
| /** | // 299 titled |
| * Create a JPanel containing a widget with a title above it. | // 300 titled |
| * This class is here because look-and-feel implementations | // 301 titled |
| * differ too much in borders around JComboBox and JSpinner. | // 302 titled |
| */ | // 303 titled |
| public class TitledWidget extends JPanel { | // 304 titled |
| /** | // 305 titled |
| * Create a TitledWidget with padding on the right and below. | // 306 titled |
| * @param t Title string to display | // 307 titled |
| * @param widget The widget to border | // 308 titled |
| * @param fixedWidth Prevent width change | // 309 titled |
| */ | // 310 titled |
| public TitledWidget(String t, | // 311 titled |
| JComponent widget, boolean fixedWidth) { | // 312 titled |
| setLayout(new BorderLayout()); // layout for JPanel | // 313 titled |
| JLabel lbl = new JLabel(" "+t); // to line up left edges | // 314 titled |
| lbl.setForeground(Color.BLUE); | // 315 titled |
| add(lbl, BorderLayout.NORTH); | // 316 titled |
| add(widget, BorderLayout.CENTER); | // 317 titled |
| if (fixedWidth) { | // 318 titled |
| Dimension wpref = widget.getPreferredSize(); | // 319 titled |
| Dimension lpref = lbl.getPreferredSize(); | // 320 titled |
| Dimension pref = new Dimension( | // 321 titled |
| Math.max(wpref.width, lpref.width), | // 322 titled |
| wpref.height+lpref.height); | // 323 titled |
| setMaximumSize(pref); | // 324 titled |
| } | // 325 titled |
| } | // 326 titled |
| } | // 327 titled |
| // end TitledWidget - class : A JPanel with a title at top and a widget within | // 328 |
| // DemoText - class : a JTextField with application-specific event handlers and reset via mouse and keyboard | // 329 |
| /** | // 330 sampletext |
| * The sample text to be shown in each font. | // 331 sampletext |
| */ | // 332 sampletext |
| class DemoText extends JTextField { | // 333 sampletext |
| public final Action resetAction; | // 334 resetaction |
| public final String resetItem = "reset action"; | // 335 resetkey |
| @Override | // 336 sampletext&samples |
| public void fireActionPerformed() { | // 337 sampletext&samples |
| currentSample = getText(); | // 338 sampletext&samples |
| super.fireActionPerformed(); | // 339 sampletext&samples |
| } | // 340 sampletext&samples |
| public DemoText(String starterText) { | // 341 sampletext |
| super(starterText, 50); | // 342 sampletext |
| setFont(labelFont); | // 343 sampletext |
| setMargin(new Insets(3, 8, 3, 0)); | // 344 sampletext |
| // 345 sampletext |
| // focus loss from sampletext: so rebuild all samples in table | // 346 sampletext&samples |
| addFocusListener(new FocusAdapter() { | // 347 sampletext&samples |
| @Override | // 348 sampletext&samples |
| public void focusLost(FocusEvent e) { | // 349 sampletext&samples |
| if ( ! getText().equals(currentSample)) | // 350 sampletext&samples |
| fireActionPerformed(); | // 351 sampletext&samples |
| } | // 352 sampletext&samples |
| }); | // 353 sampletext&samples |
| // 354 sampletext&samples |
| // DemoText().resetAction : provide mouse and keystroke actions to reset the field | // 355 |
| // ------------------------------------------------ | // 356 resetaction |
| // the remainder of DemoText() defines menu and keystroke | // 357 resetaction |
| // to reset the sample text to its default value | // 358 resetaction |
| // 359 resetaction |
| // define the Action that will be invoked by key or menu | // 360 resetaction |
| resetAction = new AbstractAction("Reset") { | // 361 resetaction |
| @Override | // 362 resetaction |
| public void actionPerformed(ActionEvent e) { | // 363 resetaction |
| setText(defaultSample); | // 364 resetaction |
| currentSample = defaultSample; | // 365 resetaction |
| fireActionPerformed(); | // 366 resetaction |
| } | // 367 resetaction |
| }; | // 368 resetaction |
| resetAction.putValue(AbstractAction.SHORT_DESCRIPTION, | // 369 resetaction |
| "Reset the text to its original test value."); | // 370 resetaction |
| resetAction.putValue(AbstractAction.MNEMONIC_KEY, | // 371 resetaction |
| new Integer(KeyEvent.VK_R)); | // 372 resetaction |
| KeyStroke ctlR = KeyStroke.getKeyStroke(KeyEvent.VK_R, | // 373 resetkey |
| ActionEvent.CTRL_MASK); | // 374 resetkey |
| resetAction.putValue(AbstractAction.ACCELERATOR_KEY, ctlR); | // 375 resetkey |
| // 376 resetaction |
| // ctlR key will reset | // 377 resetkey |
| // getKeymap().addActionForKeyStroke(ctlR, resetAction); | // 378 resetkey |
| getActionMap().put(resetItem, resetAction); | // 379 resetkey |
| getInputMap().put(ctlR, resetItem); | // 380 resetkey |
| // 381 resetkey |
| // define and utilize a popup menu with only an item for reset | // 382 resetmenu |
| final JPopupMenu resetMenu = new JPopupMenu(); | // 383 resetmenu |
| resetMenu.add(new JMenuItem(resetAction)); | // 384 resetmenu |
| addMouseListener(new MouseAdapter() { | // 385 resetmenu |
| void popup(MouseEvent e) { | // 386 resetmenu |
| resetMenu.show(sampleEditor, e.getX(), e.getY()); | // 387 resetmenu |
| } | // 388 resetmenu |
| @Override | // 389 resetmenu |
| public void mousePressed(MouseEvent e) | // 390 resetmenu |
| { if (e.isPopupTrigger()) popup(e); } | // 391 resetmenu |
| @Override | // 392 resetmenu |
| public void mouseReleased(MouseEvent e) | // 393 resetmenu |
| { if (e.isPopupTrigger()) popup(e); } | // 394 resetmenu |
| }); | // 395 resetmenu |
| // end DemoText().resetAction : provide mouse and keystroke actions to reset the field | // 396 |
| } // end DemoText constructor | // 397 sampletext |
| } // end class DemoText | // 398 sampletext |
| // 399 sampletext |
| // end DemoText - class : a JTextField with application-specific event handlers and reset via mouse and keyboard | // 400 |
| // 401 table&comments |
| // 402 table&comments |
| /////////////////////////////////////// | // 403 table&comments |
| // FontsTable | // 404 table&comments |
| // 405 table&comments |
| // FontsTable - class : the central JTable for the application | // 406 |
| /** | // 407 table |
| * The table of font names and sample strings. | // 408 table |
| */ | // 409 table |
| private class FontsTable extends JTable { | // 410 table |
| DefaultTableModel tableData = new DefaultTableModel() { | // 411 table |
| @Override | // 412 table |
| // only CATCOL and CHECKCOL can be edited | // 413 table |
| public boolean isCellEditable(int row, int col) { | // 414 table |
| if (col == catColIndex) return true; | // 415 celled |
| if (col == catColIndex) return catsMap.mutable; | // 416 celled&savecats |
| if (col == chkColIndex) return true; | // 417 checkboxes |
| return false; | // 418 table |
| } | // 419 table |
| }; | // 420 table |
| // 421 table |
| StringMap catsMap = null; | // 422 stringmap |
| // 423 stringmap |
| final JTextField sink // way-station for paste value | // 424 ctlv |
| = new JTextField(); | // 425 ctlv |
| final Action pasteSinkAction // action that does paste | // 426 ctlv |
| = TransferHandler.getPasteAction(); | // 427 ctlv |
| // 428 ctlv |
| // colors for header background | // 429 table |
| Color normalHeaderBkgd = new Color(255, 255, 0xCE); | // 430 table |
| Color sortingHeaderBkgd = new Color(255, 0x99, 0x33); | // 431 bettersort |
| // 432 table |
| // backdoor value for header cell renderer | // 433 bettersort |
| int nowSorting = -1; // what column (in Model) is being sorted | // 434 bettersort |
| // 435 bettersort |
| // FontsTable() constructor: build the screen contents of the table | // 436 |
| @SuppressWarnings("BooleanConstructorCall") | // 437 checkboxes |
| public FontsTable() { | // 438 table |
| public FontsTable(StringMap categories) { | // 439 table&readcats |
| catsMap = categories; | // 440 table&readcats |
| setFillsViewportHeight(true); | // 441 table |
| setCellSelectionEnabled(true); | // 442 table |
| setGridColor(new Color(200, 240, 255)); | // 443 table |
| getTableHeader().setBackground(normalHeaderBkgd); | // 444 table |
| setRowHeight(INITIALFONTSIZE + ADDFORROWHEIGHT); | // 445 table |
| setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); | // 446 table |
| // 447 comments |
| // values to create the columns | // 448 table |
| String[] styleColumn // STYLECOL | // 449 styles |
| = new String[fontList.length]; | // 450 styles |
| String[] categoryColumn // CATCOL | // 451 cats |
| = new String[fontList.length]; | // 452 cats |
| final String[] FontColumn // FONTCOL | // 453 fonts |
| = new String[fontList.length]; | // 454 fonts |
| Boolean[] checkColumn // CHECKCOL | // 455 checkboxes |
| = new Boolean[fontList.length]; | // 456 checkboxes |
| JLabel[] sampleColumn // SAMPLECOL | // 457 samples |
| = new JLabel[fontList.length]; | // 458 samples |
| SampleFont[] sampleColumn // SAMPLECOL | // 459 fontedsamples |
| = new SampleFont[fontList.length]; | // 460 fontedsamples |
| // 461 table |
| for (int inx = 0; inx < fontList.length; inx++) { | // 462 table |
| String fontname = fontList[inx].getFontName(); | // 463 table |
| String stylStr = ""; | // 464 styles |
| String catStr = null; | // 465 cats |
| if (catsMap != null) | // 466 readcats |
| catStr = catsMap.get(fontname); | // 467 readcats |
| if (catStr == null) { | // 468 readcats |
| stylStr = (fontname.contains("Bold") ? "B" : "") | // 469 styles |
| + (fontname.contains("Italic") ? "I" : ""); | // 470 styles |
| catStr = ""; | // 471 cats |
| } | // 472 readcats |
| else { | // 473 readcats&styles |
| // for FontViewer, a StringMap value is style;category | // 474 readcats&styles |
| // where style is one of "", "B", "I" or "BI" | // 475 readcats&styles |
| // extract style code from front of catStr | // 476 readcats&styles |
| int semiloc = catStr.indexOf(";"); | // 477 readcats&styles |
| if (semiloc >= 0) { | // 478 readcats&styles |
| stylStr = catStr.substring(0,semiloc).trim(); | // 479 readcats&styles |
| catStr = catStr.substring(semiloc+1).trim(); | // 480 readcats&styles |
| } | // 481 readcats&styles |
| } | // 482 readcats&styles |
| styleColumn[inx] = stylStr; //STYLECOL | // 483 styles |
| categoryColumn[inx] = catStr; // CATCOL | // 484 cats |
| FontColumn[inx] = fontname; // FONTCOL | // 485 fonts |
| checkColumn[inx] = new Boolean(false); // CHECKCOL | // 486 checkboxes |
| sampleColumn[inx] = new JLabel(currentSample); // SAMPLECOL | // 487 samples |
| sampleColumn[inx] = new SampleFont(fontList[inx]); // SAMPLECOL | // 488 samples&fontedsamples |
| } | // 489 table |
| // 490 table |
| // FontsTable() - configure the TableModel with the four columns | // 491 |
| // Configure the columns: data, widths, renderers, and editors | // 492 table |
| // by setting limits on the widths of the first three columns, | // 493 table |
| // all excess space is allocated to the sample text column | // 494 table |
| // 495 table |
| // we will create our own TableColumns | // 496 table |
| setAutoCreateColumnsFromModel(false); | // 497 table |
| // tell this JTable about the model | // 498 table |
| setModel(tableData); | // 499 table |
| // 500 table |
| // STYLECOL - B for bold and I for italic | // 501 styles |
| styleColIndex = appendColumn("BI", styleColumn, | // 502 styles |
| 32,32,32, new FTStringRenderer(), null); | // 503 styles |
| // CATCOL - the categories column | // 504 cats |
| DefaultCellEditor catEditor | // 505 celled |
| = (DefaultCellEditor)getDefaultEditor(String.class); | // 506 celled |
| {catEditor.getComponent().setFont(labelFont); | // 507 celled |
| // setting a border has no effect | // 508 celled |
| ((JComponent)catEditor.getComponent()).setForeground(Color.RED);} | // 509 celled |
| catColIndex = appendColumn("Category", categoryColumn, | // 510 cats |
| 25, 75, 150, new FTStringRenderer(), null); | // 511 cats |
| 25, 75, 150, new FTStringRenderer(), catEditor); | // 512 cats&celled |
| // 513 cats |
| // FONTCOL - column of font names | // 514 fonts |
| fontColIndex = appendColumn("Font Name", FontColumn, | // 515 fonts |
| 75, 200, 300, new FTStringRenderer(), null); | // 516 fonts |
| // 517 fonts |
| // CHECKCOL - a checkbox to select fonts | // 518 checkboxes |
| chkColIndex = appendColumn("Ck", checkColumn, | // 519 checkboxes |
| 26, 26, 26, getDefaultRenderer(Boolean.class), | // 520 checkboxes |
| getDefaultEditor(Boolean.class)); | // 521 checkboxes |
| // 522 checkboxes |
| //SAMPLECOL - sample text in this row's font | // 523 samples |
| sampleColIndex = appendColumn("Sample written in named font", | // 524 samples |
| sampleColumn, 75, 300, 10000, | // 525 samples |
| new FTJLabelRenderer(), null); | // 526 samples |
| new FTFontRenderer(), null); | // 527 fontedsamples |
| // 528 samples |
| // end FontsTable() - configure the TableModel with the four columns | // 529 |
| // set the tooltip to be the same for all headers | // 530 sort |
| getTableHeader().setToolTipText( | // 531 sort |
| "Click checkboxes under Ck to compare fonts. " + | // 532 sort&checkboxes |
| "Click a header to sort on its column."); | // 533 sort |
| // 534 sort |
| // set a renderer for column headings | // 535 bettersort |
| getTableHeader().setDefaultRenderer(new FTHeaderRenderer()); | // 536 bettersort |
| // 537 bettersort |
| // enable sorting the table by column data | // 538 sort|simplesort |
| setAutoCreateRowSorter(true); | // 539 simplesort |
| setRowSorter(new FTRowSorter(tableData)); | // 540 sort |
| // 541 sort |
| // listen for changes to the table | // 542 mapchanged |
| tableData.addTableModelListener( | // 543 mapchanged |
| new javax.swing.event.TableModelListener() { | // 544 mapchanged |
| public void tableChanged( | // 545 mapchanged |
| javax.swing.event.TableModelEvent e) { | // 546 mapchanged |
| if ((e.getColumn() == catColIndex | // 547 mapchanged |
| || e.getColumn() == styleColIndex | // 548 mapchanged&styles |
| ) && e.getType() | // 549 mapchanged |
| == javax.swing.event.TableModelEvent.UPDATE) | // 550 mapchanged |
| catsMap.mapChanged(); | // 551 mapchanged |
| } | // 552 mapchanged |
| }); | // 553 mapchanged |
| // 554 mapchanged |
| // FontsTable() pasteCatAction : implement paste for a cell not being edited | // 555 |
| // When a cell is clicked on, it is editable and ctl-V works fine | // 556 comments |
| // but if cell is selected with arrow keys, ctl-V does nothing | // 557 comments |
| // we fix that here by defining pasteCatAction | // 558 comments |
| // pasteCatAction - for ctl-V after typing arrow keys | // 559 ctlv |
| Action pasteCatAction =new FTPasteAction(); | // 560 ctlv |
| String pasteCatKey = "pasteCat"; | // 561 ctlv |
| KeyStroke ctlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, | // 562 ctlv |
| ActionEvent.CTRL_MASK); | // 563 ctlv |
| // 564 ctlv |
| getInputMap().put(ctlV, pasteCatKey); | // 565 ctlv |
| getActionMap().put(pasteCatKey, pasteCatAction); | // 566 ctlv |
| // end FontsTable() pasteCatAction : implement paste for a cell not being edited | // 567 |
| addKeyListener(new KeyAdapter() { | // 568 keystyles |
| @Override | // 569 keystyles |
| public void keyPressed(KeyEvent e) { | // 570 keystyles |
| int row = getSelectedRow(); | // 571 keystyles |
| if (row == -1) return; | // 572 keystyles |
| row = convertRowIndexToModel(row); | // 573 keystyles |
| int col = convertColumnIndexToModel(getSelectedColumn()); | // 574 keystyles |
| if (col == catColIndex) return; | // 575 keystyles&cats |
| String s = (String)getModel().getValueAt(row, styleColIndex); | // 576 keystyles |
| int slen = s.length(); | // 577 keystyles |
| // s is exactly one of "" "B" "I" "BI" | // 578 keystyles |
| switch (e.getKeyCode()) { | // 579 keystyles |
| case KeyEvent.VK_B: | // 580 keystyles |
| if (slen > 0 && s.startsWith("B")) | // 581 keystyles |
| s = s.substring(1); | // 582 keystyles |
| else s = "B" + s; | // 583 keystyles |
| break; | // 584 keystyles |
| case KeyEvent.VK_I: | // 585 keystyles |
| if (slen > 0 && s.endsWith("I")) | // 586 keystyles |
| s = s.substring(0, slen-1); | // 587 keystyles |
| else s += "I"; | // 588 keystyles |
| break; | // 589 keystyles |
| case KeyEvent.VK_BACK_SPACE: | // 590 keystyles |
| if (slen > 0) s = s.substring(0, slen-1); | // 591 keystyles |
| break; | // 592 keystyles |
| case KeyEvent.VK_DELETE: | // 593 keystyles |
| if (slen > 0) s = s.substring(1); | // 594 keystyles |
| break; | // 595 keystyles |
| default: return; | // 596 keystyles |
| } | // 597 keystyles |
| // now s has the new value | // 598 keystyles |
| getModel().setValueAt(s, row, styleColIndex); | // 599 keystyles |
| e.consume(); | // 600 keystyles |
| } | // 601 keystyles |
| }); | // 602 keystyles |
| } // end FontsTable constructor | // 603 table |
| // 604 table |
| // end FontsTable() constructor: build the screen contents of the table | // 605 |
| // FontsTable methods | // 606 |
| // 607 table&comments |
| // 608 table&comments |
| ///////////////////////////////////////////// | // 609 table&comments |
| // FontsTable methods | // 610 table&comments |
| // 611 table&comments |
| /** | // 612 table |
| * Append a column to the TableModel and the TableColumnModel. | // 613 table |
| * Convenience method for building the table. | // 614 table |
| */ | // 615 table |
| final int appendColumn(String name, Object[]data, int minW, | // 616 table |
| int prefW, int maxW, | // 617 table |
| TableCellRenderer render, TableCellEditor edit) { | // 618 table |
| int index = tableData.getColumnCount(); | // 619 table |
| tableData.addColumn(name, data); | // 620 table |
| TableColumn col = new TableColumn(index, prefW, render, edit); | // 621 table |
| col.setMinWidth(minW); | // 622 table |
| col.setMaxWidth(maxW); | // 623 table |
| addColumn(col); | // 624 table |
| return index; | // 625 table |
| } | // 626 table |
| // 627 table |
| // FontsTable.refontTheSamples() : when the size or style changes, revise the fonts for all samples | // 628 |
| /** | // 629 samples |
| * When the size or style changes, revise the fonts for all samples | // 630 samples |
| */ | // 631 samples |
| private void refontTheSamples() { | // 632 samples |
| // get current status | // 633 samples |
| int selectedRow = getSelectedRow(); | // 634 samples |
| int selectedCol = getSelectedColumn(); | // 635 cellfocus |
| int oldRowHeight = getRowHeight(); | // 636 rowheight |
| // record viewRect before it is overwritten by changeSelection() | // 637 rowvis |
| JViewport vp = scrollTable.getViewport(); | // 638 rowvis |
| Rectangle viewRect = vp.getViewRect(); // the visible rectangle | // 639 rowvis |
| // fetch the parameters for new fonts | // 640 samples |
| int fontsize = INITIALFONTSIZE; | // 641 samples |
| int fontsize = sizeModel.getNumber().intValue(); | // 642 samples&picksize |
| int styleInt = Font.PLAIN; | // 643 samples |
| int styleInt = styleValues[styles.getSelectedIndex()]; | // 644 samples&pickstyle |
| // 645 samples |
| // replace the fonts in all samples | // 646 samples |
| for (int inx = 0; inx < fontList.length; inx++) { | // 647 samples |
| JLabel lbl = (JLabel)tableData.getValueAt(inx, sampleColIndex); | // 648 samples |
| lbl.setFont(new Font(fontList[inx].getFontName(), styleInt, fontsize)); | // 649 samples |
| Font newf = new SampleFont(fontList[inx] | // 650 fontedsamples |
| .deriveFont(styleInt, (float)fontsize)); | // 651 fontedsamples |
| tableData.setValueAt(newf, inx, sampleColIndex); | // 652 fontedsamples |
| } | // 653 samples |
| // 654 samples |
| // choose a table row height appropriate to fontsize | // 655 rowheight |
| int newRowHeight = Math.max(INITIALFONTSIZE - 4, fontsize ) | // 656 rowheight |
| +ADDFORROWHEIGHT; | // 657 rowheight |
| // 658 rowheight |
| // FontsTable.refontTheSamples() adjust view: reinstate the selection and scroll to keep same view | // 659 |
| // if selected cell was visible, | // 660 rowvis |
| // scroll so it shows closw to where it was | // 661 rowvis |
| // but if it was offscreen, | // 662 rowvis |
| // scroll to keep the top line where it was | // 663 rowvis |
| int toprow; | // 664 rowvis |
| if (selectedRow == -1) | // 665 rowvis |
| // no selection, retain existing top row | // 666 rowvis |
| toprow = rowAtPoint(new Point(0, viewRect.y)); | // 667 rowvis |
| else { | // 668 rowvis |
| // return the focus to the selected cell, if any | // 669 cellfocus |
| // (JTable turns on autoscrolls, but it scrolls twice: | // 670 cellfocus |
| // here and in setViewPosition() below) | // 671 cellfocus |
| setAutoscrolls(false); // momentarily block autoscrolls | // 672 cellfocus&noflash |
| changeSelection(selectedRow, selectedCol, false, false); | // 673 cellfocus |
| setAutoscrolls(true); // re-enable autoscrolls | // 674 cellfocus&noflash |
| // 675 cellfocus |
| Rectangle s // the location of the selectedRow | // 676 rowvis |
| = getCellRect(selectedRow, 0, true); | // 677 rowvis |
| if (s.y+s.height - SLIVER < viewRect.y | // 678 rowvis |
| || s.y > viewRect.y+viewRect.height - SLIVER) | // 679 rowvis |
| // the selection was not in the view, retain existing top row | // 680 rowvis |
| toprow = rowAtPoint(new Point(0, viewRect.y)); | // 681 rowvis |
| else { | // 682 rowvis |
| // scroll selectedRow to near its old position on the screen | // 683 rowvis |
| int offset = s.y - viewRect.y; | // 684 rowvis |
| toprow = selectedRow | // 685 rowvis |
| - (offset-SLIVER) / (INITIALFONTSIZE+ADDFORROWHEIGHT); | // 686 rowvis |
| toprow = selectedRow - (offset-SLIVER) / newRowHeight; | // 687 rowvis&rowheight |
| } | // 688 rowvis |
| } | // 689 rowvis |
| setRowHeight(newRowHeight); // change view geometry ! | // 690 rowheight |
| int yTop = getCellRect(toprow, 0, true).y; | // 691 rowvis |
| vp.setViewPosition(new Point(0, yTop)); | // 692 rowvis |
| // 693 rowvis |
| // end FontsTable.refontTheSamples() adjust view: reinstate the selection and scroll to keep same view | // 694 |
| // the focus has moved to the sizes or styles widget | // 695 cellfocus |
| // return the focus to the table | // 696 cellfocus |
| requestFocusInWindow(); | // 697 cellfocus |
| // 698 cellfocus |
| repaint(); // re-render all (to get new samples displayed) | // 699 samples |
| } // end refontTheSamples | // 700 samples |
| // 701 samples |
| // end FontsTable.refontTheSamples() : when the size or style changes, revise the fonts for all samples | // 702 |
| // FontsTable.reviseSamples() : after the sampletext has changed in the DemoText, revise all samples | // 703 |
| /** sample text has changed, trigger a repaint of all sample cells.*/ | // 704 sampletext&samples |
| private void reviseSamples() { | // 705 sampletext&samples |
| for (int inx = 0; inx < fontList.length; inx++) // cause repaint | // 706 sampletext&samples |
| tableData.fireTableCellUpdated(inx, sampleColIndex); | // 707 sampletext&samples |
| } | // 708 sampletext&samples |
| // 709 sampletext&samples |
| // end FontsTable.reviseSamples() : after the sampletext has changed in the DemoText, revise all samples | // 710 |
| // FontsTable.cancelEditing() : called when any open cell editor should be closed | // 711 |
| /** | // 712 celled&canceledit |
| * Close any open cell editor | // 713 celled&canceledit |
| */ | // 714 celled&canceledit |
| public void cancelEditing() { | // 715 celled&canceledit |
| CellEditor ed = getCellEditor(); | // 716 celled&canceledit |
| if (ed != null) | // 717 celled&canceledit |
| ed.stopCellEditing(); | // 718 celled&canceledit |
| } | // 719 celled&canceledit |
| // 720 celled&canceledit |
| // end FontsTable.cancelEditing() : called when any open cell editor should be closed | // 721 |
| // FontsTable.saveCats() : if categories have changed, rebuild the map and save it | // 722 |
| /** Save the categories file. | // 723 savecats |
| * If it has changed. | // 724 mapchanged |
| * Reconstruct the contents of a categories list, | // 725 savecats |
| * from table columns CATCOL and FONTCOL. | // 726 savecats |
| * Call cancelEditing() before saveCats() (except from timer task). | // 727 savecats&canceledit |
| */ | // 728 savecats |
| protected void saveCats() { | // 729 savecats |
| // rebuild the catsMap | // 730 savecats |
| for (int inx = 0; inx < tableData.getRowCount(); inx++) { | // 731 savecats |
| String cat = (String) tableData.getValueAt(inx, catColIndex); | // 732 savecats |
| if (cat == null) cat = ""; | // 733 savecats |
| String styl = (String)tableData.getValueAt(inx, styleColIndex); | // 734 savecats&styles |
| if (cat.length() == 0) | // 735 savecats |
| if (styl.length() + cat.length() == 0) | // 736 savecats&styles |
| continue; // not saving blank entries | // 737 savecats |
| cat = styl + "; " + cat; | // 738 savecats&styles |
| String lbl = fontList[inx].getFontName(); | // 739 savecats |
| catsMap.put(lbl, cat); | // 740 savecats |
| } | // 741 savecats |
| catsMap.save(); | // 742 savecats |
| } | // 743 savecats |
| // end FontsTable.saveCats() : if categories have changed, rebuild the map and save it | // 744 |
| // end FontsTable methods | // 745 |
| // FontsTable - support classes | // 746 |
| // 747 table&comments |
| // 748 table&comments |
| ////////////////////////////////////////// | // 749 table&comments |
| // Classes for FontsTable | // 750 table&comments |
| // 751 table&comments |
| // FontsTable.SampleFont -a Font subclass with the right toString() value | // 752 |
| /** | // 753 fontedsamples |
| * The samples column is an array of Font objects, | // 754 fontedsamples |
| * If the user types ctl-C to copy a samples column cell, | // 755 fontedsamples |
| * the value later pasted will be from Font.toString(). Not useful. | // 756 fontedsamples |
| * SampleFont.toString() returns the String that actually appears | // 757 fontedsamples |
| */ | // 758 fontedsamples |
| class SampleFont extends Font { | // 759 fontedsamples |
| public SampleFont(Font f) { super(f); } | // 760 fontedsamples |
| @Override public String toString() | // 761 fontedsamples |
| { return currentSample; } | // 762 fontedsamples |
| } | // 763 fontedsamples |
| // 764 fontedsamples |
| // end FontsTable.SampleFont -a Font subclass with the right toString() value | // 765 |
| // FontsTable.FTStringRenderer -a Font subclass for rendering categories and fontnames | // 766 |
| /** RFender a table cell with my chosen font and border. */ | // 767 table |
| class FTStringRenderer extends DefaultTableCellRenderer { | // 768 table |
| @Override | // 769 table |
| public Component getTableCellRendererComponent( | // 770 table |
| JTable table, | // 771 table |
| Object value, // the Font for this sample cell | // 772 table |
| boolean isSelected, boolean hasFocus, | // 773 table |
| int row, int column) { | // 774 table |
| setText((String)value); | // 775 table |
| setFont(labelFont); | // 776 table |
| setBorder(hasFocus ? borderBlue : cellBorder); | // 777 table |
| setForeground(hasFocus ? Color.BLUE : Color.BLACK); | // 778 table |
| return this; | // 779 table |
| } | // 780 table |
| } | // 781 table |
| // 782 table |
| // end FontsTable.FTStringRenderer -a Font subclass for rendering categories and fontnames | // 783 |
| // FontsTable.FTFontRenderer - render the sample text; the data is actually the Font object | // 784 |
| // /** render the samples column; | // 785 samples |
| // * show the sampletext in the row's named Font. */ | // 786 samples |
| class FTJLabelRenderer extends DefaultTableCellRenderer { | // 787 samples |
| class FTFontRenderer extends DefaultTableCellRenderer { | // 788 fontedsamples |
| @Override | // 789 samples |
| public Component getTableCellRendererComponent( | // 790 samples |
| JTable table, | // 791 samples |
| Object value, // the Font for this sample cell | // 792 samples |
| boolean isSelected, boolean hasFocus, | // 793 samples |
| int row, int column) { // these parameters are ignored | // 794 samples |
| JLabel renderer = (JLabel)value; | // 795 samples |
| JLabel renderer = this; // (DefaultTableCellRenderer extends JLabel) | // 796 fontedsamples |
| if (scrollTable.getVerticalScrollBar().getValueIsAdjusting()) { | // 797 samples&fastscroll |
| renderer.setText(""); // defer rendering to accelerate scrolling | // 798 samples&fastscroll |
| renderer.setBorder(cellBorder); | // 799 samples&fastscroll |
| } | // 800 samples&fastscroll |
| else { | // 801 samples&fastscroll |
| renderer.setText(currentSample); | // 802 samples |
| renderer.setFont((Font)value); | // 803 fontedsamples |
| renderer.setBorder(hasFocus ? borderBlue : cellBorder); | // 804 samples |
| renderer.setForeground(hasFocus ? Color.BLUE : Color.BLACK); | // 805 samples |
| } | // 806 samples&fastscroll |
| return renderer; | // 807 samples |
| } | // 808 samples |
| } | // 809 samples |
| // end FontsTable.FTFontRenderer - render the sample text; the data is actually the Font object | // 810 |
| // FontsTable.FTHeaderRenderer - render the column headers idiosyncratically | // 811 |
| /** Render column headings. | // 812 bettersort |
| * Omit the "sorting arrow"; we always sort ascending | // 813 bettersort |
| * Color the header background during the sort | // 814 bettersort |
| */ | // 815 bettersort |
| class FTHeaderRenderer extends DefaultTableCellRenderer { | // 816 bettersort |
| @Override | // 817 bettersort |
| public Component getTableCellRendererComponent( | // 818 bettersort |
| JTable table, Object value, boolean isSelected, | // 819 bettersort |
| boolean hasFocus, int row, int column) { | // 820 bettersort |
| int modelCol = convertColumnIndexToModel(column); | // 821 bettersort |
| setText(" "+(String)value); | // 822 bettersort |
| setOpaque(true); | // 823 bettersort |
| setFont(headerFont); | // 824 bettersort |
| setBackground(nowSorting==modelCol | // 825 bettersort |
| ? sortingHeaderBkgd : normalHeaderBkgd); | // 826 bettersort |
| setForeground(Color.BLUE); | // 827 bettersort |
| if (modelCol == styleColIndex) | // 828 bettersort&styles |
| setHorizontalAlignment(JLabel.CENTER); | // 829 bettersort&styles |
| return this; | // 830 bettersort |
| } | // 831 bettersort |
| /** the header looks better with a bottom line */ | // 832 bettersort |
| @Override | // 833 bettersort |
| protected void paintBorder(Graphics g) { | // 834 bettersort |
| g.drawLine(0, getHeight()-1, getWidth(), getHeight()-1); | // 835 bettersort |
| } | // 836 bettersort |
| } | // 837 bettersort |
| // 838 bettersort |
| // end FontsTable.FTHeaderRenderer - render the column headers idiosyncratically | // 839 |
| // FontsTable.FTCorner - draw an empty corner | // 840 |
| /** Draw an empty corner for the header/scrollbar intersection. | // 841 scrollcorner |
| same color and border as FTHeaderRenderer */ | // 842 scrollcorner |
| class FTCorner extends JPanel { | // 843 scrollcorner |
| @Override | // 844 scrollcorner |
| public void addNotify() { | // 845 scrollcorner |
| super.addNotify(); | // 846 scrollcorner |
| setOpaque(true); | // 847 scrollcorner |
| setBackground(normalHeaderBkgd); | // 848 scrollcorner |
| } | // 849 scrollcorner |
| @Override | // 850 scrollcorner |
| protected void paintBorder(Graphics g) { | // 851 scrollcorner |
| g.drawLine(0, getHeight()-1, getWidth(), getHeight()-1); | // 852 scrollcorner |
| } | // 853 scrollcorner |
| } // end FTCorner | // 854 scrollcorner |
| // 855 scrollcorner |
| // end FontsTable.FTCorner - draw an empty corner | // 856 |
| // FontsTable.FTChangeListener- listen to scroll bar changes to control repainting the samples | // 857 |
| /** listen to changes in the vertical scroll bar. | // 858 samples&fastscroll |
| * When it has stopped moving it sends a final change | // 859 samples&fastscroll |
| * with valueIsAdjusting false. We have not been rendering | // 860 samples&fastscroll |
| * the samples column while scrolling, so we render it now. | // 861 samples&fastscroll |
| */ | // 862 samples&fastscroll |
| class FTChangeListener | // 863 samples&fastscroll |
| implements javax.swing.event.ChangeListener { | // 864 samples&fastscroll |
| boolean moving = false; | // 865 samples&fasterscroll |
| public void stateChanged(javax.swing.event.ChangeEvent e) { | // 866 samples&fastscroll |
| if (scrollTable.getVerticalScrollBar().getValueIsAdjusting()) { | // 867 samples&fasterscroll |
| moving = true; | // 868 samples&fasterscroll |
| } | // 869 samples&fasterscroll |
| else { | // 870 samples&fasterscroll |
| if (moving && FontViewer.this.isDoubleBuffered()) { | // 871 samples&fasterscroll |
| // to avoid the long wait after scrolling, | // 872 samples&fasterscroll |
| // turn off double buffering while redrawing the samples | // 873 samples&fasterscroll |
| moving = false; | // 874 samples&fasterscroll |
| FontViewer.this.setDoubleBuffered(false); | // 875 samples&fasterscroll |
| FontViewer.this.getRootPane().setDoubleBuffered(false); | // 876 samples&fasterscroll |
| needToRestoreDoubleBuffering = true; | // 877 samples&fasterscroll |
| } | // 878 samples&fasterscroll |
| // scroll movement has stopped | // 879 samples&fastscroll |
| // must repaint all visible elements in SAMPLE column | // 880 samples&fastscroll |
| JViewport vp = scrollTable.getViewport(); | // 881 samples&fastscroll |
| Rectangle viewRect = vp.getViewRect(); | // 882 samples&fastscroll |
| int sampCol = mainTable | // 883 samples&fastscroll |
| .convertColumnIndexToView(sampleColIndex); | // 884 samples&fastscroll |
| Rectangle cr = mainTable.getCellRect(0, sampCol, true); | // 885 samples&fastscroll |
| scrollTable.repaint(0, cr.x, 0, | // 886 samples&fastscroll |
| cr.width, viewRect.height + cr.height); | // 887 samples&fastscroll |
| } | // 888 samples&fasterscroll |
| } | // 889 samples&fastscroll |
| } | // 890 samples&fastscroll |
| // 891 samples&fastscroll |
| // end FontsTable.FTChangeListener- listen to scroll bar changes to control repainting the samples | // 892 |
| // FontsTable.FTPasteAction - Action for pasting into category cells | // 893 |
| /** An Action for pasting values into the category cells */ | // 894 ctlv |
| class FTPasteAction extends AbstractAction { | // 895 ctlv |
| @Override | // 896 ctlv |
| public void actionPerformed(ActionEvent e) { | // 897 ctlv |
| // be sure focused cell is in CATCOL | // 898 ctlv |
| ListSelectionModel selmod | // 899 ctlv |
| = getColumnModel().getSelectionModel(); | // 900 ctlv |
| int viewcol = selmod.getLeadSelectionIndex(); | // 901 ctlv |
| int modcol = convertColumnIndexToModel(viewcol); | // 902 ctlv |
| if (catColIndex != modcol) | // 903 ctlv |
| return; // lead cell is not in CATCOL | // 904 ctlv |
| // 905 ctlv |
| // copy the cutbuffer into sink, a temp | // 906 ctlv |
| sink.setText(""); | // 907 ctlv |
| pasteSinkAction.actionPerformed( | // 908 ctlv |
| new ActionEvent(sink, TransferHandler.COPY, "")); | // 909 ctlv |
| // 910 ctlv |
| // copy from sink to the label | // 911 ctlv |
| String text = sink.getText(); | // 912 ctlv |
| int viewrow = getSelectionModel().getLeadSelectionIndex(); | // 913 ctlv |
| int modrow = convertRowIndexToModel(viewrow); | // 914 ctlv |
| setValueAt(text, viewrow, viewcol); | // 915 ctlv |
| repaint(getCellRect(viewrow, viewcol, true)); | // 916 ctlv |
| } | // 917 ctlv |
| } | // 918 ctlv |
| // end FontsTable.FTPasteAction - Action for pasting into category cells | // 919 |
| // FontsTable.FTRowSorter - sort rows | // 920 |
| /** | // 921 sort |
| * Specialized sorting routines. Strings in ascending order | // 922 sort |
| * and checkboxes sort the checked boxes first. | // 923 sort |
| */ | // 924 sort |
| private class FTRowSorter | // 925 sort |
| extends TableRowSorter<DefaultTableModel>{ | // 926 sort |
| FTRowSorter(DefaultTableModel tmodel) { | // 927 sort |
| super(tmodel); | // 928 sort |
| } | // 929 sort |
| /** Comparators | // 930 sort |
| * @param column which column | // 931 sort |
| * @return appropriate Comparator | // 932 sort |
| */ | // 933 sort |
| @Override | // 934 sort |
| public Comparator getComparator(int column) { | // 935 sort |
| if (column == chkColIndex) | // 936 sort&checkboxes |
| return new Comparator<Boolean>() { | // 937 sort&checkboxes |
| @Override | // 938 sort&checkboxes |
| public int compare(Boolean o1, Boolean o2) { | // 939 sort&checkboxes |
| // reverse compare to favor checked boxes | // 940 sort&checkboxes |
| return o2.compareTo(o1); | // 941 sort&checkboxes |
| } | // 942 sort&checkboxes |
| }; | // 943 sort&checkboxes |
| if (column == sampleColIndex) | // 944 sort&samples |
| return null; | // 945 sort&samples |
| return new Comparator<String>() { | // 946 sort |
| @Override | // 947 sort |
| public int compare(String o1, String o2) { | // 948 sort |
| return o1.compareToIgnoreCase(o2); | // 949 sort |
| } | // 950 sort |
| }; | // 951 sort |
| } | // 952 sort |
| @Override | // 953 sort |
| protected boolean useToString(int column) { return false; } | // 954 sort |
| @Override | // 955 sort |
| public boolean isSortable(int column) { | // 956 sort |
| return true; | // 957 sort |
| return column != sampleColIndex; | // 958 sort&samples |
| } | // 959 sort |
| // 960 sort |
| // FontsTable.FTRowSorter.setSortKeys - call proper low level routines to choose sort order | // 961 |
| /** Normal sort has two problems: | // 962 bettersort |
| // a) if the table has been sorted on a column. | // 963 bettersort |
| // reclicking the header does not sort again | // 964 bettersort |
| // b) each sort is in the opposite direction, | // 965 bettersort |
| // this is not useful for fonts, so we sort always ascending | // 966 bettersort |
| // this override of setSortKeys fixes both problems | // 967 bettersort |
| */ | // 968 bettersort |
| @Override | // 969 sort |
| public void setSortKeys( | // 970 sort |
| java.util.List<? extends SortKey>keys) { | // 971 sort |
| cancelEditing(); // save any in-progress category edit | // 972 sort&canceledit |
| super.setSortKeys(keys); | // 973 sort |
| java.util.List<SortKey> copy | // 974 bettersort |
| = new ArrayList<SortKey>(keys.size()); | // 975 bettersort |
| for (SortKey k : keys) | // 976 bettersort |
| copy.add(new SortKey(k.getColumn(), | // 977 bettersort |
| SortOrder.ASCENDING)); | // 978 bettersort |
| // during the sort, the column header changes color | // 979 bettersort |
| // the column number in the sortkey is per the model | // 980 bettersort |
| nowSorting = copy.get(0).getColumn(); | // 981 bettersort |
| FontsTable.this.getTableHeader() | // 982 bettersort |
| .paintImmediately(0,0,99999,99999); | // 983 bettersort |
| // 984 bettersort |
| java.util.List<SortKey>newSortKeys | // 985 bettersort |
| = Collections.unmodifiableList(copy); | // 986 bettersort |
| if (getSortKeys().equals(newSortKeys)) | // 987 bettersort |
| allRowsChanged(); // force a sort | // 988 bettersort |
| else | // 989 bettersort |
| super.setSortKeys(copy); // this does the actual sort | // 990 bettersort |
| // 991 bettersort |
| javax.swing.SwingUtilities.invokeLater(new Runnable() { | // 992 bettersort |
| @Override | // 993 bettersort |
| public void run() { | // 994 bettersort |
| nowSorting = -1; // turn off header color | // 995 bettersort |
| FontsTable.this.getTableHeader() | // 996 bettersort |
| .paintImmediately(0,0,99999,99999); | // 997 bettersort |
| } | // 998 bettersort |
| }); | // 999 bettersort |
| } // end setSortKeys | // 1000 sort |
| } // end FTPRowSorter | // 1001 sort |
| // end FontsTable.FTRowSorter.setSortKeys - call proper low level routines to choose sort order | // 1002 |
| // end FontsTable.FTRowSorter - sort rows | // 1003 |
| // end FontsTable - support classes | // 1004 |
| } // end class FontsTable | // 1005 table |
| // 1006 table |
| // end FontsTable - class : the central JTable for the application | // 1007 |
| // StringMap - class : a HashMap mapping from fontname to category | // 1008 |
| // 1009 stringmap |
| // 1010 stringmap |
| /////////////////////////////////////// | // 1011 stringmap |
| // String Map | // 1012 stringmap |
| // 1013 stringmap |
| /** Maintain a map from strings to strings. | // 1014 stringmap |
| * The file format has key and value, separated with a colon. | // 1015 stringmap |
| * Keys and values are each trim()ed to remove outer whitespace. | // 1016 stringmap |
| * In keys, colons are converted to question marks.. | // 1017 stringmap |
| */ | // 1018 stringmap |
| static public class StringMap extends HashMap<String, String> { | // 1019 stringmap |
| String catSrc = null; // where to get the categories file | // 1020 readcats |
| boolean mutable = true; // FVApplet wil set this false | // 1021 savecats |
| String catDest = null; // file to save revised categories | // 1022 savecats |
| boolean changed = false; // set to true by mapChanged() | // 1023 savecats |
| // and back to false by save() | // 1024 savecats |
| // 1025 readcats |
| StringMap() {} | // 1026 stringmap |
| /** Create a StringMap with a given source location. | // 1027 readcats |
| * @param name Name of the data source. | // 1028 readcats |
| * May be null to use the default map. | // 1029 readcats |
| */ | // 1030 readcats |
| public StringMap(String name) { | // 1031 readcats |
| catSrc = name; | // 1032 readcats |
| } | // 1033 readcats |
| // 1034 readcats |
| /** called by FVApplet to prevent trying to write to disk */ | // 1035 savecats |
| void readOnly() { mutable = false; } | // 1036 savecats |
| // 1037 savecats |
| /** | // 1038 mapchanged |
| * The category map has changed (for the first time). | // 1039 mapchanged |
| * Determine if and where to save the result. If necessary | // 1040 mapchanged |
| * and appropriate, prompt the user for a save location | // 1041 mapchanged |
| */ | // 1042 mapchanged |
| void mapChanged() { | // 1043 mapchanged |
| if (changed) return; | // 1044 mapchanged |
| changed = true; | // 1045 mapchanged |
| if (catDest != null) | // 1046 mapchanged |
| return; // catSrc is a file; save will replace that file | // 1047 mapchanged |
| String msg = (mutable) | // 1048 mapchanged |
| ? "Category changes will not be saved until\n" | // 1049 mapchanged |
| + "a file is picked via \"Save As\" in the File menu." | // 1050 mapchanged |
| : "FontViewer cannot save category\n" | // 1051 mapchanged |
| + "changes when run as an applet"; | // 1052 mapchanged |
| JOptionPane.showMessageDialog(null, msg, | // 1053 mapchanged |
| "Warning", JOptionPane.WARNING_MESSAGE); | // 1054 mapchanged |
| } | // 1055 mapchanged |
| // 1056 mapchanged |
| void promptForCatDest() { | // 1057 filechooser |
| // prompt for save file location | // 1058 filechooser |
| JFileChooser chooser = new JFileChooser(); | // 1059 filechooser |
| chooser.setDialogTitle("Choose a file for the categories list"); | // 1060 filechooser |
| chooser.setSelectedFile(new File("categories.txt")); | // 1061 filechooser |
| chooser.setApproveButtonText("Save"); | // 1062 filechooser |
| chooser.setApproveButtonToolTipText( | // 1063 filechooser |
| "Choose now a file to later<br>" | // 1064 filechooser |
| + "store a revised categories.txt"); | // 1065 filechooser |
| if (chooser.showOpenDialog(null) | // 1066 filechooser |
| == JFileChooser.APPROVE_OPTION) { | // 1067 filechooser |
| catDest = chooser.getSelectedFile().getAbsolutePath(); | // 1068 filechooser |
| mutable = true; | // 1069 filechooser |
| } | // 1070 filechooser |
| } | // 1071 filechooser |
| // 1072 filechooser |
| void errorAlert(String msg) { | // 1073 readcats |
| JOptionPane.showMessageDialog(null, msg, | // 1074 readcats |
| "Categories file error", JOptionPane.ERROR_MESSAGE); | // 1075 readcats |
| catDest = null; | // 1076 savecats |
| } | // 1077 readcats |
| // 1078 readcats |
| // StringMap.getReader() : parses category file/URL name and opens the stream | // 1079 |
| /** | // 1080 readcats |
| * Parse the src value and open a Reader on the data describes. | // 1081 readcats |
| * Possible syntaxes: | // 1082 readcats |
| * resource:name - look for name as a file among the class files | // 1083 readcats |
| * the default is resource:categories.txt | // 1084 readcats |
| * data:,xxxxx ... - category pairs are embedded in src itself | // 1085 readcats |
| * xxxxx is a sequence of lines, each having | // 1086 readcats |
| * fontname,':', category, and a newline | // 1087 readcats |
| * URI - scheme://.... - open the URI | // 1088 readcats |
| * else - assume file name; open the file | // 1089 readcats |
| * If src fails to open, an IOException is thrown. | // 1090 readcats |
| * catDest is set if the data comes from a file. | // 1091 savecats |
| * @param src The location to read from, as noted above | // 1092 readcats |
| * @return an InputStream for reading the category file | // 1093 readcats |
| * @throws IOException if an error occurs in opening the src | // 1094 readcats |
| */ | // 1095 readcats |
| Reader getReader(String src) throws IOException { | // 1096 readcats |
| // To match URI schemes and not Windows drive letter, | // 1097 readcats |
| // the scheme name is expected to be at least two letters. | // 1098 readcats |
| Pattern uripat = Pattern.compile( | // 1099 readcats |
| "\\A" // start of string | // 1100 readcats |
| + "([a-zA-Z][a-zA-Z]+)" // scheme name | // 1101 readcats |
| + "\\:(" // "colon" and start scheme-specific group 2 | // 1102 readcats |
| + "([^,]*,)?" // optional group 3: data: stream controls | // 1103 readcats |
| + "(.*)" // group 4, the data area of a "data:" URI | // 1104 readcats |
| + ")\\Z", // end group 2, end of string | // 1105 readcats |
| Pattern.DOTALL | Pattern.MULTILINE); | // 1106 readcats |
| java.util.regex.Matcher urimat = uripat.matcher(src); | // 1107 readcats |
| if (urimat.matches()) { | // 1108 readcats |
| String scheme = urimat.group(1); | // 1109 readcats |
| if (scheme.equalsIgnoreCase("resource")) { | // 1110 readcats |
| InputStream cis = FontViewer.class | // 1111 readcats |
| .getResourceAsStream(urimat.group(2)); | // 1112 readcats |
| return new BufferedReader(new InputStreamReader(cis)); | // 1113 readcats |
| } | // 1114 readcats |
| else if(scheme.equalsIgnoreCase("data")) | // 1115 readcats |
| return new StringReader(urimat.group(4)); | // 1116 readcats |
| else | // 1117 readcats |
| return new InputStreamReader( | // 1118 readcats |
| new java.net.URL(src).openStream()); | // 1119 readcats |
| } | // 1120 readcats |
| else { | // 1121 readcats |
| Reader rdr = new FileReader(catSrc); | // 1122 readcats |
| catDest = catSrc; // created FileReader, so catsrc exists | // 1123 savecats |
| return rdr; | // 1124 readcats |
| } | // 1125 readcats |
| } | // 1126 readcats |
| // 1127 readcats |
| // endStringMap.getReader() : parses category file/URL name and opens the stream | // 1128 |
| // StringMap.read() : reads from a BufferedReader to populate the StringMap | // 1129 |
| public void read() { | // 1130 readcats |
| if (catSrc != null) { | // 1131 readcats |
| if (readFromSource(catSrc)) | // 1132 readcats |
| return; | // 1133 readcats |
| } | // 1134 readcats |
| // catSrc failed, try the default | // 1135 readcats |
| catSrc = catsDefaultFile; | // 1136 readcats |
| readFromSource(catSrc); | // 1137 readcats |
| } | // 1138 readcats |
| // 1139 readcats |
| public boolean readFromSource(String src) { | // 1140 readcats |
| BufferedReader brdr = null; | // 1141 readcats |
| try { | // 1142 readcats |
| brdr = new BufferedReader(getReader(src)); | // 1143 readcats |
| // read from brdr | // 1144 readcats |
| String line; | // 1145 readcats |
| while (true) { | // 1146 readcats |
| line = brdr.readLine(); | // 1147 readcats |
| if (line == null) break; | // 1148 readcats |
| int colx = line.indexOf(':'); | // 1149 readcats |
| if (colx < 0) continue; | // 1150 readcats |
| put(line.substring(0, colx).trim(), // key before the colon | // 1151 readcats |
| line.substring(colx + 1).trim()); // and value after it | // 1152 readcats |
| } | // 1153 readcats |
| } | // 1154 readcats |
| catch (IOException ex) { | // 1155 readcats |
| errorAlert("Failed reading categories from " + src); | // 1156 readcats |
| catSrc = null; | // 1157 readcats |
| catDest = null; | // 1158 savecats |
| return false; | // 1159 readcats |
| } | // 1160 readcats |
| finally { | // 1161 readcats |
| if (brdr != null) try { brdr.close(); } catch (IOException ex){} | // 1162 readcats |
| } | // 1163 readcats |
| return true; | // 1164 readcats |
| } | // 1165 readcats |
| // 1166 readcats |
| // end StringMap.read() : reads from a BufferedReader to populate the StringMap | // 1167 |
| // StringMap.getWriter() : opens the inputfile for revision, or prompts user for file | // 1168 |
| /** | // 1169 savecats |
| * Open an output writer to save the categories file. | // 1170 savecats |
| * catDest has already been checked as non-null | // 1171 savecats |
| * @return The output stream, or null if catDest is not valid | // 1172 savecats |
| */ | // 1173 savecats |
| Writer getWriter() { | // 1174 savecats |
| Writer os = null; | // 1175 savecats |
| try { | // 1176 savecats |
| os = new FileWriter(catDest); | // 1177 savecats |
| } catch(Exception ex) { | // 1178 savecats |
| errorAlert("Cannot write to " + catDest); | // 1179 savecats |
| catDest = null; | // 1180 savecats |
| } // if error, os remains null; | // 1181 savecats |
| return os; // may be null for error | // 1182 savecats |
| } | // 1183 savecats |
| // 1184 savecats |
| // endStringMap.getWriter() : opens the inputfile for revision, or prompts user for file | // 1185 |
| // StringMap.save() : writes the StringMap back to a file or stdout | // 1186 |
| /** | // 1187 savecats |
| * Save the map to the place where it came from. | // 1188 savecats |
| */ | // 1189 savecats |
| public void save() { | // 1190 savecats |
| if (catDest == null) | // 1191 savecats |
| return; | // 1192 savecats |
| BufferedWriter bwtr = null; | // 1193 savecats |
| int n = 0; | // 1194 savecats |
| try { | // 1195 savecats |
| bwtr = new BufferedWriter(getWriter()); | // 1196 savecats |
| n = saveToWriter(bwtr); | // 1197 savecats |
| } catch (Exception ex) { | // 1198 savecats |
| errorAlert("Failed saving font categories to " | // 1199 savecats |
| + catDest + ": " + ex.getLocalizedMessage()); | // 1200 savecats |
| } | // 1201 savecats |
| finally { | // 1202 savecats |
| try { | // 1203 savecats |
| if (bwtr != null) { | // 1204 savecats |
| changed = false; | // 1205 savecats |
| bwtr.close(); | // 1206 savecats |
| } | // 1207 savecats |
| System.out.println("Saved " + n | // 1208 savecats |
| + " font categories data to " + catDest); | // 1209 savecats |
| } catch(IOException ex) {} | // 1210 savecats |
| } | // 1211 savecats |
| } | // 1212 savecats |
| // 1213 savecats |
| /** | // 1214 savecats |
| * Save the StringMap data to a given stream. | // 1215 savecats |
| * Only Entries which map to non-empty strings are saved. | // 1216 savecats |
| * @param bwr Where to send the StringMap entries. | // 1217 savecats |
| * @return The number of lines written to bwr.. | // 1218 savecats |
| * @throws IOException | // 1219 savecats |
| */ | // 1220 savecats |
| public int saveToWriter(BufferedWriter bwr) throws IOException { | // 1221 savecats |
| int n = 0; | // 1222 savecats |
| ArrayList<java.util.Map.Entry<String, String>> entries | // 1223 savecats |
| = new ArrayList<java.util.Map.Entry<String, String>> | // 1224 savecats |
| (entrySet()); | // 1225 savecats |
| Collections.sort(entries, | // 1226 sortmap |
| new Comparator<java.util.Map.Entry<String, String>>() { | // 1227 sortmap |
| @Override | // 1228 sortmap |
| public int compare(java.util.Map.Entry<String, String> o1, | // 1229 sortmap |
| java.util.Map.Entry<String, String> o2) { | // 1230 sortmap |
| return o1.getKey().compareToIgnoreCase(o2.getKey()); | // 1231 sortmap |
| } | // 1232 sortmap |
| }); | // 1233 sortmap |
| for (java.util.Map.Entry<String, String> e : entries) { | // 1234 savecats |
| String key = e.getKey(); | // 1235 savecats |
| String val = e.getValue(); | // 1236 savecats |
| if (val == null || val.length() == 0) | // 1237 savecats |
| continue; // skip entries that map font name to blank | // 1238 savecats |
| bwr.write(key + " : " + val); | // 1239 savecats |
| bwr.newLine(); | // 1240 savecats |
| n++; | // 1241 savecats |
| } | // 1242 savecats |
| return n; | // 1243 savecats |
| } // end save() | // 1244 savecats |
| // end StringMap.save() : writes the StringMap back to a file or stdout | // 1245 |
| } // end class StringMap | // 1246 stringmap |
| // 1247 stringmap |
| // end StringMap - class : a HashMap mapping from fontname to category | // 1248 |
| // FontViewer.addMenuItem() common code for making menu items | // 1249 |
| /** | // 1250 menu |
| * Add a menu item to a menu, and set its listener and code. | // 1251 menu |
| * @param menu The destination menu or menubar. | // 1252 menu |
| * @param name The name that will appear in the menu item. | // 1253 menu |
| * @param ear Listener to be called when the menu item is selected. | // 1254 menu |
| * @param mnemonic Which key will select this menu item. | // 1255 menu |
| * @param cmd String that will be available to the ActionListener | // 1256 menu |
| * as the actionCommand. | // 1257 menu |
| */ | // 1258 menu |
| static JMenuItem addMenuItem(JComponent menu, String name, | // 1259 menu |
| ActionListener ear, int mnemonic, String cmd) { | // 1260 menu |
| JMenuItem item = new JMenuItem(name, mnemonic); | // 1261 menu |
| item.setActionCommand(cmd); | // 1262 menu |
| item.addActionListener(ear); | // 1263 menu |
| menu.add(item); | // 1264 menu |
| return item; | // 1265 menu |
| } | // 1266 menu |
| // 1267 menu |
| // end FontViewer.addMenuItem() common code for making menu items | // 1268 |
| // 1269 backbone |
| // 1270 backbone |
| /////////////////////////////////////// | // 1271 backbone |
| // main() | // 1272 backbone |
| // 1273 backbone |
| // FontViewer.main() : the main program if FontViewer is not an applet or part of a larger application | // 1274 |
| /** Run this application | // 1275 backbone |
| * @param args If given, the location of initial StringMap categories | // 1276 backbone |
| */ | // 1277 backbone |
| public static void main(String[] args) { | // 1278 backbone |
| // 1279 backbone |
| FontViewer.printFontList(System.out); | // 1280 offline |
| // 1281 offline |
| // The default UI is "metal." Its design for the`sizes' JSpinner is ugly | // 1282 laf |
| // So we use the native look and feel.. | // 1283 laf |
| try { | // 1284 laf |
| String className | // 1285 laf |
| = UIManager.getSystemLookAndFeelClassName(); | // 1286 laf |
| UIManager.setLookAndFeel(className); | // 1287 laf |
| } catch (Exception cnf) {} // unlikely and not vital, ignore the error | // 1288 laf |
| // 1289 laf |
| // where to read the font categories info | // 1290 readcats |
| String categoryFile | // 1291 readcats |
| = (args.length > 0) ? args[0] : null; | // 1292 readcats |
| /* sample values for categoryFile: | // 1293 readcats |
| = "data:,Accent:Odd Bold\nAgency FB:Sans B T\n"; | // 1294 readcats |
| = "http://physpics.com/Java/apps/FontViewer/fontcategories.txt"; | // 1295 readcats |
| = "g:\\fred\\java\\FontViewer\\distsrc\\fontcategories.txt"; */ | // 1296 readcats |
| // Note: many fonts in the default fontcategories.txt are in cygwin | // 1297 readcats |
| // 1298 readcats |
| // create FontViewer to be tested | // 1299 window |
| final FontViewer subject = new FontViewer(); | // 1300 window |
| final FontViewer subject = new FontViewer(new StringMap()); | // 1301 stringmap |
| final StringMap cats = new StringMap(categoryFile); | // 1302 readcats |
| cats.read(); | // 1303 readcats |
| final FontViewer subject = new FontViewer(cats); | // 1304 readcats |
| // 1305 window |
| final JFrame frame = new JFrame(" Font Viewer"); | // 1306 window |
| frame.setContentPane(subject); | // 1307 window |
| frame.setIconImage(Toolkit.getDefaultToolkit().createImage( | // 1308 laf |
| FontViewer.class.getResource("images/FV16.png"))); | // 1309 laf |
| // 1310 window |
| JMenuBar menuBar = new JMenuBar(); | // 1311 menu |
| JMenu fileMenu = new JMenu("File"); | // 1312 menu |
| JMenuItem ti; | // 1313 menu |
| ti = addMenuItem(fileMenu, "Save Categories", | // 1314 menu&savecats |
| subject, KeyEvent.VK_S, "S"); | // 1315 menu&savecats |
| ti.setAccelerator( | // 1316 menu&savecats |
| KeyStroke.getKeyStroke(KeyEvent.VK_S, | // 1317 menu&savecats |
| InputEvent.CTRL_DOWN_MASK)); | // 1318 menu&savecats |
| addMenuItem(fileMenu, "Save As ...", subject, KeyEvent.VK_A, "A"); | // 1319 menu&filechooser |
| addMenuItem(fileMenu, "Exit", subject, KeyEvent.VK_X, "X"); | // 1320 menu&shut |
| menuBar.add(fileMenu); | // 1321 menu |
| JMenu helpMenu = new JMenu("Help"); | // 1322 menu |
| if (Desktop.isDesktopSupported() && Desktop | // 1323 menu |
| .getDesktop().isSupported(Desktop.Action.BROWSE)) { | // 1324 menu |
| ti = addMenuItem(helpMenu, "Help", | // 1325 menu |
| subject, KeyEvent.VK_H, "H"); | // 1326 menu |
| ti.setAccelerator(KeyStroke | // 1327 menu |
| .getKeyStroke(KeyEvent.VK_F1, 0)); | // 1328 menu |
| } | // 1329 menu |
| ti = new JMenuItem(subject.sampleEditor.resetAction); | // 1330 menu&resetaction |
| helpMenu.add(ti); | // 1331 menu&resetaction |
| menuBar.add(helpMenu); | // 1332 menu |
| frame.setJMenuBar(menuBar); | // 1333 menu |
| // 1334 menu |
| subject.startSaving(10*60*1000); // save categories every 10 min. | // 1335 savecats&autosave |
| // 1336 savecats&autosave |
| // FontViewer.main() - window closure : save the categories file | // 1337 |
| frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | // 1338 window |
| frame.setDefaultCloseOperation( | // 1339 shut |
| WindowConstants.DISPOSE_ON_CLOSE); | // 1340 shut |
| frame.addWindowListener(new WindowAdapter() { | // 1341 shut |
| void saveAndExit() { | // 1342 shut |
| subject.mainTable.cancelEditing(); | // 1343 shut&canceledit |
| if (cats.changed) { | // 1344 shut&savecats |
| if (cats.catDest == null) | // 1345 shut&savecats |
| cats.promptForCatDest(); | // 1346 shut&filechooser |
| subject.mainTable.saveCats(); | // 1347 shut&savecats |
| } | // 1348 shut&savecats |
| // exit only after all processing for the current event | // 1349 shut |
| java.awt.EventQueue.invokeLater( | // 1350 shut |
| new Runnable() { | // 1351 shut |
| @Override | // 1352 shut |
| public void run() { System.exit(0); } | // 1353 shut |
| }); | // 1354 shut |
| } | // 1355 shut |
| @Override | // 1356 shut |
| public void windowClosing(WindowEvent we) { | // 1357 shut |
| saveAndExit(); | // 1358 shut |
| } | // 1359 shut |
| @Override | // 1360 shut |
| public void windowClosed(WindowEvent we) { | // 1361 shut |
| saveAndExit(); | // 1362 shut |
| } | // 1363 shut |
| }); | // 1364 shut |
| // 1365 shut |
| // end FontViewer.main() - window closure : save the categories file | // 1366 |
| // FontViewer.main().invokeLater() : launch the application | // 1367 |
| javax.swing.SwingUtilities.invokeLater(new Runnable() { | // 1368 window |
| @Override | // 1369 window |
| public void run() { | // 1370 window |
| frame.setPreferredSize(new Dimension(725, 800)); | // 1371 window |
| frame.pack(); | // 1372 window |
| subject.mainTable.requestFocusInWindow(); | // 1373 window&table |
| frame.setVisible(true); | // 1374 window |
| } | // 1375 window |
| }); | // 1376 window |
| // end FontViewer.main().invokeLater() : launch the application | // 1377 |
| } // end method main() | // 1378 backbone |
| // end FontViewer.main() : the main program if FontViewer is not an applet or part of a larger application | // 1379 |
| } // end class FontViewer | // 1380 backbone |
| // end FontViewer class | // 1381 |
| // end FontViewer.java - Display system fonts, with a sample in each | // 1382 |