1 /* 2 * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 42 import java.awt.Color; 43 import java.awt.Component; 44 import java.awt.BorderLayout; 45 import java.awt.CheckboxGroup; 46 import java.awt.Container; 47 import java.awt.Dimension; 48 import java.awt.Font; 49 import java.awt.Graphics; 50 import java.awt.Graphics2D; 51 import java.awt.GraphicsEnvironment; 52 import java.awt.GridBagConstraints; 53 import java.awt.GridBagLayout; 54 import java.awt.GridLayout; 55 import java.awt.Insets; 56 import java.awt.RenderingHints; 57 import java.awt.Toolkit; 58 import java.awt.event.ActionEvent; 59 import java.awt.event.ActionListener; 60 import java.awt.event.ItemEvent; 61 import java.awt.event.ItemListener; 62 import java.awt.event.WindowAdapter; 63 import java.awt.event.WindowEvent; 64 import java.awt.image.BufferedImage; 65 import java.io.BufferedInputStream; 66 import java.io.BufferedOutputStream; 67 import java.io.File; 68 import java.io.FileInputStream; 69 import java.io.FileOutputStream; 70 import java.util.EnumSet; 71 import java.util.StringTokenizer; 72 import java.util.BitSet; 73 import javax.swing.*; 74 import javax.swing.event.*; 75 76 /** 77 * Font2DTest.java 78 * 79 * @author Shinsuke Fukuda 80 * @author Ankit Patel [Conversion to Swing - 01/07/30] 81 */ 82 83 /// Main Font2DTest Class 84 85 public final class Font2DTest extends JPanel 86 implements ActionListener, ItemListener, ChangeListener { 87 88 /// JFrame that will contain Font2DTest 89 private final JFrame parent; 90 /// FontPanel class that will contain all graphical output 91 private final FontPanel fp; 92 /// RangeMenu class that contains info about the unicode ranges 93 private final RangeMenu rm; 94 95 /// Other menus to set parameters for text drawing 96 private final ChoiceV2 fontMenu; 97 private final JTextField sizeField; 98 private final ChoiceV2 styleMenu; 99 private final ChoiceV2 textMenu; 100 private int currentTextChoice = 0; 101 private final ChoiceV2 transformMenu; 102 private final ChoiceV2 transformMenuG2; 103 private final ChoiceV2 methodsMenu; 104 private final JComboBox antiAliasMenu; 105 private final JComboBox fracMetricsMenu; 106 107 private final JSlider contrastSlider; 108 109 /// CheckboxMenuItems 110 private CheckboxMenuItemV2 displayGridCBMI; 111 private CheckboxMenuItemV2 force16ColsCBMI; 112 private CheckboxMenuItemV2 showFontInfoCBMI; 113 114 /// JDialog boxes 115 private JDialog userTextDialog; 116 private JTextArea userTextArea; 117 private JDialog printDialog; 118 private JDialog fontInfoDialog; 119 private LabelV2[] fontInfos = new LabelV2[2]; 120 private JFileChooser filePromptDialog = null; 121 122 private ButtonGroup printCBGroup; 123 private JRadioButton[] printModeCBs = new JRadioButton[3]; 124 125 /// Status bar 126 private final LabelV2 statusBar; 127 128 private int[] fontStyles = {Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD | Font.ITALIC}; 129 130 /// Text filename 131 private String tFileName; 132 133 // Enabled or disabled status of canDisplay check 134 private static boolean canDisplayCheck = true; 135 136 /// Initialize GUI variables and its layouts 137 public Font2DTest( JFrame f, boolean isApplet ) { 138 parent = f; 139 140 rm = new RangeMenu( this, parent ); 141 fp = new FontPanel( this, parent ); 142 statusBar = new LabelV2(""); 143 144 fontMenu = new ChoiceV2( this, canDisplayCheck ); 145 sizeField = new JTextField( "12", 3 ); 146 sizeField.addActionListener( this ); 147 styleMenu = new ChoiceV2( this ); 148 textMenu = new ChoiceV2( ); // listener added later 149 transformMenu = new ChoiceV2( this ); 150 transformMenuG2 = new ChoiceV2( this ); 151 methodsMenu = new ChoiceV2( this ); 152 153 antiAliasMenu = 154 new JComboBox(EnumSet.allOf(FontPanel.AAValues.class).toArray()); 155 antiAliasMenu.addActionListener(this); 156 fracMetricsMenu = 157 new JComboBox(EnumSet.allOf(FontPanel.FMValues.class).toArray()); 158 fracMetricsMenu.addActionListener(this); 159 160 contrastSlider = new JSlider(JSlider.HORIZONTAL, 100, 250, 161 FontPanel.getDefaultLCDContrast().intValue()); 162 contrastSlider.setEnabled(false); 163 contrastSlider.setMajorTickSpacing(20); 164 contrastSlider.setMinorTickSpacing(10); 165 contrastSlider.setPaintTicks(true); 166 contrastSlider.setPaintLabels(true); 167 contrastSlider.addChangeListener(this); 168 setupPanel(); 169 setupMenu( isApplet ); 170 setupDialog( isApplet ); 171 172 if(canDisplayCheck) { 173 fireRangeChanged(); 174 } 175 } 176 177 /// Set up the main interface panel 178 private void setupPanel() { 179 GridBagLayout gbl = new GridBagLayout(); 180 GridBagConstraints gbc = new GridBagConstraints(); 181 gbc.fill = GridBagConstraints.HORIZONTAL; 182 gbc.weightx = 1; 183 gbc.insets = new Insets( 2, 0, 2, 2 ); 184 this.setLayout( gbl ); 185 186 addLabeledComponentToGBL( "Font: ", fontMenu, gbl, gbc, this ); 187 addLabeledComponentToGBL( "Size: ", sizeField, gbl, gbc, this ); 188 gbc.gridwidth = GridBagConstraints.REMAINDER; 189 addLabeledComponentToGBL( "Font Transform:", 190 transformMenu, gbl, gbc, this ); 191 gbc.gridwidth = 1; 192 193 addLabeledComponentToGBL( "Range: ", rm, gbl, gbc, this ); 194 addLabeledComponentToGBL( "Style: ", styleMenu, gbl, gbc, this ); 195 gbc.gridwidth = GridBagConstraints.REMAINDER; 196 addLabeledComponentToGBL( "Graphics Transform: ", 197 transformMenuG2, gbl, gbc, this ); 198 gbc.gridwidth = 1; 199 200 gbc.anchor = GridBagConstraints.WEST; 201 addLabeledComponentToGBL( "Method: ", methodsMenu, gbl, gbc, this ); 202 addLabeledComponentToGBL("", null, gbl, gbc, this); 203 gbc.anchor = GridBagConstraints.EAST; 204 gbc.gridwidth = GridBagConstraints.REMAINDER; 205 addLabeledComponentToGBL( "Text to use:", textMenu, gbl, gbc, this ); 206 207 gbc.weightx=1; 208 gbc.gridwidth = 1; 209 gbc.fill = GridBagConstraints.HORIZONTAL; 210 gbc.anchor = GridBagConstraints.WEST; 211 addLabeledComponentToGBL("LCD contrast: ", 212 contrastSlider, gbl, gbc, this); 213 214 gbc.gridwidth = 1; 215 gbc.fill = GridBagConstraints.NONE; 216 addLabeledComponentToGBL("Antialiasing: ", 217 antiAliasMenu, gbl, gbc, this); 218 219 gbc.anchor = GridBagConstraints.EAST; 220 gbc.gridwidth = GridBagConstraints.REMAINDER; 221 addLabeledComponentToGBL("Fractional metrics: ", 222 fracMetricsMenu, gbl, gbc, this); 223 224 gbc.weightx = 1; 225 gbc.weighty = 1; 226 gbc.anchor = GridBagConstraints.WEST; 227 gbc.insets = new Insets( 2, 0, 0, 2 ); 228 gbc.fill = GridBagConstraints.BOTH; 229 gbl.setConstraints( fp, gbc ); 230 this.add( fp ); 231 232 gbc.weighty = 0; 233 gbc.insets = new Insets( 0, 2, 0, 0 ); 234 gbl.setConstraints( statusBar, gbc ); 235 this.add( statusBar ); 236 } 237 238 /// Adds a component to a container with a label to its left in GridBagLayout 239 private void addLabeledComponentToGBL( String name, 240 JComponent c, 241 GridBagLayout gbl, 242 GridBagConstraints gbc, 243 Container target ) { 244 LabelV2 l = new LabelV2( name ); 245 GridBagConstraints gbcLabel = (GridBagConstraints) gbc.clone(); 246 gbcLabel.insets = new Insets( 2, 2, 2, 0 ); 247 gbcLabel.gridwidth = 1; 248 gbcLabel.weightx = 0; 249 250 if ( c == null ) 251 c = new JLabel( "" ); 252 253 gbl.setConstraints( l, gbcLabel ); 254 target.add( l ); 255 gbl.setConstraints( c, gbc ); 256 target.add( c ); 257 } 258 259 /// Sets up menu entries 260 private void setupMenu( boolean isApplet ) { 261 JMenu fileMenu = new JMenu( "File" ); 262 JMenu optionMenu = new JMenu( "Option" ); 263 264 fileMenu.add( new MenuItemV2( "Save Selected Options...", this )); 265 fileMenu.add( new MenuItemV2( "Load Options...", this )); 266 fileMenu.addSeparator(); 267 fileMenu.add( new MenuItemV2( "Save as PNG...", this )); 268 fileMenu.add( new MenuItemV2( "Load PNG File to Compare...", this )); 269 fileMenu.add( new MenuItemV2( "Page Setup...", this )); 270 fileMenu.add( new MenuItemV2( "Print...", this )); 271 fileMenu.addSeparator(); 272 if ( !isApplet ) 273 fileMenu.add( new MenuItemV2( "Exit", this )); 274 else 275 fileMenu.add( new MenuItemV2( "Close", this )); 276 277 displayGridCBMI = new CheckboxMenuItemV2( "Display Grid", true, this ); 278 force16ColsCBMI = new CheckboxMenuItemV2( "Force 16 Columns", false, this ); 279 showFontInfoCBMI = new CheckboxMenuItemV2( "Display Font Info", false, this ); 280 optionMenu.add( displayGridCBMI ); 281 optionMenu.add( force16ColsCBMI ); 282 optionMenu.add( showFontInfoCBMI ); 283 284 JMenuBar mb = parent.getJMenuBar(); 285 if ( mb == null ) 286 mb = new JMenuBar(); 287 mb.add( fileMenu ); 288 mb.add( optionMenu ); 289 290 parent.setJMenuBar( mb ); 291 292 String[] fontList = 293 GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); 294 295 for ( int i = 0; i < fontList.length; i++ ) 296 fontMenu.addItem( fontList[i] ); 297 fontMenu.setSelectedItem( "Dialog" ); 298 299 styleMenu.addItem( "Plain" ); 300 styleMenu.addItem( "Bold" ); 301 styleMenu.addItem( "Italic" ); 302 styleMenu.addItem( "Bold Italic" ); 303 304 transformMenu.addItem( "None" ); 305 transformMenu.addItem( "Scale" ); 306 transformMenu.addItem( "Shear" ); 307 transformMenu.addItem( "Rotate" ); 308 309 transformMenuG2.addItem( "None" ); 310 transformMenuG2.addItem( "Scale" ); 311 transformMenuG2.addItem( "Shear" ); 312 transformMenuG2.addItem( "Rotate" ); 313 314 methodsMenu.addItem( "drawString" ); 315 methodsMenu.addItem( "drawChars" ); 316 methodsMenu.addItem( "drawBytes" ); 317 methodsMenu.addItem( "drawGlyphVector" ); 318 methodsMenu.addItem( "TextLayout.draw" ); 319 methodsMenu.addItem( "GlyphVector.getOutline + draw" ); 320 methodsMenu.addItem( "TextLayout.getOutline + draw" ); 321 322 textMenu.addItem( "Unicode Range" ); 323 textMenu.addItem( "All Glyphs" ); 324 textMenu.addItem( "User Text" ); 325 textMenu.addItem( "Text File" ); 326 textMenu.addActionListener ( this ); // listener added later so unneeded events not thrown 327 } 328 329 /// Sets up the all dialogs used in Font2DTest... 330 private void setupDialog( boolean isApplet ) { 331 if (!isApplet) 332 filePromptDialog = new JFileChooser( ); 333 else 334 filePromptDialog = null; 335 336 /// Prepare user text dialog... 337 userTextDialog = new JDialog( parent, "User Text", false ); 338 JPanel dialogTopPanel = new JPanel(); 339 JPanel dialogBottomPanel = new JPanel(); 340 LabelV2 message1 = new LabelV2( "Enter text below and then press update" ); 341 LabelV2 message2 = new LabelV2( "(Unicode char can be denoted by \\uXXXX)" ); 342 LabelV2 message3 = new LabelV2( "(Supplementary chars can be denoted by \\UXXXXXX)" ); 343 userTextArea = new JTextArea( "Font2DTest!" ); 344 ButtonV2 bUpdate = new ButtonV2( "Update", this ); 345 userTextArea.setFont( new Font( "dialog", Font.PLAIN, 12 )); 346 dialogTopPanel.setLayout( new GridLayout( 3, 1 )); 347 dialogTopPanel.add( message1 ); 348 dialogTopPanel.add( message2 ); 349 dialogTopPanel.add( message3 ); 350 dialogBottomPanel.add( bUpdate ); 351 //ABP 352 JScrollPane userTextAreaSP = new JScrollPane(userTextArea); 353 userTextAreaSP.setPreferredSize(new Dimension(300, 100)); 354 355 userTextDialog.getContentPane().setLayout( new BorderLayout() ); 356 userTextDialog.getContentPane().add( "North", dialogTopPanel ); 357 userTextDialog.getContentPane().add( "Center", userTextAreaSP ); 358 userTextDialog.getContentPane().add( "South", dialogBottomPanel ); 359 userTextDialog.pack(); 360 userTextDialog.addWindowListener( new WindowAdapter() { 361 public void windowClosing( WindowEvent e ) { 362 userTextDialog.hide(); 363 } 364 }); 365 366 /// Prepare printing dialog... 367 printCBGroup = new ButtonGroup(); 368 printModeCBs[ fp.ONE_PAGE ] = 369 new JRadioButton( "Print one page from currently displayed character/line", 370 true ); 371 printModeCBs[ fp.CUR_RANGE ] = 372 new JRadioButton( "Print all characters in currently selected range", 373 false ); 374 printModeCBs[ fp.ALL_TEXT ] = 375 new JRadioButton( "Print all lines of text", 376 false ); 377 LabelV2 l = 378 new LabelV2( "Note: Page range in native \"Print\" dialog will not affect the result" ); 379 JPanel buttonPanel = new JPanel(); 380 printModeCBs[ fp.ALL_TEXT ].setEnabled( false ); 381 buttonPanel.add( new ButtonV2( "Print", this )); 382 buttonPanel.add( new ButtonV2( "Cancel", this )); 383 384 printDialog = new JDialog( parent, "Print...", true ); 385 printDialog.setResizable( false ); 386 printDialog.addWindowListener( new WindowAdapter() { 387 public void windowClosing( WindowEvent e ) { 388 printDialog.hide(); 389 } 390 }); 391 printDialog.getContentPane().setLayout( new GridLayout( printModeCBs.length + 2, 1 )); 392 printDialog.getContentPane().add( l ); 393 for ( int i = 0; i < printModeCBs.length; i++ ) { 394 printCBGroup.add( printModeCBs[i] ); 395 printDialog.getContentPane().add( printModeCBs[i] ); 396 } 397 printDialog.getContentPane().add( buttonPanel ); 398 printDialog.pack(); 399 400 /// Prepare font information dialog... 401 fontInfoDialog = new JDialog( parent, "Font info", false ); 402 fontInfoDialog.setResizable( false ); 403 fontInfoDialog.addWindowListener( new WindowAdapter() { 404 public void windowClosing( WindowEvent e ) { 405 fontInfoDialog.hide(); 406 showFontInfoCBMI.setState( false ); 407 } 408 }); 409 JPanel fontInfoPanel = new JPanel(); 410 fontInfoPanel.setLayout( new GridLayout( fontInfos.length, 1 )); 411 for ( int i = 0; i < fontInfos.length; i++ ) { 412 fontInfos[i] = new LabelV2(""); 413 fontInfoPanel.add( fontInfos[i] ); 414 } 415 fontInfoDialog.getContentPane().add( fontInfoPanel ); 416 417 /// Move the location of the dialog... 418 userTextDialog.setLocation( 200, 300 ); 419 fontInfoDialog.setLocation( 0, 400 ); 420 } 421 422 /// RangeMenu object signals using this function 423 /// when Unicode range has been changed and text needs to be redrawn 424 public void fireRangeChanged() { 425 int[] range = rm.getSelectedRange(); 426 fp.setTextToDraw( fp.RANGE_TEXT, range, null, null ); 427 if(canDisplayCheck) { 428 setupFontList(range[0], range[1]); 429 } 430 if ( showFontInfoCBMI.getState() ) 431 fireUpdateFontInfo(); 432 } 433 434 /// Changes the message on the status bar 435 public void fireChangeStatus( String message, boolean error ) { 436 /// If this is not ran as an applet, use own status bar, 437 /// Otherwise, use the appletviewer/browser's status bar 438 statusBar.setText( message ); 439 if ( error ) 440 fp.showingError = true; 441 else 442 fp.showingError = false; 443 } 444 445 /// Updates the information about the selected font 446 public void fireUpdateFontInfo() { 447 if ( showFontInfoCBMI.getState() ) { 448 String[] infos = fp.getFontInfo(); 449 for ( int i = 0; i < fontInfos.length; i++ ) 450 fontInfos[i].setText( infos[i] ); 451 fontInfoDialog.pack(); 452 } 453 } 454 455 private void setupFontList(int rangeStart, int rangeEnd) { 456 457 int listCount = fontMenu.getItemCount(); 458 int size = 16; 459 460 try { 461 size = Float.valueOf(sizeField.getText()).intValue(); 462 } 463 catch ( Exception e ) { 464 System.out.println("Invalid font size in the size textField. Using default value of 16"); 465 } 466 467 int style = fontStyles[styleMenu.getSelectedIndex()]; 468 Font f; 469 for (int i = 0; i < listCount; i++) { 470 String fontName = (String)fontMenu.getItemAt(i); 471 f = new Font(fontName, style, size); 472 if ((rm.getSelectedIndex() != RangeMenu.SURROGATES_AREA_INDEX) && 473 canDisplayRange(f, rangeStart, rangeEnd)) { 474 fontMenu.setBit(i, true); 475 } 476 else { 477 fontMenu.setBit(i, false); 478 } 479 } 480 481 fontMenu.repaint(); 482 } 483 484 protected boolean canDisplayRange(Font font, int rangeStart, int rangeEnd) { 485 for (int i = rangeStart; i < rangeEnd; i++) { 486 if (font.canDisplay(i)) { 487 return true; 488 } 489 } 490 return false; 491 } 492 493 /// Displays a file load/save dialog and returns the specified file 494 private String promptFile( boolean isSave, String initFileName ) { 495 int retVal; 496 String str; 497 498 /// ABP 499 if ( filePromptDialog == null) 500 return null; 501 502 if ( isSave ) { 503 filePromptDialog.setDialogType( JFileChooser.SAVE_DIALOG ); 504 filePromptDialog.setDialogTitle( "Save..." ); 505 str = "Save"; 506 507 508 } 509 else { 510 filePromptDialog.setDialogType( JFileChooser.OPEN_DIALOG ); 511 filePromptDialog.setDialogTitle( "Load..." ); 512 str = "Load"; 513 } 514 515 if (initFileName != null) 516 filePromptDialog.setSelectedFile( new File( initFileName ) ); 517 retVal = filePromptDialog.showDialog( this, str ); 518 519 if ( retVal == JFileChooser.APPROVE_OPTION ) { 520 File file = filePromptDialog.getSelectedFile(); 521 String fileName = file.getAbsolutePath(); 522 if ( fileName != null ) { 523 return fileName; 524 } 525 } 526 527 return null; 528 } 529 530 /// Converts user text into arrays of String, delimited at newline character 531 /// Also replaces any valid escape sequence with appropriate unicode character 532 /// Support \\UXXXXXX notation for surrogates 533 private String[] parseUserText( String orig ) { 534 int length = orig.length(); 535 StringTokenizer perLine = new StringTokenizer( orig, "\n" ); 536 String[] textLines = new String[ perLine.countTokens() ]; 537 int lineNumber = 0; 538 539 while ( perLine.hasMoreElements() ) { 540 StringBuffer converted = new StringBuffer(); 541 String oneLine = perLine.nextToken(); 542 int lineLength = oneLine.length(); 543 int prevEscapeEnd = 0; 544 int nextEscape = -1; 545 do { 546 int nextBMPEscape = oneLine.indexOf( "\\u", prevEscapeEnd ); 547 int nextSupEscape = oneLine.indexOf( "\\U", prevEscapeEnd ); 548 nextEscape = (nextBMPEscape < 0) 549 ? ((nextSupEscape < 0) 550 ? -1 551 : nextSupEscape) 552 : ((nextSupEscape < 0) 553 ? nextBMPEscape 554 : Math.min(nextBMPEscape, nextSupEscape)); 555 556 if ( nextEscape != -1 ) { 557 if ( prevEscapeEnd < nextEscape ) 558 converted.append( oneLine.substring( prevEscapeEnd, nextEscape )); 559 560 prevEscapeEnd = nextEscape + (nextEscape == nextBMPEscape ? 6 : 8); 561 try { 562 String hex = oneLine.substring( nextEscape + 2, prevEscapeEnd ); 563 if (nextEscape == nextBMPEscape) { 564 converted.append( (char) Integer.parseInt( hex, 16 )); 565 } else { 566 converted.append( new String( Character.toChars( Integer.parseInt( hex, 16 )))); 567 } 568 } 569 catch ( Exception e ) { 570 int copyLimit = Math.min(lineLength, prevEscapeEnd); 571 converted.append( oneLine.substring( nextEscape, copyLimit )); 572 } 573 } 574 } while (nextEscape != -1); 575 if ( prevEscapeEnd < lineLength ) 576 converted.append( oneLine.substring( prevEscapeEnd, lineLength )); 577 textLines[ lineNumber++ ] = converted.toString(); 578 } 579 return textLines; 580 } 581 582 /// Reads the text from specified file, detecting UTF-16 encoding 583 /// Then breaks the text into String array, delimited at every line break 584 private void readTextFile( String fileName ) { 585 try { 586 String fileText;String[] textLines; 587 BufferedInputStream bis = 588 new BufferedInputStream( new FileInputStream( fileName )); 589 int numBytes = bis.available(); 590 if (numBytes == 0) { 591 throw new Exception("Text file " + fileName + " is empty"); 592 } 593 byte[] byteData = new byte[ numBytes ]; 594 bis.read( byteData, 0, numBytes ); 595 bis.close(); 596 597 /// If byte mark is found, then use UTF-16 encoding to convert bytes... 598 if (numBytes >= 2 && 599 (( byteData[0] == (byte) 0xFF && byteData[1] == (byte) 0xFE ) || 600 ( byteData[0] == (byte) 0xFE && byteData[1] == (byte) 0xFF ))) 601 fileText = new String( byteData, "UTF-16" ); 602 /// Otherwise, use system default encoding 603 else 604 fileText = new String( byteData ); 605 606 int length = fileText.length(); 607 StringTokenizer perLine = new StringTokenizer( fileText, "\n" ); 608 /// Determine "Return Char" used in this file 609 /// This simply finds first occurrence of CR, CR+LF or LF... 610 for ( int i = 0; i < length; i++ ) { 611 char iTh = fileText.charAt( i ); 612 if ( iTh == '\r' ) { 613 if ( i < length - 1 && fileText.charAt( i + 1 ) == '\n' ) 614 perLine = new StringTokenizer( fileText, "\r\n" ); 615 else 616 perLine = new StringTokenizer( fileText, "\r" ); 617 break; 618 } 619 else if ( iTh == '\n' ) 620 /// Use the one already created 621 break; 622 } 623 int lineNumber = 0, numLines = perLine.countTokens(); 624 textLines = new String[ numLines ]; 625 626 while ( perLine.hasMoreElements() ) { 627 String oneLine = perLine.nextToken(); 628 if ( oneLine == null ) 629 /// To make LineBreakMeasurer to return a valid TextLayout 630 /// on an empty line, simply feed it a space char... 631 oneLine = " "; 632 textLines[ lineNumber++ ] = oneLine; 633 } 634 fp.setTextToDraw( fp.FILE_TEXT, null, null, textLines ); 635 rm.setEnabled( false ); 636 methodsMenu.setEnabled( false ); 637 } 638 catch ( Exception ex ) { 639 fireChangeStatus( "ERROR: Failed to Read Text File; See Stack Trace", true ); 640 ex.printStackTrace(); 641 } 642 } 643 644 /// Returns a String storing current configuration 645 private void writeCurrentOptions( String fileName ) { 646 try { 647 String curOptions = fp.getCurrentOptions(); 648 BufferedOutputStream bos = 649 new BufferedOutputStream( new FileOutputStream( fileName )); 650 /// Prepend title and the option that is only obtainable here 651 int[] range = rm.getSelectedRange(); 652 String completeOptions = 653 ( "Font2DTest Option File\n" + 654 displayGridCBMI.getState() + "\n" + 655 force16ColsCBMI.getState() + "\n" + 656 showFontInfoCBMI.getState() + "\n" + 657 rm.getSelectedItem() + "\n" + 658 range[0] + "\n" + range[1] + "\n" + curOptions + tFileName); 659 byte[] toBeWritten = completeOptions.getBytes( "UTF-16" ); 660 bos.write( toBeWritten, 0, toBeWritten.length ); 661 bos.close(); 662 } 663 catch ( Exception ex ) { 664 fireChangeStatus( "ERROR: Failed to Save Options File; See Stack Trace", true ); 665 ex.printStackTrace(); 666 } 667 } 668 669 /// Updates GUI visibility/status after some parameters have changed 670 private void updateGUI() { 671 int selectedText = textMenu.getSelectedIndex(); 672 673 /// Set the visibility of User Text dialog 674 if ( selectedText == fp.USER_TEXT ) 675 userTextDialog.show(); 676 else 677 userTextDialog.hide(); 678 /// Change the visibility/status/availability of Print JDialog buttons 679 printModeCBs[ fp.ONE_PAGE ].setSelected( true ); 680 if ( selectedText == fp.FILE_TEXT || selectedText == fp.USER_TEXT ) { 681 /// ABP 682 /// update methodsMenu to show that TextLayout.draw is being used 683 /// when we are in FILE_TEXT mode 684 if ( selectedText == fp.FILE_TEXT ) 685 methodsMenu.setSelectedItem("TextLayout.draw"); 686 methodsMenu.setEnabled( selectedText == fp.USER_TEXT ); 687 printModeCBs[ fp.CUR_RANGE ].setEnabled( false ); 688 printModeCBs[ fp.ALL_TEXT ].setEnabled( true ); 689 } 690 else { 691 /// ABP 692 /// update methodsMenu to show that drawGlyph is being used 693 /// when we are in ALL_GLYPHS mode 694 if ( selectedText == fp.ALL_GLYPHS ) 695 methodsMenu.setSelectedItem("drawGlyphVector"); 696 methodsMenu.setEnabled( selectedText == fp.RANGE_TEXT ); 697 printModeCBs[ fp.CUR_RANGE ].setEnabled( true ); 698 printModeCBs[ fp.ALL_TEXT ].setEnabled( false ); 699 } 700 /// Modify RangeMenu and fontInfo label availabilty 701 if ( selectedText == fp.RANGE_TEXT ) { 702 fontInfos[1].setVisible( true ); 703 rm.setEnabled( true ); 704 } 705 else { 706 fontInfos[1].setVisible( false ); 707 rm.setEnabled( false ); 708 } 709 } 710 711 /// Loads saved options and applies them 712 private void loadOptions( String fileName ) { 713 try { 714 BufferedInputStream bis = 715 new BufferedInputStream( new FileInputStream( fileName )); 716 int numBytes = bis.available(); 717 byte[] byteData = new byte[ numBytes ]; 718 bis.read( byteData, 0, numBytes ); 719 bis.close(); 720 if ( numBytes < 2 || 721 (byteData[0] != (byte) 0xFE || byteData[1] != (byte) 0xFF) ) 722 throw new Exception( "Not a Font2DTest options file" ); 723 724 String options = new String( byteData, "UTF-16" ); 725 StringTokenizer perLine = new StringTokenizer( options, "\n" ); 726 String title = perLine.nextToken(); 727 if ( !title.equals( "Font2DTest Option File" )) 728 throw new Exception( "Not a Font2DTest options file" ); 729 730 /// Parse all options 731 boolean displayGridOpt = Boolean.parseBoolean( perLine.nextToken() ); 732 boolean force16ColsOpt = Boolean.parseBoolean( perLine.nextToken() ); 733 boolean showFontInfoOpt = Boolean.parseBoolean( perLine.nextToken() ); 734 String rangeNameOpt = perLine.nextToken(); 735 int rangeStartOpt = Integer.parseInt( perLine.nextToken() ); 736 int rangeEndOpt = Integer.parseInt( perLine.nextToken() ); 737 String fontNameOpt = perLine.nextToken(); 738 float fontSizeOpt = Float.parseFloat( perLine.nextToken() ); 739 int fontStyleOpt = Integer.parseInt( perLine.nextToken() ); 740 int fontTransformOpt = Integer.parseInt( perLine.nextToken() ); 741 int g2TransformOpt = Integer.parseInt( perLine.nextToken() ); 742 int textToUseOpt = Integer.parseInt( perLine.nextToken() ); 743 int drawMethodOpt = Integer.parseInt( perLine.nextToken() ); 744 int antialiasOpt = Integer.parseInt(perLine.nextToken()); 745 int fractionalOpt = Integer.parseInt(perLine.nextToken()); 746 int lcdContrast = Integer.parseInt(perLine.nextToken()); 747 String[] userTextOpt = { "Font2DTest!" }; 748 String dialogEntry = "Font2DTest!"; 749 if (textToUseOpt == fp.USER_TEXT ) { 750 int numLines = perLine.countTokens(), lineNumber = 0; 751 if ( numLines != 0 ) { 752 userTextOpt = new String[ numLines ]; 753 dialogEntry = ""; 754 for ( ; perLine.hasMoreElements(); lineNumber++ ) { 755 userTextOpt[ lineNumber ] = perLine.nextToken(); 756 dialogEntry += userTextOpt[ lineNumber ] + "\n"; 757 } 758 } 759 } 760 761 /// Reset GUIs 762 displayGridCBMI.setState( displayGridOpt ); 763 force16ColsCBMI.setState( force16ColsOpt ); 764 showFontInfoCBMI.setState( showFontInfoOpt ); 765 rm.setSelectedRange( rangeNameOpt, rangeStartOpt, rangeEndOpt ); 766 fontMenu.setSelectedItem( fontNameOpt ); 767 sizeField.setText( String.valueOf( fontSizeOpt )); 768 styleMenu.setSelectedIndex( fontStyleOpt ); 769 transformMenu.setSelectedIndex( fontTransformOpt ); 770 transformMenuG2.setSelectedIndex( g2TransformOpt ); 771 textMenu.setSelectedIndex( textToUseOpt ); 772 methodsMenu.setSelectedIndex( drawMethodOpt ); 773 antiAliasMenu.setSelectedIndex( antialiasOpt ); 774 fracMetricsMenu.setSelectedIndex( fractionalOpt ); 775 contrastSlider.setValue(lcdContrast); 776 777 userTextArea.setText( dialogEntry ); 778 updateGUI(); 779 780 if ( textToUseOpt == fp.FILE_TEXT ) { 781 tFileName = perLine.nextToken(); 782 readTextFile(tFileName ); 783 } 784 785 /// Reset option variables and repaint 786 fp.loadOptions( displayGridOpt, force16ColsOpt, 787 rangeStartOpt, rangeEndOpt, 788 fontNameOpt, fontSizeOpt, 789 fontStyleOpt, fontTransformOpt, g2TransformOpt, 790 textToUseOpt, drawMethodOpt, 791 antialiasOpt, fractionalOpt, 792 lcdContrast, userTextOpt ); 793 if ( showFontInfoOpt ) { 794 fireUpdateFontInfo(); 795 fontInfoDialog.show(); 796 } 797 else 798 fontInfoDialog.hide(); 799 } 800 catch ( Exception ex ) { 801 fireChangeStatus( "ERROR: Failed to Load Options File; See Stack Trace", true ); 802 ex.printStackTrace(); 803 } 804 } 805 806 /// Loads a previously saved image 807 private void loadComparisonPNG( String fileName ) { 808 try { 809 BufferedImage image = 810 javax.imageio.ImageIO.read(new File(fileName)); 811 JFrame f = new JFrame( "Comparison PNG" ); 812 ImagePanel ip = new ImagePanel( image ); 813 f.setResizable( false ); 814 f.getContentPane().add( ip ); 815 f.addWindowListener( new WindowAdapter() { 816 public void windowClosing( WindowEvent e ) { 817 ( (JFrame) e.getSource() ).dispose(); 818 } 819 }); 820 f.pack(); 821 f.show(); 822 } 823 catch ( Exception ex ) { 824 fireChangeStatus( "ERROR: Failed to Load PNG File; See Stack Trace", true ); 825 ex.printStackTrace(); 826 } 827 } 828 829 /// Interface functions... 830 831 /// ActionListener interface function 832 /// Responds to JMenuItem, JTextField and JButton actions 833 public void actionPerformed( ActionEvent e ) { 834 Object source = e.getSource(); 835 836 if ( source instanceof JMenuItem ) { 837 JMenuItem mi = (JMenuItem) source; 838 String itemName = mi.getText(); 839 840 if ( itemName.equals( "Save Selected Options..." )) { 841 String fileName = promptFile( true, "options.txt" ); 842 if ( fileName != null ) 843 writeCurrentOptions( fileName ); 844 } 845 else if ( itemName.equals( "Load Options..." )) { 846 String fileName = promptFile( false, "options.txt" ); 847 if ( fileName != null ) 848 loadOptions( fileName ); 849 } 850 else if ( itemName.equals( "Save as PNG..." )) { 851 String fileName = promptFile( true, fontMenu.getSelectedItem() + ".png" ); 852 if ( fileName != null ) 853 fp.doSavePNG( fileName ); 854 } 855 else if ( itemName.equals( "Load PNG File to Compare..." )) { 856 String fileName = promptFile( false, null ); 857 if ( fileName != null ) 858 loadComparisonPNG( fileName ); 859 } 860 else if ( itemName.equals( "Page Setup..." )) 861 fp.doPageSetup(); 862 else if ( itemName.equals( "Print..." )) 863 printDialog.show(); 864 else if ( itemName.equals( "Close" )) 865 parent.dispose(); 866 else if ( itemName.equals( "Exit" )) 867 System.exit(0); 868 } 869 870 else if ( source instanceof JTextField ) { 871 JTextField tf = (JTextField) source; 872 float sz = 12f; 873 try { 874 sz = Float.parseFloat(sizeField.getText()); 875 if (sz < 1f || sz > 120f) { 876 sz = 12f; 877 sizeField.setText("12"); 878 } 879 } catch (Exception se) { 880 sizeField.setText("12"); 881 } 882 if ( tf == sizeField ) 883 fp.setFontParams( fontMenu.getSelectedItem(), 884 sz, 885 styleMenu.getSelectedIndex(), 886 transformMenu.getSelectedIndex() ); 887 } 888 889 else if ( source instanceof JButton ) { 890 String itemName = ( (JButton) source ).getText(); 891 /// Print dialog buttons... 892 if ( itemName.equals( "Print" )) { 893 for ( int i = 0; i < printModeCBs.length; i++ ) 894 if ( printModeCBs[i].isSelected() ) { 895 printDialog.hide(); 896 fp.doPrint( i ); 897 } 898 } 899 else if ( itemName.equals( "Cancel" )) 900 printDialog.hide(); 901 /// Update button from Usert Text JDialog... 902 else if ( itemName.equals( "Update" )) 903 fp.setTextToDraw( fp.USER_TEXT, null, 904 parseUserText( userTextArea.getText() ), null ); 905 } 906 else if ( source instanceof JComboBox ) { 907 JComboBox c = (JComboBox) source; 908 909 /// RangeMenu handles actions by itself and then calls fireRangeChanged, 910 /// so it is not listed or handled here 911 if ( c == fontMenu || c == styleMenu || c == transformMenu ) { 912 float sz = 12f; 913 try { 914 sz = Float.parseFloat(sizeField.getText()); 915 if (sz < 1f || sz > 120f) { 916 sz = 12f; 917 sizeField.setText("12"); 918 } 919 } catch (Exception se) { 920 sizeField.setText("12"); 921 } 922 fp.setFontParams(fontMenu.getSelectedItem(), 923 sz, 924 styleMenu.getSelectedIndex(), 925 transformMenu.getSelectedIndex()); 926 } else if ( c == methodsMenu ) 927 fp.setDrawMethod( methodsMenu.getSelectedIndex() ); 928 else if ( c == textMenu ) { 929 930 if(canDisplayCheck) { 931 fireRangeChanged(); 932 } 933 934 int selected = textMenu.getSelectedIndex(); 935 936 if ( selected == fp.RANGE_TEXT ) 937 fp.setTextToDraw( fp.RANGE_TEXT, rm.getSelectedRange(), 938 null, null ); 939 else if ( selected == fp.USER_TEXT ) 940 fp.setTextToDraw( fp.USER_TEXT, null, 941 parseUserText( userTextArea.getText() ), null ); 942 else if ( selected == fp.FILE_TEXT ) { 943 String fileName = promptFile( false, null ); 944 if ( fileName != null ) { 945 tFileName = fileName; 946 readTextFile( fileName ); 947 } else { 948 /// User cancelled selection; reset to previous choice 949 c.setSelectedIndex( currentTextChoice ); 950 return; 951 } 952 } 953 else if ( selected == fp.ALL_GLYPHS ) 954 fp.setTextToDraw( fp.ALL_GLYPHS, null, null, null ); 955 956 updateGUI(); 957 currentTextChoice = selected; 958 } 959 else if ( c == transformMenuG2 ) { 960 fp.setTransformG2( transformMenuG2.getSelectedIndex() ); 961 } 962 else if (c == antiAliasMenu || c == fracMetricsMenu) { 963 if (c == antiAliasMenu) { 964 boolean enabled = FontPanel.AAValues. 965 isLCDMode(antiAliasMenu.getSelectedItem()); 966 contrastSlider.setEnabled(enabled); 967 } 968 fp.setRenderingHints(antiAliasMenu.getSelectedItem(), 969 fracMetricsMenu.getSelectedItem(), 970 contrastSlider.getValue()); 971 } 972 } 973 } 974 975 public void stateChanged(ChangeEvent e) { 976 Object source = e.getSource(); 977 if (source instanceof JSlider) { 978 fp.setRenderingHints(antiAliasMenu.getSelectedItem(), 979 fracMetricsMenu.getSelectedItem(), 980 contrastSlider.getValue()); 981 } 982 } 983 984 /// ItemListener interface function 985 /// Responds to JCheckBoxMenuItem, JComboBox and JCheckBox actions 986 public void itemStateChanged( ItemEvent e ) { 987 Object source = e.getSource(); 988 989 if ( source instanceof JCheckBoxMenuItem ) { 990 JCheckBoxMenuItem cbmi = (JCheckBoxMenuItem) source; 991 if ( cbmi == displayGridCBMI ) 992 fp.setGridDisplay( displayGridCBMI.getState() ); 993 else if ( cbmi == force16ColsCBMI ) 994 fp.setForce16Columns( force16ColsCBMI.getState() ); 995 else if ( cbmi == showFontInfoCBMI ) { 996 if ( showFontInfoCBMI.getState() ) { 997 fireUpdateFontInfo(); 998 fontInfoDialog.show(); 999 } 1000 else 1001 fontInfoDialog.hide(); 1002 } 1003 } 1004 } 1005 1006 private static void printUsage() { 1007 String usage = "Usage: java -jar Font2DTest.jar [options]\n" + 1008 "\nwhere options include:\n" + 1009 " -dcdc | -disablecandisplaycheck disable canDisplay check for font\n" + 1010 " -? | -help print this help message\n" + 1011 "\nExample :\n" + 1012 " To disable canDisplay check on font for ranges\n" + 1013 " java -jar Font2DTest.jar -dcdc"; 1014 System.out.println(usage); 1015 System.exit(0); 1016 } 1017 1018 /// Main function 1019 public static void main(String[] argv) { 1020 1021 if(argv.length > 0) { 1022 if(argv[0].equalsIgnoreCase("-disablecandisplaycheck") || 1023 argv[0].equalsIgnoreCase("-dcdc")) { 1024 canDisplayCheck = false; 1025 } 1026 else { 1027 printUsage(); 1028 } 1029 } 1030 1031 UIManager.put("swing.boldMetal", Boolean.FALSE); 1032 final JFrame f = new JFrame( "Font2DTest" ); 1033 final Font2DTest f2dt = new Font2DTest( f, false ); 1034 f.addWindowListener( new WindowAdapter() { 1035 public void windowOpening( WindowEvent e ) { f2dt.repaint(); } 1036 public void windowClosing( WindowEvent e ) { System.exit(0); } 1037 }); 1038 1039 f.getContentPane().add( f2dt ); 1040 f.pack(); 1041 f.show(); 1042 } 1043 1044 /// Inner class definitions... 1045 1046 /// Class to display just an image file 1047 /// Used to show the comparison PNG image 1048 private final class ImagePanel extends JPanel { 1049 private final BufferedImage bi; 1050 1051 public ImagePanel( BufferedImage image ) { 1052 bi = image; 1053 } 1054 1055 public Dimension getPreferredSize() { 1056 return new Dimension( bi.getWidth(), bi.getHeight() ); 1057 } 1058 1059 public void paintComponent( Graphics g ) { 1060 g.drawImage( bi, 0, 0, this ); 1061 } 1062 } 1063 1064 /// Classes made to avoid repetitive calls... (being lazy) 1065 private final class ButtonV2 extends JButton { 1066 public ButtonV2( String name, ActionListener al ) { 1067 super( name ); 1068 this.addActionListener( al ); 1069 } 1070 } 1071 1072 private final class ChoiceV2 extends JComboBox { 1073 1074 private BitSet bitSet = null; 1075 1076 public ChoiceV2() {;} 1077 1078 public ChoiceV2( ActionListener al ) { 1079 super(); 1080 this.addActionListener( al ); 1081 } 1082 1083 public ChoiceV2( ActionListener al, boolean fontChoice) { 1084 this(al); 1085 if(fontChoice) { 1086 //Register this component in ToolTipManager 1087 setToolTipText(""); 1088 bitSet = new BitSet(); 1089 setRenderer(new ChoiceV2Renderer(this)); 1090 } 1091 } 1092 1093 public String getToolTipText() { 1094 int index = this.getSelectedIndex(); 1095 String fontName = (String) this.getSelectedItem(); 1096 if(fontName != null && 1097 (textMenu.getSelectedIndex() == fp.RANGE_TEXT)) { 1098 if (getBit(index)) { 1099 return "Font \"" + fontName + "\" can display some characters in \"" + 1100 rm.getSelectedItem() + "\" range"; 1101 } 1102 else { 1103 return "Font \"" + fontName + "\" cannot display any characters in \"" + 1104 rm.getSelectedItem() + "\" range"; 1105 } 1106 } 1107 return super.getToolTipText(); 1108 } 1109 1110 public void setBit(int bitIndex, boolean value) { 1111 bitSet.set(bitIndex, value); 1112 } 1113 1114 public boolean getBit(int bitIndex) { 1115 return bitSet.get(bitIndex); 1116 } 1117 } 1118 1119 private final class ChoiceV2Renderer extends DefaultListCellRenderer { 1120 1121 private ImageIcon yesImage, blankImage; 1122 private ChoiceV2 choice = null; 1123 1124 public ChoiceV2Renderer(ChoiceV2 choice) { 1125 BufferedImage yes = 1126 new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB); 1127 Graphics2D g = yes.createGraphics(); 1128 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 1129 RenderingHints.VALUE_ANTIALIAS_ON); 1130 g.setColor(Color.BLUE); 1131 g.drawLine(0, 5, 3, 10); 1132 g.drawLine(1, 5, 4, 10); 1133 g.drawLine(3, 10, 10, 0); 1134 g.drawLine(4, 9, 9, 0); 1135 g.dispose(); 1136 BufferedImage blank = 1137 new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB); 1138 yesImage = new ImageIcon(yes); 1139 blankImage = new ImageIcon(blank); 1140 this.choice = choice; 1141 } 1142 1143 public Component getListCellRendererComponent(JList list, 1144 Object value, 1145 int index, 1146 boolean isSelected, 1147 boolean cellHasFocus) { 1148 1149 if(textMenu.getSelectedIndex() == fp.RANGE_TEXT) { 1150 1151 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1152 1153 //For JComboBox if index is -1, its rendering the selected index. 1154 if(index == -1) { 1155 index = choice.getSelectedIndex(); 1156 } 1157 1158 if(choice.getBit(index)) { 1159 setIcon(yesImage); 1160 } 1161 else { 1162 setIcon(blankImage); 1163 } 1164 1165 } else { 1166 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1167 setIcon(blankImage); 1168 } 1169 1170 return this; 1171 } 1172 } 1173 1174 private final class LabelV2 extends JLabel { 1175 public LabelV2( String name ) { 1176 super( name ); 1177 } 1178 } 1179 1180 private final class MenuItemV2 extends JMenuItem { 1181 public MenuItemV2( String name, ActionListener al ) { 1182 super( name ); 1183 this.addActionListener( al ); 1184 } 1185 } 1186 1187 private final class CheckboxMenuItemV2 extends JCheckBoxMenuItem { 1188 public CheckboxMenuItemV2( String name, boolean b, ItemListener il ) { 1189 super( name, b ); 1190 this.addItemListener( il ); 1191 } 1192 } 1193 }