home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / JBuilder8.iso / Solaris / resource / jre / demo / plugin / jfc / Font2DTest / src / Font2DTest.java next >
Encoding:
Java Source  |  2002-09-06  |  37.5 KB  |  958 lines

  1. /*
  2.  * Copyright (c) 2002 Sun Microsystems, Inc. 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.  * -Redistribution in binary form must reproduct the above copyright
  12.  *  notice, this list of conditions and the following disclaimer in
  13.  *  the documentation and/or other materials provided with the distribution.
  14.  * 
  15.  * Neither the name of Sun Microsystems, Inc. or the names of contributors
  16.  * may be used to endorse or promote products derived from this software
  17.  * without specific prior written permission.
  18.  * 
  19.  * This software is provided "AS IS," without a warranty of any kind. ALL
  20.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
  21.  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
  22.  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT
  23.  * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT
  24.  * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS
  25.  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
  26.  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
  27.  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
  28.  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
  29.  * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  30.  * 
  31.  * You acknowledge that Software is not designed, licensed or intended for
  32.  * use in the design, construction, operation or maintenance of any nuclear
  33.  * facility.
  34.  */
  35.  
  36. /*
  37.  * @(#)Font2DTest.java    1.19 02/06/13
  38.  */
  39.  
  40. import java.awt.BorderLayout;
  41. import java.awt.CheckboxGroup;
  42. import java.awt.Container;
  43. import java.awt.Dimension;
  44. import java.awt.Font;
  45. import java.awt.Graphics;
  46. import java.awt.GraphicsEnvironment;
  47. import java.awt.GridBagConstraints;
  48. import java.awt.GridBagLayout;
  49. import java.awt.GridLayout;
  50. import java.awt.Insets;
  51. import java.awt.Toolkit;
  52. import java.awt.event.ActionEvent;
  53. import java.awt.event.ActionListener;
  54. import java.awt.event.ItemEvent;
  55. import java.awt.event.ItemListener;
  56. import java.awt.event.WindowAdapter;
  57. import java.awt.event.WindowEvent;
  58. import java.awt.image.BufferedImage;
  59. import java.io.BufferedInputStream;
  60. import java.io.BufferedOutputStream;
  61. import java.io.File;
  62. import java.io.FileInputStream;
  63. import java.io.FileOutputStream;
  64. import java.util.StringTokenizer;
  65.  
  66. import javax.swing.*;
  67.  
  68. import com.sun.image.codec.jpeg.JPEGCodec;
  69. import com.sun.image.codec.jpeg.JPEGImageDecoder;
  70.  
  71. /**
  72.  * Font2DTest.java
  73.  *
  74.  * @version @(#)Font2DTest.java    1.2 00/08/22
  75.  * @author Shinsuke Fukuda
  76.  * @author Ankit Patel [Conversion to Swing - 01/07/30] 
  77.  */
  78.  
  79. /// Main Font2DTest Class
  80.  
  81. public final class Font2DTest extends JPanel implements ActionListener, ItemListener {
  82.  
  83.     /// JFrame that will contain Font2DTest
  84.     private final JFrame parent;
  85.     /// FontPanel class that will contain all graphical output
  86.     private final FontPanel fp;
  87.     /// RangeMenu class that contains info about the unicode ranges
  88.     private final RangeMenu rm;
  89.  
  90.     /// Other menus to set parameters for text drawing
  91.     private final ChoiceV2 fontMenu;
  92.     private final JTextField sizeField;
  93.     private final ChoiceV2 styleMenu;
  94.     private final ChoiceV2 textMenu;
  95.     private int currentTextChoice = 0;
  96.     private final ChoiceV2 transformMenu;
  97.     private final ChoiceV2 transformMenuG2;    
  98.     private final ChoiceV2 methodsMenu;
  99.     private final JCheckBox useAntialiasCB;
  100.     private final JCheckBox useFractionalCB;
  101.  
  102.     /// CheckboxMenuItems
  103.     private CheckboxMenuItemV2 displayGridCBMI;
  104.     private CheckboxMenuItemV2 force16ColsCBMI;
  105.     private CheckboxMenuItemV2 showFontInfoCBMI;
  106.  
  107.     /// JDialog boxes
  108.     private JDialog userTextDialog;
  109.     private JTextArea userTextArea;
  110.     private JDialog printDialog;
  111.     private JDialog fontInfoDialog;
  112.     private LabelV2 fontInfos[] = new LabelV2[2];
  113.     private JFileChooser filePromptDialog = null;
  114.  
  115.     private ButtonGroup printCBGroup;
  116.     private JRadioButton printModeCBs[] = new JRadioButton[3];
  117.  
  118.     /// Status bar
  119.     private final LabelV2 statusBar;
  120.  
  121.     /// Universal font used for labels
  122.     private final Font labelFont = new Font( "dialog", Font.BOLD, 12 );
  123.  
  124.   /// Text filename
  125.   private String tFileName;
  126.  
  127.     /// Initialize GUI variables and its layouts
  128.     public Font2DTest( JFrame f, boolean isApplet ) {
  129.         parent = f;
  130.         
  131.         rm = new RangeMenu( this, parent );
  132.         fp = new FontPanel( this, parent );
  133.         statusBar = new LabelV2("");
  134.  
  135.         fontMenu = new ChoiceV2( this );
  136.         sizeField = new JTextField( "12", 3 );
  137.         styleMenu = new ChoiceV2( this );
  138.         textMenu = new ChoiceV2( ); // listener added later
  139.         transformMenu = new ChoiceV2( this );
  140.         transformMenuG2 = new ChoiceV2( this );        
  141.         methodsMenu = new ChoiceV2( this );
  142.  
  143.         useAntialiasCB = new JCheckBox( "Antialiasing", false );
  144.         useFractionalCB = new JCheckBox(" Fractional Metrics", false );
  145.         useAntialiasCB.setFont( labelFont );
  146.         useFractionalCB.setFont( labelFont );
  147.         sizeField.addActionListener( this );
  148.         useAntialiasCB.addItemListener( this );
  149.         useFractionalCB.addItemListener( this );
  150.  
  151.         setupPanel();
  152.         setupMenu( isApplet );
  153.         setupDialog( isApplet );
  154.     }
  155.  
  156.     /// Set up the main interface panel
  157.     private void setupPanel() {
  158.         GridBagLayout gbl = new GridBagLayout();
  159.         GridBagConstraints gbc = new GridBagConstraints();
  160.         gbc.fill = GridBagConstraints.BOTH;
  161.         gbc.weightx = 1;
  162.         gbc.insets = new Insets( 2, 0, 2, 2 );
  163.         this.setLayout( gbl );
  164.  
  165.         addLabeledComponentToGBL( "Font:", fontMenu, gbl, gbc, this );
  166.         addLabeledComponentToGBL( "Size:", sizeField, gbl, gbc, this );
  167.         gbc.gridwidth = GridBagConstraints.REMAINDER;
  168.         addLabeledComponentToGBL( "Transform:", transformMenu, gbl, gbc, this );
  169.         gbc.gridwidth = 1;
  170.  
  171.         addLabeledComponentToGBL( "Range:", rm, gbl, gbc, this );
  172.         addLabeledComponentToGBL( "Style:", styleMenu, gbl, gbc, this );
  173.         gbc.gridwidth = GridBagConstraints.REMAINDER;
  174.         addLabeledComponentToGBL( "Text to use:", textMenu, gbl, gbc, this );
  175.         gbc.gridwidth = 1;
  176.  
  177.     /// ABP
  178.         addLabeledComponentToGBL( "Method:", methodsMenu, gbl, gbc, this );
  179.         gbc.anchor = GridBagConstraints.EAST;
  180.         gbc.gridwidth = GridBagConstraints.REMAINDER;
  181.         addLabeledComponentToGBL( "Graphics2D Transform:", transformMenuG2, gbl, gbc, this );        
  182.         gbc.gridwidth = 1;
  183.         
  184.         gbc.gridwidth = 2;
  185.         gbc.fill = GridBagConstraints.NONE;
  186.         gbc.anchor = GridBagConstraints.CENTER;
  187.         gbl.setConstraints( useAntialiasCB, gbc );
  188.         this.add( useAntialiasCB );
  189.         gbc.gridwidth = GridBagConstraints.REMAINDER;
  190.         gbl.setConstraints( useFractionalCB, gbc );
  191.         this.add( useFractionalCB );        
  192.         
  193.         gbc.weightx = 1;
  194.         gbc.weighty = 1;
  195.         gbc.insets = new Insets( 2, 0, 0, 2 );
  196.         gbc.fill = GridBagConstraints.BOTH;
  197.         gbl.setConstraints( fp, gbc );
  198.         this.add( fp );
  199.  
  200.         gbc.weighty = 0;
  201.         gbc.insets = new Insets( 0, 2, 0, 0 );
  202.         gbl.setConstraints( statusBar, gbc );
  203.         this.add( statusBar );
  204.     }
  205.  
  206.     /// Adds a component to a container with a label to its left in GridBagLayout
  207.     private void addLabeledComponentToGBL( String name,
  208.                                            JComponent c,
  209.                                            GridBagLayout gbl,
  210.                                            GridBagConstraints gbc,
  211.                                            Container target ) {
  212.         LabelV2 l = new LabelV2( name );
  213.         GridBagConstraints gbcLabel = (GridBagConstraints) gbc.clone();
  214.         gbcLabel.insets = new Insets( 2, 2, 2, 0 );
  215.         gbcLabel.gridwidth = 1;
  216.         gbcLabel.weightx = 0;
  217.  
  218.         if ( c == null )
  219.           c = new JLabel( "" );
  220.  
  221.         gbl.setConstraints( l, gbcLabel );
  222.         target.add( l );
  223.         gbl.setConstraints( c, gbc );
  224.         target.add( c );
  225.     }
  226.  
  227.     /// Sets up menu entries
  228.     private void setupMenu( boolean isApplet ) {
  229.         JMenu fileMenu = new JMenu( "File" );
  230.         JMenu optionMenu = new JMenu( "Option" );
  231.  
  232.         fileMenu.add( new MenuItemV2( "Save Selected Options...", this ));
  233.         fileMenu.add( new MenuItemV2( "Load Options...", this ));
  234.         fileMenu.addSeparator();
  235.         fileMenu.add( new MenuItemV2( "Save as JPEG...", this ));
  236.         fileMenu.add( new MenuItemV2( "Load JPEG File to Compare...", this ));
  237.         fileMenu.add( new MenuItemV2( "Page Setup...", this ));
  238.         fileMenu.add( new MenuItemV2( "Print...", this ));
  239.         fileMenu.addSeparator();
  240.         if ( !isApplet )
  241.           fileMenu.add( new MenuItemV2( "Exit", this ));
  242.         else
  243.           fileMenu.add( new MenuItemV2( "Close", this ));
  244.  
  245.         displayGridCBMI = new CheckboxMenuItemV2( "Display Grid", true, this );
  246.         force16ColsCBMI = new CheckboxMenuItemV2( "Force 16 Columns", false, this );
  247.         showFontInfoCBMI = new CheckboxMenuItemV2( "Display Font Info", false, this );
  248.         optionMenu.add( displayGridCBMI );
  249.         optionMenu.add( force16ColsCBMI );
  250.         optionMenu.add( showFontInfoCBMI );
  251.  
  252.         JMenuBar mb = parent.getJMenuBar();
  253.         if ( mb == null )
  254.           mb = new JMenuBar();
  255.         mb.add( fileMenu );
  256.         mb.add( optionMenu );
  257.  
  258.         parent.setJMenuBar( mb );
  259.  
  260.         String fontList[] =
  261.           GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
  262.  
  263.         for ( int i = 0; i < fontList.length; i++ )
  264.           fontMenu.addItem( fontList[i] );
  265.         fontMenu.setSelectedItem( "Dialog" );
  266.  
  267.         styleMenu.addItem( "Plain" );
  268.         styleMenu.addItem( "Bold" );
  269.         styleMenu.addItem( "Italic" );
  270.         styleMenu.addItem( "Bold Italic" );
  271.  
  272.         transformMenu.addItem( "None" );
  273.         transformMenu.addItem( "Scale" );
  274.         transformMenu.addItem( "Shear" );
  275.         transformMenu.addItem( "Rotate" );
  276.  
  277.         transformMenuG2.addItem( "None" );
  278.         transformMenuG2.addItem( "Scale" );
  279.         transformMenuG2.addItem( "Shear" );
  280.         transformMenuG2.addItem( "Rotate" );
  281.  
  282.         methodsMenu.addItem( "drawString" );
  283.         methodsMenu.addItem( "drawChars" );
  284.         methodsMenu.addItem( "drawBytes" );
  285.         methodsMenu.addItem( "drawGlyphVector" );
  286.         methodsMenu.addItem( "TextLayout.draw" );
  287.         methodsMenu.addItem( "GlyphVector.getOutline + draw" );
  288.         methodsMenu.addItem( "TextLayout.getOutline + draw" );
  289.  
  290.         textMenu.addItem( "Unicode Range" );
  291.         textMenu.addItem( "All Glyphs" );
  292.         textMenu.addItem( "User Text" );
  293.         textMenu.addItem( "Text File" );
  294.         textMenu.addActionListener ( this ); // listener added later so unneeded events not thrown
  295.     }
  296.  
  297.     /// Sets up the all dialogs used in Font2DTest...
  298.     private void setupDialog( boolean isApplet ) {
  299.         if (!isApplet) 
  300.             filePromptDialog = new JFileChooser( );
  301.         else
  302.             filePromptDialog = null;
  303.  
  304.         /// Prepare user text dialog...
  305.         userTextDialog = new JDialog( parent, "User Text", false );
  306.         JPanel dialogTopPanel = new JPanel();
  307.         JPanel dialogBottomPanel = new JPanel();
  308.         LabelV2 message1 = new LabelV2( "Enter text below and then press update" );
  309.         LabelV2 message2 = new LabelV2( "(Unicode char can be denoted by \\uXXXX)" );
  310.         userTextArea = new JTextArea( "Java2D!" );
  311.         ButtonV2 bUpdate = new ButtonV2( "Update", this );
  312.         userTextArea.setFont( new Font( "dialog", Font.PLAIN, 12 ));
  313.         dialogTopPanel.setLayout( new GridLayout( 2, 1 ));
  314.         dialogTopPanel.add( "North", message1 );
  315.         dialogTopPanel.add( "South", message2 );
  316.         dialogBottomPanel.add( bUpdate );
  317.         //ABP
  318.         JScrollPane userTextAreaSP = new JScrollPane(userTextArea);
  319.         userTextAreaSP.setPreferredSize(new Dimension(300, 100));
  320.  
  321.         userTextDialog.getContentPane().setLayout( new BorderLayout() );
  322.         userTextDialog.getContentPane().add( "North", dialogTopPanel );
  323.         userTextDialog.getContentPane().add( "Center", userTextAreaSP );
  324.         userTextDialog.getContentPane().add( "South", dialogBottomPanel );
  325.         userTextDialog.pack();
  326.     userTextDialog.addWindowListener( new WindowAdapter() {
  327.             public void windowClosing( WindowEvent e ) {
  328.                 userTextDialog.hide();
  329.             }
  330.         });
  331.  
  332.         /// Prepare printing dialog...
  333.         printCBGroup = new ButtonGroup();
  334.         printModeCBs[ fp.ONE_PAGE ] =
  335.           new JRadioButton( "Print one page from currently displayed character/line",
  336.                          true );
  337.         printModeCBs[ fp.CUR_RANGE ] =
  338.           new JRadioButton( "Print all characters in currently selected range",
  339.                          false );
  340.         printModeCBs[ fp.ALL_TEXT ] =
  341.           new JRadioButton( "Print all lines of text",
  342.                          false );
  343.         LabelV2 l =
  344.           new LabelV2( "Note: Page range in native \"Print\" dialog will not affect the result" );
  345.         JPanel buttonPanel = new JPanel();
  346.         printModeCBs[ fp.ALL_TEXT ].setEnabled( false );
  347.         buttonPanel.add( new ButtonV2( "Print", this ));
  348.         buttonPanel.add( new ButtonV2( "Cancel", this ));
  349.  
  350.         printDialog = new JDialog( parent, "Print...", true );
  351.         printDialog.setResizable( false );
  352.     printDialog.addWindowListener( new WindowAdapter() {
  353.             public void windowClosing( WindowEvent e ) {
  354.                 printDialog.hide();
  355.             }
  356.         });
  357.         printDialog.getContentPane().setLayout( new GridLayout( printModeCBs.length + 2, 1 ));
  358.         printDialog.getContentPane().add( l );
  359.         for ( int i = 0; i < printModeCBs.length; i++ ) {
  360.             printModeCBs[i].setFont( labelFont );
  361.             printCBGroup.add( printModeCBs[i] );
  362.             printDialog.getContentPane().add( printModeCBs[i] );
  363.         }
  364.         printDialog.getContentPane().add( buttonPanel );
  365.         printDialog.pack();
  366.  
  367.         /// Prepare font information dialog...
  368.         fontInfoDialog = new JDialog( parent, "Font info", false );
  369.         fontInfoDialog.setResizable( false );
  370.         fontInfoDialog.addWindowListener( new WindowAdapter() {
  371.             public void windowClosing( WindowEvent e ) {
  372.                 fontInfoDialog.hide();
  373.                 showFontInfoCBMI.setState( false );
  374.             }
  375.         });
  376.         JPanel fontInfoPanel = new JPanel();
  377.         fontInfoPanel.setLayout( new GridLayout( fontInfos.length, 1 ));
  378.         for ( int i = 0; i < fontInfos.length; i++ ) {
  379.             fontInfos[i] = new LabelV2("");
  380.             fontInfoPanel.add( fontInfos[i] );
  381.         }
  382.         fontInfoDialog.getContentPane().add( fontInfoPanel );
  383.  
  384.         /// Move the location of the dialog...
  385.         userTextDialog.setLocation( 200, 300 );
  386.         fontInfoDialog.setLocation( 0, 400 );
  387.     }
  388.  
  389.     /// RangeMenu object signals using this function
  390.     /// when Unicode range has been changed and text needs to be redrawn
  391.     public void fireRangeChanged() {
  392.         int range[] = rm.getSelectedRange();
  393.         fp.setTextToDraw( fp.RANGE_TEXT, range, null, null );
  394.         if ( showFontInfoCBMI.getState() )
  395.           fireUpdateFontInfo();
  396.     }
  397.  
  398.     /// Changes the message on the status bar
  399.     public void fireChangeStatus( String message, boolean error ) {
  400.         /// If this is not ran as an applet, use own status bar,
  401.         /// Otherwise, use the appletviewer/browser's status bar
  402.         statusBar.setText( message );
  403.         if ( error )
  404.           fp.showingError = true;
  405.         else
  406.           fp.showingError = false;
  407.     }
  408.  
  409.     /// Updates the information about the selected font
  410.     public void fireUpdateFontInfo() {
  411.         if ( showFontInfoCBMI.getState() ) {
  412.             String infos[] = fp.getFontInfo();
  413.             for ( int i = 0; i < fontInfos.length; i++ )
  414.               fontInfos[i].setText( infos[i] );
  415.             fontInfoDialog.pack();
  416.         }
  417.     }
  418.  
  419.     /// Displays a file load/save dialog and returns the specified file
  420.     private String promptFile( boolean isSave, String initFileName ) {
  421.     int retVal;
  422.     String str;
  423.     
  424.     /// ABP
  425.     if ( filePromptDialog == null)
  426.         return null;
  427.     
  428.         if ( isSave ) {
  429.             filePromptDialog.setDialogType( JFileChooser.SAVE_DIALOG );
  430.             filePromptDialog.setDialogTitle( "Save..." );
  431.             str = "Save";
  432.  
  433.  
  434.         }
  435.         else {
  436.             filePromptDialog.setDialogType( JFileChooser.OPEN_DIALOG );
  437.             filePromptDialog.setDialogTitle( "Load..." );
  438.             str = "Load";
  439.         }
  440.         
  441.     if (initFileName != null)
  442.         filePromptDialog.setSelectedFile( new File( initFileName ) );        
  443.     retVal = filePromptDialog.showDialog( this, str );
  444.  
  445.         if ( retVal == JFileChooser.APPROVE_OPTION ) {
  446.             File file = filePromptDialog.getSelectedFile();
  447.             String fileName = file.getAbsolutePath();
  448.             if ( fileName != null ) {
  449.                 return fileName;
  450.         }
  451.     }
  452.     
  453.         return null;
  454.     }
  455.  
  456.     /// Converts user text into arrays of String, delimited at newline character
  457.     /// Also replaces any valid escape sequence with appropriate unicode character
  458.     private String[] parseUserText( String orig ) {
  459.         int length = orig.length();
  460.         StringTokenizer perLine = new StringTokenizer( orig, "\n" );
  461.         String textLines[] = new String[ perLine.countTokens() ];
  462.         int lineNumber = 0;
  463.  
  464.         while ( perLine.hasMoreElements() ) {
  465.             String oneLine = perLine.nextToken();
  466.             int lineLength = oneLine.length();
  467.             int prevEscapeEnd = 0;
  468.             int nextEscape = oneLine.indexOf( "\\u" );
  469.             StringBuffer converted = new StringBuffer();
  470.  
  471.             while ( nextEscape != -1 ) {
  472.                 if ( prevEscapeEnd < nextEscape )
  473.                   converted.append( oneLine.substring( prevEscapeEnd, nextEscape ));
  474.                 prevEscapeEnd = nextEscape + 6;
  475.                 try {
  476.                     String hex = oneLine.substring( nextEscape + 2, nextEscape + 6 );
  477.                     converted.append( (char) Integer.parseInt( hex, 16 ));
  478.                 }
  479.                 catch ( Exception e ) {
  480.                     int copyLimit =
  481.                       ( nextEscape + 6 < lineLength ) ? ( nextEscape + 6 ) : lineLength;
  482.                     converted.append( oneLine.substring( nextEscape, copyLimit ));
  483.                 }
  484.                 nextEscape = oneLine.indexOf( "\\u", prevEscapeEnd );
  485.             }
  486.             if ( prevEscapeEnd < lineLength )
  487.               converted.append( oneLine.substring( prevEscapeEnd, lineLength ));
  488.             textLines[ lineNumber++ ] = converted.toString();
  489.         }
  490.         return textLines;
  491.     }
  492.  
  493.     /// Reads the text from specified file, detecting UTF-16 encoding
  494.     /// Then breaks the text into String array, delimited at every line break
  495.     private void readTextFile( String fileName ) {
  496.         try {
  497.             String fileText, textLines[];
  498.             BufferedInputStream bis =
  499.               new BufferedInputStream( new FileInputStream( fileName ));
  500.             int numBytes = bis.available();
  501.             if (numBytes == 0) {
  502.                 throw new Exception("Text file " + fileName + " is empty");
  503.             }
  504.             byte byteData[] = new byte[ numBytes ];
  505.             bis.read( byteData, 0, numBytes );
  506.             bis.close();
  507.  
  508.             /// If byte mark is found, then use UTF-16 encoding to convert bytes...
  509.             if (numBytes >= 2 &&
  510.                 (( byteData[0] == (byte) 0xFF && byteData[1] == (byte) 0xFE ) ||
  511.                  ( byteData[0] == (byte) 0xFE && byteData[1] == (byte) 0xFF )))
  512.               fileText = new String( byteData, "UTF-16" );
  513.             /// Otherwise, use system default encoding
  514.             else
  515.               fileText = new String( byteData );
  516.  
  517.             int length = fileText.length();
  518.             StringTokenizer perLine = new StringTokenizer( fileText, "\n" );
  519.             /// Determine "Return Char" used in this file
  520.             /// This simply finds first occurrence of CR, CR+LF or LF...
  521.             for ( int i = 0; i < length; i++ ) {
  522.                 char iTh = fileText.charAt( i );
  523.                 if ( iTh == '\r' ) {
  524.                     if ( i < length - 1 && fileText.charAt( i + 1 ) == '\n' )
  525.                       perLine = new StringTokenizer( fileText, "\r\n" );
  526.                     else
  527.                       perLine = new StringTokenizer( fileText, "\r" );
  528.                     break;
  529.                 }
  530.                 else if ( iTh == '\n' )
  531.                   /// Use the one already created
  532.                   break;
  533.             }
  534.             int lineNumber = 0, numLines = perLine.countTokens();
  535.             textLines = new String[ numLines ];
  536.  
  537.             while ( perLine.hasMoreElements() ) {
  538.                 String oneLine = perLine.nextToken();
  539.                 if ( oneLine == null )
  540.                   /// To make LineBreakMeasurer to return a valid TextLayout
  541.                   /// on an empty line, simply feed it a space char...
  542.                   oneLine = " ";
  543.                 textLines[ lineNumber++ ] = oneLine;
  544.             }
  545.             fp.setTextToDraw( fp.FILE_TEXT, null, null, textLines );
  546.             rm.setEnabled( false );
  547.             methodsMenu.setEnabled( false );
  548.         }
  549.         catch ( Exception ex ) {
  550.             fireChangeStatus( "ERROR: Failed to Read Text File; See Stack Trace", true );
  551.             ex.printStackTrace();
  552.         }
  553.     }
  554.  
  555.     /// Returns a String storing current configuration
  556.     private void writeCurrentOptions( String fileName ) {
  557.         try {
  558.             String curOptions = fp.getCurrentOptions();
  559.             BufferedOutputStream bos =
  560.               new BufferedOutputStream( new FileOutputStream( fileName ));
  561.             /// Prepend title and the option that is only obtainable here
  562.             int range[] = rm.getSelectedRange();
  563.             String completeOptions =
  564.               ( "Font2DTest Option File\n" + 
  565.                 displayGridCBMI.getState() + "\n" +
  566.                 force16ColsCBMI.getState() + "\n" +
  567.                 showFontInfoCBMI.getState() + "\n" +
  568.                 rm.getSelectedItem() + "\n" +
  569.                 range[0] + "\n" + range[1] + "\n" + curOptions + tFileName);
  570.             byte toBeWritten[] = completeOptions.getBytes( "UTF-16" );
  571.             bos.write( toBeWritten, 0, toBeWritten.length );
  572.             bos.close();
  573.         }
  574.         catch ( Exception ex ) {
  575.             fireChangeStatus( "ERROR: Failed to Save Options File; See Stack Trace", true );
  576.             ex.printStackTrace();
  577.         }
  578.     }
  579.  
  580.     /// Updates GUI visibility/status after some parameters have changed
  581.     private void updateGUI() {
  582.         int selectedText = textMenu.getSelectedIndex();
  583.  
  584.         /// Set the visibility of User Text dialog
  585.         if ( selectedText == fp.USER_TEXT )
  586.           userTextDialog.show();
  587.         else
  588.           userTextDialog.hide();
  589.         /// Change the visibility/status/availability of Print JDialog buttons
  590.         printModeCBs[ fp.ONE_PAGE ].setSelected( true );
  591.         if ( selectedText == fp.FILE_TEXT || selectedText == fp.USER_TEXT ) {
  592.         /// ABP
  593.         /// update methodsMenu to show that TextLayout.draw is being used
  594.         /// when we are in FILE_TEXT mode
  595.         if ( selectedText == fp.FILE_TEXT )
  596.             methodsMenu.setSelectedItem("TextLayout.draw");         
  597.             methodsMenu.setEnabled( selectedText == fp.USER_TEXT );
  598.             printModeCBs[ fp.CUR_RANGE ].setEnabled( false );
  599.             printModeCBs[ fp.ALL_TEXT ].setEnabled( true );
  600.         }
  601.         else {
  602.         /// ABP
  603.         /// update methodsMenu to show that drawGlyph is being used
  604.         /// when we are in ALL_GLYPHS mode
  605.         if ( selectedText == fp.ALL_GLYPHS )
  606.             methodsMenu.setSelectedItem("drawGlyphVector"); 
  607.             methodsMenu.setEnabled( selectedText == fp.RANGE_TEXT );
  608.             printModeCBs[ fp.CUR_RANGE ].setEnabled( true );
  609.             printModeCBs[ fp.ALL_TEXT ].setEnabled( false );
  610.         }
  611.         /// Modify RangeMenu and fontInfo label availabilty
  612.         if ( selectedText == fp.RANGE_TEXT ) {
  613.             fontInfos[1].setVisible( true );
  614.             rm.setEnabled( true );
  615.         }
  616.         else {
  617.             fontInfos[1].setVisible( false );
  618.             rm.setEnabled( false );
  619.         }
  620.     }
  621.  
  622.     /// Loads saved options and applies them
  623.     private void loadOptions( String fileName ) {
  624.         try {
  625.             BufferedInputStream bis =
  626.               new BufferedInputStream( new FileInputStream( fileName ));
  627.             int numBytes = bis.available();
  628.             byte byteData[] = new byte[ numBytes ];
  629.             bis.read( byteData, 0, numBytes );
  630.             bis.close();
  631.             if ( numBytes < 2 || 
  632.         (byteData[0] != (byte) 0xFE || byteData[1] != (byte) 0xFF) )
  633.               throw new Exception( "Not a Font2DTest options file" );
  634.             
  635.             String options = new String( byteData, "UTF-16" );
  636.             StringTokenizer perLine = new StringTokenizer( options, "\n" );
  637.             String title = perLine.nextToken();
  638.             if ( !title.equals( "Font2DTest Option File" ))
  639.               throw new Exception( "Not a Font2DTest options file" );
  640.  
  641.             /// Parse all options
  642.             boolean displayGridOpt = new Boolean( perLine.nextToken() ).booleanValue();
  643.             boolean force16ColsOpt = new Boolean( perLine.nextToken() ).booleanValue();
  644.             boolean showFontInfoOpt = new Boolean( perLine.nextToken() ).booleanValue();
  645.             String rangeNameOpt = perLine.nextToken();
  646.             int rangeStartOpt = Integer.parseInt( perLine.nextToken() );
  647.             int rangeEndOpt = Integer.parseInt( perLine.nextToken() );
  648.             String fontNameOpt = perLine.nextToken();
  649.             int fontSizeOpt = Integer.parseInt( perLine.nextToken() );
  650.             int fontStyleOpt = Integer.parseInt( perLine.nextToken() );
  651.             int fontTransformOpt = Integer.parseInt( perLine.nextToken() );
  652.             int g2TransformOpt = Integer.parseInt( perLine.nextToken() );
  653.             int textToUseOpt = Integer.parseInt( perLine.nextToken() );
  654.             int drawMethodOpt = Integer.parseInt( perLine.nextToken() );
  655.             boolean useAntialiasOpt = new Boolean( perLine.nextToken() ).booleanValue();
  656.             boolean useFractionalOpt = new Boolean( perLine.nextToken() ).booleanValue();
  657.             String userTextOpt[] = { "Java2D!" }, dialogEntry = "Java2D!";       
  658.             if (textToUseOpt == fp.USER_TEXT )  {
  659.                 int numLines = perLine.countTokens(), lineNumber = 0;
  660.                 if ( numLines != 0 ) {
  661.                     userTextOpt = new String[ numLines ];
  662.                     dialogEntry = "";
  663.                     for ( ; perLine.hasMoreElements(); lineNumber++ ) {
  664.                         userTextOpt[ lineNumber ] = perLine.nextToken();
  665.                         dialogEntry += userTextOpt[ lineNumber ] + "\n";
  666.                     }
  667.                 }
  668.         }            
  669.  
  670.             /// Reset GUIs
  671.             displayGridCBMI.setState( displayGridOpt );
  672.             force16ColsCBMI.setState( force16ColsOpt );
  673.             showFontInfoCBMI.setState( showFontInfoOpt );
  674.             rm.setSelectedRange( rangeNameOpt, rangeStartOpt, rangeEndOpt );
  675.             fontMenu.setSelectedItem( fontNameOpt );
  676.             sizeField.setText( String.valueOf( fontSizeOpt ));
  677.             styleMenu.setSelectedIndex( fontStyleOpt );
  678.             transformMenu.setSelectedIndex( fontTransformOpt );
  679.             transformMenuG2.setSelectedIndex( g2TransformOpt );
  680.             textMenu.setSelectedIndex( textToUseOpt );
  681.             methodsMenu.setSelectedIndex( drawMethodOpt );
  682.             useAntialiasCB.setSelected( useAntialiasOpt );
  683.             useFractionalCB.setSelected( useFractionalOpt );      
  684.  
  685.             userTextArea.setText( dialogEntry );
  686.             updateGUI();
  687.  
  688.         if ( textToUseOpt == fp.FILE_TEXT ) {
  689.           tFileName = perLine.nextToken();
  690.           readTextFile(tFileName );
  691.             }
  692.  
  693.             /// Reset option variables and repaint
  694.             fp.loadOptions( displayGridOpt, force16ColsOpt, rangeStartOpt, rangeEndOpt,
  695.                             fontNameOpt, fontSizeOpt, fontStyleOpt, fontTransformOpt, g2TransformOpt,
  696.                             textToUseOpt, drawMethodOpt, useAntialiasOpt,
  697.                             useFractionalOpt, userTextOpt );
  698.             if ( showFontInfoOpt ) {
  699.                 fireUpdateFontInfo();
  700.                 fontInfoDialog.show();
  701.             }
  702.             else
  703.               fontInfoDialog.hide();
  704.         }
  705.         catch ( Exception ex ) {
  706.             fireChangeStatus( "ERROR: Failed to Load Options File; See Stack Trace", true );
  707.             ex.printStackTrace();
  708.         }
  709.     }
  710.  
  711.     /// Loads a previously saved image 
  712.     private void loadComparisonJPEG( String fileName ) {
  713.         try {
  714.             BufferedInputStream bis =
  715.               new BufferedInputStream( new FileInputStream( fileName ));
  716.             JPEGImageDecoder jid = JPEGCodec.createJPEGDecoder( bis );
  717.             BufferedImage image = jid.decodeAsBufferedImage();
  718.             bis.close();
  719.  
  720.             JFrame f = new JFrame( "Comparison JPEG" );
  721.             ImagePanel ip = new ImagePanel( image );
  722.             f.setResizable( false );
  723.             f.getContentPane().add( ip );
  724.             f.addWindowListener( new WindowAdapter() {
  725.                 public void windowClosing( WindowEvent e ) {
  726.                     ( (JFrame) e.getSource() ).dispose();
  727.                 }
  728.             });
  729.             f.pack();
  730.             f.show();
  731.         }
  732.         catch ( Exception ex ) {
  733.             fireChangeStatus( "ERROR: Failed to Load JPEG File; See Stack Trace", true );
  734.             ex.printStackTrace();
  735.         }
  736.     }
  737.  
  738.     /// Interface functions...
  739.  
  740.     /// ActionListener interface function
  741.     /// Responds to JMenuItem, JTextField and JButton actions
  742.     public void actionPerformed( ActionEvent e ) {
  743.         Object source = e.getSource();
  744.  
  745.         if ( source instanceof JMenuItem ) {
  746.             JMenuItem mi = (JMenuItem) source;
  747.             String itemName = mi.getLabel();
  748.  
  749.             if ( itemName.equals( "Save Selected Options..." )) {
  750.                 String fileName = promptFile( true, "options.txt" );
  751.                 if ( fileName != null )
  752.                   writeCurrentOptions( fileName );
  753.             }
  754.             else if ( itemName.equals( "Load Options..." )) {
  755.                 String fileName = promptFile( false, "options.txt" );
  756.                 if ( fileName != null )
  757.                   loadOptions( fileName );
  758.             }
  759.             else if ( itemName.equals( "Save as JPEG..." )) {
  760.                 String fileName = promptFile( true, fontMenu.getSelectedItem() + ".jpeg" );
  761.                 if ( fileName != null )
  762.                   fp.doSaveJPEG( fileName );
  763.             }
  764.             else if ( itemName.equals( "Load JPEG File to Compare..." )) {
  765.                 String fileName = promptFile( false, null );
  766.                 if ( fileName != null )
  767.                   loadComparisonJPEG( fileName );
  768.             }
  769.             else if ( itemName.equals( "Page Setup..." ))
  770.               fp.doPageSetup();
  771.             else if ( itemName.equals( "Print..." ))
  772.               printDialog.show();
  773.             else if ( itemName.equals( "Close" ))
  774.               parent.dispose();
  775.             else if ( itemName.equals( "Exit" ))
  776.               System.exit(0);
  777.         }
  778.  
  779.         else if ( source instanceof JTextField ) {
  780.             JTextField tf = (JTextField) source;
  781.             int sz = 12;
  782.             try {
  783.                  sz = Integer.parseInt(sizeField.getText());
  784.                  if (sz < 1 || sz > 120) {
  785.                       sz = 12;
  786.                       sizeField.setText("12");
  787.                  }
  788.             } catch (Exception se) {
  789.                  sizeField.setText("12");
  790.             }
  791.             if ( tf == sizeField )
  792.               fp.setFontParams( fontMenu.getSelectedItem(),
  793.                                 sz,
  794.                                 styleMenu.getSelectedIndex(),
  795.                                 transformMenu.getSelectedIndex() );
  796.         }
  797.  
  798.         else if ( source instanceof JButton ) {
  799.             String itemName = ( (JButton) source ).getLabel();
  800.             /// Print dialog buttons...
  801.             if ( itemName.equals( "Print" )) {
  802.                 for ( int i = 0; i < printModeCBs.length; i++ )
  803.                   if ( printModeCBs[i].isSelected() ) {
  804.                       printDialog.hide();
  805.                       fp.doPrint( i );
  806.                   }
  807.             }
  808.             else if ( itemName.equals( "Cancel" ))
  809.               printDialog.hide();
  810.             /// Update button from Usert Text JDialog...
  811.             else if ( itemName.equals( "Update" ))
  812.               fp.setTextToDraw( fp.USER_TEXT, null,
  813.                                 parseUserText( userTextArea.getText() ), null );
  814.         }
  815.         else if ( source instanceof JComboBox ) {
  816.             JComboBox c = (JComboBox) source;
  817.             
  818.             /// RangeMenu handles actions by itself and then calls fireRangeChanged,
  819.             /// so it is not listed or handled here
  820.             if ( c == fontMenu || c == styleMenu || c == transformMenu )
  821.               fp.setFontParams( fontMenu.getSelectedItem(),
  822.                                 Integer.parseInt(sizeField.getText()),
  823.                                 styleMenu.getSelectedIndex(),
  824.                                 transformMenu.getSelectedIndex() );
  825.             else if ( c == methodsMenu )
  826.               fp.setDrawMethod( methodsMenu.getSelectedIndex() );
  827.             else if ( c == textMenu ) {
  828.                 int selected = textMenu.getSelectedIndex();
  829.  
  830.                 if ( selected == fp.RANGE_TEXT )
  831.                   fp.setTextToDraw( fp.RANGE_TEXT, rm.getSelectedRange(),
  832.                                     null, null );
  833.                 else if ( selected == fp.USER_TEXT )
  834.                   fp.setTextToDraw( fp.USER_TEXT, null,
  835.                                     parseUserText( userTextArea.getText() ), null );
  836.                 else if ( selected == fp.FILE_TEXT ) {
  837.                     String fileName = promptFile( false, null );
  838.                     if ( fileName != null ) {
  839.               tFileName = fileName;
  840.               readTextFile( fileName );
  841.             } else {
  842.                         /// User cancelled selection; reset to previous choice
  843.                         c.setSelectedIndex( currentTextChoice );
  844.                         return;
  845.                     }
  846.                 }
  847.                 else if ( selected == fp.ALL_GLYPHS )
  848.                   fp.setTextToDraw( fp.ALL_GLYPHS, null, null, null );
  849.  
  850.                 updateGUI();
  851.                 currentTextChoice = selected;
  852.             }
  853.             else if ( c == transformMenuG2 ) {
  854.                 fp.setTransformG2( transformMenuG2.getSelectedIndex() );
  855.             }
  856.         }
  857.     }
  858.  
  859.     /// ItemListener interface function
  860.     /// Responds to JCheckBoxMenuItem, JComboBox and JCheckBox actions
  861.     public void itemStateChanged( ItemEvent e ) {
  862.         Object source = e.getSource();
  863.  
  864.         if ( source instanceof JCheckBoxMenuItem ) {
  865.             JCheckBoxMenuItem cbmi = (JCheckBoxMenuItem) source;
  866.             if ( cbmi == displayGridCBMI )
  867.               fp.setGridDisplay( displayGridCBMI.getState() );
  868.             else if ( cbmi == force16ColsCBMI )
  869.               fp.setForce16Columns( force16ColsCBMI.getState() );
  870.             else if ( cbmi == showFontInfoCBMI ) {
  871.                 if ( showFontInfoCBMI.getState() ) {
  872.                     fireUpdateFontInfo();
  873.                     fontInfoDialog.show();
  874.                 }
  875.                 else
  876.                   fontInfoDialog.hide();
  877.             }
  878.         }
  879.  
  880.         else if ( source instanceof JCheckBox ) {
  881.             fp.setRenderingHints( useAntialiasCB.isSelected(),
  882.                                   useFractionalCB.isSelected() );
  883.         }
  884.     }
  885.  
  886.     /// Main function
  887.     public static void main(String argv[]) {
  888.         final JFrame f = new JFrame( "Font2DTest" );
  889.         final Font2DTest f2dt = new Font2DTest( f, false );
  890.         f.addWindowListener( new WindowAdapter() {
  891.             public void windowOpening( WindowEvent e ) { f2dt.repaint(); }
  892.             public void windowClosing( WindowEvent e ) { System.exit(0); }
  893.         });
  894.  
  895.         f.getContentPane().add( f2dt );
  896.         f.pack();
  897.         f.show();
  898.     }
  899.  
  900.     /// Inner class definitions...
  901.  
  902.     /// Class to display just an image file
  903.     /// Used to show the comparison JPEG image
  904.     private final class ImagePanel extends JPanel {
  905.         private final BufferedImage bi;
  906.         
  907.         public ImagePanel( BufferedImage image ) {
  908.             bi = image;
  909.         }
  910.  
  911.         public Dimension getPreferredSize() {
  912.             return new Dimension( bi.getWidth(), bi.getHeight() );
  913.         }
  914.  
  915.         public void paintComponent( Graphics g ) {
  916.             g.drawImage( bi, 0, 0, this );
  917.         }
  918.     }
  919.  
  920.     /// Classes made to avoid repetitive calls... (being lazy)
  921.     private final class ButtonV2 extends JButton {
  922.         public ButtonV2( String name, ActionListener al ) {
  923.             super( name );
  924.             this.setFont( labelFont );
  925.             this.addActionListener( al );
  926.         }
  927.     }
  928.  
  929.     private final class ChoiceV2 extends JComboBox {
  930.     public ChoiceV2() {;}
  931.         public ChoiceV2( ActionListener al ) {
  932.             super();
  933.             this.addActionListener( al );
  934.         }
  935.     }
  936.  
  937.     private final class LabelV2 extends JLabel {
  938.         public LabelV2( String name ) {
  939.             super( name );
  940.             this.setFont( labelFont );
  941.         }
  942.     }
  943.  
  944.     private final class MenuItemV2 extends JMenuItem {
  945.         public MenuItemV2( String name, ActionListener al ) {
  946.             super( name );
  947.             this.addActionListener( al );
  948.         }
  949.     }
  950.  
  951.     private final class CheckboxMenuItemV2 extends JCheckBoxMenuItem {
  952.         public CheckboxMenuItemV2( String name, boolean b, ItemListener il ) {
  953.             super( name, b );
  954.             this.addItemListener( il );
  955.         }
  956.     }
  957. }
  958.