/* * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This source code is provided to illustrate the usage of a given feature * or technique and has been deliberately simplified. Additional steps * required for a production-quality application, such as security checks, * input validation and proper error handling, might not be present in * this sample code. */ import java.awt.Color; import java.awt.Component; import java.awt.BorderLayout; import java.awt.CheckboxGroup; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.EnumSet; import java.util.StringTokenizer; import java.util.BitSet; import javax.swing.*; import javax.swing.event.*; /** * Font2DTest.java * * @author Shinsuke Fukuda * @author Ankit Patel [Conversion to Swing - 01/07/30] */ /// Main Font2DTest Class public final class Font2DTest extends JPanel implements ActionListener, ItemListener, ChangeListener { /// JFrame that will contain Font2DTest private final JFrame parent; /// FontPanel class that will contain all graphical output private final FontPanel fp; /// RangeMenu class that contains info about the unicode ranges private final RangeMenu rm; /// Other menus to set parameters for text drawing private final ChoiceV2 fontMenu; private final JTextField sizeField; private final ChoiceV2 styleMenu; private final ChoiceV2 textMenu; private int currentTextChoice = 0; private final ChoiceV2 transformMenu; private final ChoiceV2 transformMenuG2; private final ChoiceV2 methodsMenu; private final JComboBox antiAliasMenu; private final JComboBox fracMetricsMenu; private final JSlider contrastSlider; /// CheckboxMenuItems private CheckboxMenuItemV2 displayGridCBMI; private CheckboxMenuItemV2 force16ColsCBMI; private CheckboxMenuItemV2 showFontInfoCBMI; /// JDialog boxes private JDialog userTextDialog; private JTextArea userTextArea; private JDialog printDialog; private JDialog fontInfoDialog; private LabelV2 fontInfos[] = new LabelV2[2]; private JFileChooser filePromptDialog = null; private ButtonGroup printCBGroup; private JRadioButton printModeCBs[] = new JRadioButton[3]; /// Status bar private final LabelV2 statusBar; private int fontStyles [] = {Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD | Font.ITALIC}; /// Text filename private String tFileName; // Enabled or disabled status of canDisplay check private static boolean canDisplayCheck = true; /// Initialize GUI variables and its layouts public Font2DTest( JFrame f, boolean isApplet ) { parent = f; rm = new RangeMenu( this, parent ); fp = new FontPanel( this, parent ); statusBar = new LabelV2(""); fontMenu = new ChoiceV2( this, canDisplayCheck ); sizeField = new JTextField( "12", 3 ); sizeField.addActionListener( this ); styleMenu = new ChoiceV2( this ); textMenu = new ChoiceV2( ); // listener added later transformMenu = new ChoiceV2( this ); transformMenuG2 = new ChoiceV2( this ); methodsMenu = new ChoiceV2( this ); antiAliasMenu = new JComboBox(EnumSet.allOf(FontPanel.AAValues.class).toArray()); antiAliasMenu.addActionListener(this); fracMetricsMenu = new JComboBox(EnumSet.allOf(FontPanel.FMValues.class).toArray()); fracMetricsMenu.addActionListener(this); contrastSlider = new JSlider(JSlider.HORIZONTAL, 100, 250, FontPanel.getDefaultLCDContrast().intValue()); contrastSlider.setEnabled(false); contrastSlider.setMajorTickSpacing(20); contrastSlider.setMinorTickSpacing(10); contrastSlider.setPaintTicks(true); contrastSlider.setPaintLabels(true); contrastSlider.addChangeListener(this); setupPanel(); setupMenu( isApplet ); setupDialog( isApplet ); if(canDisplayCheck) { fireRangeChanged(); } } /// Set up the main interface panel private void setupPanel() { GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1; gbc.insets = new Insets( 2, 0, 2, 2 ); this.setLayout( gbl ); addLabeledComponentToGBL( "Font: ", fontMenu, gbl, gbc, this ); addLabeledComponentToGBL( "Size: ", sizeField, gbl, gbc, this ); gbc.gridwidth = GridBagConstraints.REMAINDER; addLabeledComponentToGBL( "Font Transform:", transformMenu, gbl, gbc, this ); gbc.gridwidth = 1; addLabeledComponentToGBL( "Range: ", rm, gbl, gbc, this ); addLabeledComponentToGBL( "Style: ", styleMenu, gbl, gbc, this ); gbc.gridwidth = GridBagConstraints.REMAINDER; addLabeledComponentToGBL( "Graphics Transform: ", transformMenuG2, gbl, gbc, this ); gbc.gridwidth = 1; gbc.anchor = GridBagConstraints.WEST; addLabeledComponentToGBL( "Method: ", methodsMenu, gbl, gbc, this ); addLabeledComponentToGBL("", null, gbl, gbc, this); gbc.anchor = GridBagConstraints.EAST; gbc.gridwidth = GridBagConstraints.REMAINDER; addLabeledComponentToGBL( "Text to use:", textMenu, gbl, gbc, this ); gbc.weightx=1; gbc.gridwidth = 1; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.WEST; addLabeledComponentToGBL("LCD contrast: ", contrastSlider, gbl, gbc, this); gbc.gridwidth = 1; gbc.fill = GridBagConstraints.NONE; addLabeledComponentToGBL("Antialiasing: ", antiAliasMenu, gbl, gbc, this); gbc.anchor = GridBagConstraints.EAST; gbc.gridwidth = GridBagConstraints.REMAINDER; addLabeledComponentToGBL("Fractional metrics: ", fracMetricsMenu, gbl, gbc, this); gbc.weightx = 1; gbc.weighty = 1; gbc.anchor = GridBagConstraints.WEST; gbc.insets = new Insets( 2, 0, 0, 2 ); gbc.fill = GridBagConstraints.BOTH; gbl.setConstraints( fp, gbc ); this.add( fp ); gbc.weighty = 0; gbc.insets = new Insets( 0, 2, 0, 0 ); gbl.setConstraints( statusBar, gbc ); this.add( statusBar ); } /// Adds a component to a container with a label to its left in GridBagLayout private void addLabeledComponentToGBL( String name, JComponent c, GridBagLayout gbl, GridBagConstraints gbc, Container target ) { LabelV2 l = new LabelV2( name ); GridBagConstraints gbcLabel = (GridBagConstraints) gbc.clone(); gbcLabel.insets = new Insets( 2, 2, 2, 0 ); gbcLabel.gridwidth = 1; gbcLabel.weightx = 0; if ( c == null ) c = new JLabel( "" ); gbl.setConstraints( l, gbcLabel ); target.add( l ); gbl.setConstraints( c, gbc ); target.add( c ); } /// Sets up menu entries private void setupMenu( boolean isApplet ) { JMenu fileMenu = new JMenu( "File" ); JMenu optionMenu = new JMenu( "Option" ); fileMenu.add( new MenuItemV2( "Save Selected Options...", this )); fileMenu.add( new MenuItemV2( "Load Options...", this )); fileMenu.addSeparator(); fileMenu.add( new MenuItemV2( "Save as PNG...", this )); fileMenu.add( new MenuItemV2( "Load PNG File to Compare...", this )); fileMenu.add( new MenuItemV2( "Page Setup...", this )); fileMenu.add( new MenuItemV2( "Print...", this )); fileMenu.addSeparator(); if ( !isApplet ) fileMenu.add( new MenuItemV2( "Exit", this )); else fileMenu.add( new MenuItemV2( "Close", this )); displayGridCBMI = new CheckboxMenuItemV2( "Display Grid", true, this ); force16ColsCBMI = new CheckboxMenuItemV2( "Force 16 Columns", false, this ); showFontInfoCBMI = new CheckboxMenuItemV2( "Display Font Info", false, this ); optionMenu.add( displayGridCBMI ); optionMenu.add( force16ColsCBMI ); optionMenu.add( showFontInfoCBMI ); JMenuBar mb = parent.getJMenuBar(); if ( mb == null ) mb = new JMenuBar(); mb.add( fileMenu ); mb.add( optionMenu ); parent.setJMenuBar( mb ); String fontList[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); for ( int i = 0; i < fontList.length; i++ ) fontMenu.addItem( fontList[i] ); fontMenu.setSelectedItem( "Dialog" ); styleMenu.addItem( "Plain" ); styleMenu.addItem( "Bold" ); styleMenu.addItem( "Italic" ); styleMenu.addItem( "Bold Italic" ); transformMenu.addItem( "None" ); transformMenu.addItem( "Scale" ); transformMenu.addItem( "Shear" ); transformMenu.addItem( "Rotate" ); transformMenuG2.addItem( "None" ); transformMenuG2.addItem( "Scale" ); transformMenuG2.addItem( "Shear" ); transformMenuG2.addItem( "Rotate" ); methodsMenu.addItem( "drawString" ); methodsMenu.addItem( "drawChars" ); methodsMenu.addItem( "drawBytes" ); methodsMenu.addItem( "drawGlyphVector" ); methodsMenu.addItem( "TextLayout.draw" ); methodsMenu.addItem( "GlyphVector.getOutline + draw" ); methodsMenu.addItem( "TextLayout.getOutline + draw" ); textMenu.addItem( "Unicode Range" ); textMenu.addItem( "All Glyphs" ); textMenu.addItem( "User Text" ); textMenu.addItem( "Text File" ); textMenu.addActionListener ( this ); // listener added later so unneeded events not thrown } /// Sets up the all dialogs used in Font2DTest... private void setupDialog( boolean isApplet ) { if (!isApplet) filePromptDialog = new JFileChooser( ); else filePromptDialog = null; /// Prepare user text dialog... userTextDialog = new JDialog( parent, "User Text", false ); JPanel dialogTopPanel = new JPanel(); JPanel dialogBottomPanel = new JPanel(); LabelV2 message1 = new LabelV2( "Enter text below and then press update" ); LabelV2 message2 = new LabelV2( "(Unicode char can be denoted by \\uXXXX)" ); LabelV2 message3 = new LabelV2( "(Supplementary chars can be denoted by \\UXXXXXX)" ); userTextArea = new JTextArea( "Font2DTest!" ); ButtonV2 bUpdate = new ButtonV2( "Update", this ); userTextArea.setFont( new Font( "dialog", Font.PLAIN, 12 )); dialogTopPanel.setLayout( new GridLayout( 3, 1 )); dialogTopPanel.add( message1 ); dialogTopPanel.add( message2 ); dialogTopPanel.add( message3 ); dialogBottomPanel.add( bUpdate ); //ABP JScrollPane userTextAreaSP = new JScrollPane(userTextArea); userTextAreaSP.setPreferredSize(new Dimension(300, 100)); userTextDialog.getContentPane().setLayout( new BorderLayout() ); userTextDialog.getContentPane().add( "North", dialogTopPanel ); userTextDialog.getContentPane().add( "Center", userTextAreaSP ); userTextDialog.getContentPane().add( "South", dialogBottomPanel ); userTextDialog.pack(); userTextDialog.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { userTextDialog.hide(); } }); /// Prepare printing dialog... printCBGroup = new ButtonGroup(); printModeCBs[ fp.ONE_PAGE ] = new JRadioButton( "Print one page from currently displayed character/line", true ); printModeCBs[ fp.CUR_RANGE ] = new JRadioButton( "Print all characters in currently selected range", false ); printModeCBs[ fp.ALL_TEXT ] = new JRadioButton( "Print all lines of text", false ); LabelV2 l = new LabelV2( "Note: Page range in native \"Print\" dialog will not affect the result" ); JPanel buttonPanel = new JPanel(); printModeCBs[ fp.ALL_TEXT ].setEnabled( false ); buttonPanel.add( new ButtonV2( "Print", this )); buttonPanel.add( new ButtonV2( "Cancel", this )); printDialog = new JDialog( parent, "Print...", true ); printDialog.setResizable( false ); printDialog.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { printDialog.hide(); } }); printDialog.getContentPane().setLayout( new GridLayout( printModeCBs.length + 2, 1 )); printDialog.getContentPane().add( l ); for ( int i = 0; i < printModeCBs.length; i++ ) { printCBGroup.add( printModeCBs[i] ); printDialog.getContentPane().add( printModeCBs[i] ); } printDialog.getContentPane().add( buttonPanel ); printDialog.pack(); /// Prepare font information dialog... fontInfoDialog = new JDialog( parent, "Font info", false ); fontInfoDialog.setResizable( false ); fontInfoDialog.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { fontInfoDialog.hide(); showFontInfoCBMI.setState( false ); } }); JPanel fontInfoPanel = new JPanel(); fontInfoPanel.setLayout( new GridLayout( fontInfos.length, 1 )); for ( int i = 0; i < fontInfos.length; i++ ) { fontInfos[i] = new LabelV2(""); fontInfoPanel.add( fontInfos[i] ); } fontInfoDialog.getContentPane().add( fontInfoPanel ); /// Move the location of the dialog... userTextDialog.setLocation( 200, 300 ); fontInfoDialog.setLocation( 0, 400 ); } /// RangeMenu object signals using this function /// when Unicode range has been changed and text needs to be redrawn public void fireRangeChanged() { int range[] = rm.getSelectedRange(); fp.setTextToDraw( fp.RANGE_TEXT, range, null, null ); if(canDisplayCheck) { setupFontList(range[0], range[1]); } if ( showFontInfoCBMI.getState() ) fireUpdateFontInfo(); } /// Changes the message on the status bar public void fireChangeStatus( String message, boolean error ) { /// If this is not ran as an applet, use own status bar, /// Otherwise, use the appletviewer/browser's status bar statusBar.setText( message ); if ( error ) fp.showingError = true; else fp.showingError = false; } /// Updates the information about the selected font public void fireUpdateFontInfo() { if ( showFontInfoCBMI.getState() ) { String infos[] = fp.getFontInfo(); for ( int i = 0; i < fontInfos.length; i++ ) fontInfos[i].setText( infos[i] ); fontInfoDialog.pack(); } } private void setupFontList(int rangeStart, int rangeEnd) { int listCount = fontMenu.getItemCount(); int size = 16; try { size = Float.valueOf(sizeField.getText()).intValue(); } catch ( Exception e ) { System.out.println("Invalid font size in the size textField. Using default value of 16"); } int style = fontStyles[styleMenu.getSelectedIndex()]; Font f; for (int i = 0; i < listCount; i++) { String fontName = (String)fontMenu.getItemAt(i); f = new Font(fontName, style, size); if ((rm.getSelectedIndex() != RangeMenu.SURROGATES_AREA_INDEX) && canDisplayRange(f, rangeStart, rangeEnd)) { fontMenu.setBit(i, true); } else { fontMenu.setBit(i, false); } } fontMenu.repaint(); } protected boolean canDisplayRange(Font font, int rangeStart, int rangeEnd) { for (int i = rangeStart; i < rangeEnd; i++) { if (font.canDisplay(i)) { return true; } } return false; } /// Displays a file load/save dialog and returns the specified file private String promptFile( boolean isSave, String initFileName ) { int retVal; String str; /// ABP if ( filePromptDialog == null) return null; if ( isSave ) { filePromptDialog.setDialogType( JFileChooser.SAVE_DIALOG ); filePromptDialog.setDialogTitle( "Save..." ); str = "Save"; } else { filePromptDialog.setDialogType( JFileChooser.OPEN_DIALOG ); filePromptDialog.setDialogTitle( "Load..." ); str = "Load"; } if (initFileName != null) filePromptDialog.setSelectedFile( new File( initFileName ) ); retVal = filePromptDialog.showDialog( this, str ); if ( retVal == JFileChooser.APPROVE_OPTION ) { File file = filePromptDialog.getSelectedFile(); String fileName = file.getAbsolutePath(); if ( fileName != null ) { return fileName; } } return null; } /// Converts user text into arrays of String, delimited at newline character /// Also replaces any valid escape sequence with appropriate unicode character /// Support \\UXXXXXX notation for surrogates private String[] parseUserText( String orig ) { int length = orig.length(); StringTokenizer perLine = new StringTokenizer( orig, "\n" ); String textLines[] = new String[ perLine.countTokens() ]; int lineNumber = 0; while ( perLine.hasMoreElements() ) { StringBuffer converted = new StringBuffer(); String oneLine = perLine.nextToken(); int lineLength = oneLine.length(); int prevEscapeEnd = 0; int nextEscape = -1; do { int nextBMPEscape = oneLine.indexOf( "\\u", prevEscapeEnd ); int nextSupEscape = oneLine.indexOf( "\\U", prevEscapeEnd ); nextEscape = (nextBMPEscape < 0) ? ((nextSupEscape < 0) ? -1 : nextSupEscape) : ((nextSupEscape < 0) ? nextBMPEscape : Math.min(nextBMPEscape, nextSupEscape)); if ( nextEscape != -1 ) { if ( prevEscapeEnd < nextEscape ) converted.append( oneLine.substring( prevEscapeEnd, nextEscape )); prevEscapeEnd = nextEscape + (nextEscape == nextBMPEscape ? 6 : 8); try { String hex = oneLine.substring( nextEscape + 2, prevEscapeEnd ); if (nextEscape == nextBMPEscape) { converted.append( (char) Integer.parseInt( hex, 16 )); } else { converted.append( new String( Character.toChars( Integer.parseInt( hex, 16 )))); } } catch ( Exception e ) { int copyLimit = Math.min(lineLength, prevEscapeEnd); converted.append( oneLine.substring( nextEscape, copyLimit )); } } } while (nextEscape != -1); if ( prevEscapeEnd < lineLength ) converted.append( oneLine.substring( prevEscapeEnd, lineLength )); textLines[ lineNumber++ ] = converted.toString(); } return textLines; } /// Reads the text from specified file, detecting UTF-16 encoding /// Then breaks the text into String array, delimited at every line break private void readTextFile( String fileName ) { try { String fileText, textLines[]; BufferedInputStream bis = new BufferedInputStream( new FileInputStream( fileName )); int numBytes = bis.available(); if (numBytes == 0) { throw new Exception("Text file " + fileName + " is empty"); } byte byteData[] = new byte[ numBytes ]; bis.read( byteData, 0, numBytes ); bis.close(); /// If byte mark is found, then use UTF-16 encoding to convert bytes... if (numBytes >= 2 && (( byteData[0] == (byte) 0xFF && byteData[1] == (byte) 0xFE ) || ( byteData[0] == (byte) 0xFE && byteData[1] == (byte) 0xFF ))) fileText = new String( byteData, "UTF-16" ); /// Otherwise, use system default encoding else fileText = new String( byteData ); int length = fileText.length(); StringTokenizer perLine = new StringTokenizer( fileText, "\n" ); /// Determine "Return Char" used in this file /// This simply finds first occurrence of CR, CR+LF or LF... for ( int i = 0; i < length; i++ ) { char iTh = fileText.charAt( i ); if ( iTh == '\r' ) { if ( i < length - 1 && fileText.charAt( i + 1 ) == '\n' ) perLine = new StringTokenizer( fileText, "\r\n" ); else perLine = new StringTokenizer( fileText, "\r" ); break; } else if ( iTh == '\n' ) /// Use the one already created break; } int lineNumber = 0, numLines = perLine.countTokens(); textLines = new String[ numLines ]; while ( perLine.hasMoreElements() ) { String oneLine = perLine.nextToken(); if ( oneLine == null ) /// To make LineBreakMeasurer to return a valid TextLayout /// on an empty line, simply feed it a space char... oneLine = " "; textLines[ lineNumber++ ] = oneLine; } fp.setTextToDraw( fp.FILE_TEXT, null, null, textLines ); rm.setEnabled( false ); methodsMenu.setEnabled( false ); } catch ( Exception ex ) { fireChangeStatus( "ERROR: Failed to Read Text File; See Stack Trace", true ); ex.printStackTrace(); } } /// Returns a String storing current configuration private void writeCurrentOptions( String fileName ) { try { String curOptions = fp.getCurrentOptions(); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream( fileName )); /// Prepend title and the option that is only obtainable here int range[] = rm.getSelectedRange(); String completeOptions = ( "Font2DTest Option File\n" + displayGridCBMI.getState() + "\n" + force16ColsCBMI.getState() + "\n" + showFontInfoCBMI.getState() + "\n" + rm.getSelectedItem() + "\n" + range[0] + "\n" + range[1] + "\n" + curOptions + tFileName); byte toBeWritten[] = completeOptions.getBytes( "UTF-16" ); bos.write( toBeWritten, 0, toBeWritten.length ); bos.close(); } catch ( Exception ex ) { fireChangeStatus( "ERROR: Failed to Save Options File; See Stack Trace", true ); ex.printStackTrace(); } } /// Updates GUI visibility/status after some parameters have changed private void updateGUI() { int selectedText = textMenu.getSelectedIndex(); /// Set the visibility of User Text dialog if ( selectedText == fp.USER_TEXT ) userTextDialog.show(); else userTextDialog.hide(); /// Change the visibility/status/availability of Print JDialog buttons printModeCBs[ fp.ONE_PAGE ].setSelected( true ); if ( selectedText == fp.FILE_TEXT || selectedText == fp.USER_TEXT ) { /// ABP /// update methodsMenu to show that TextLayout.draw is being used /// when we are in FILE_TEXT mode if ( selectedText == fp.FILE_TEXT ) methodsMenu.setSelectedItem("TextLayout.draw"); methodsMenu.setEnabled( selectedText == fp.USER_TEXT ); printModeCBs[ fp.CUR_RANGE ].setEnabled( false ); printModeCBs[ fp.ALL_TEXT ].setEnabled( true ); } else { /// ABP /// update methodsMenu to show that drawGlyph is being used /// when we are in ALL_GLYPHS mode if ( selectedText == fp.ALL_GLYPHS ) methodsMenu.setSelectedItem("drawGlyphVector"); methodsMenu.setEnabled( selectedText == fp.RANGE_TEXT ); printModeCBs[ fp.CUR_RANGE ].setEnabled( true ); printModeCBs[ fp.ALL_TEXT ].setEnabled( false ); } /// Modify RangeMenu and fontInfo label availabilty if ( selectedText == fp.RANGE_TEXT ) { fontInfos[1].setVisible( true ); rm.setEnabled( true ); } else { fontInfos[1].setVisible( false ); rm.setEnabled( false ); } } /// Loads saved options and applies them private void loadOptions( String fileName ) { try { BufferedInputStream bis = new BufferedInputStream( new FileInputStream( fileName )); int numBytes = bis.available(); byte byteData[] = new byte[ numBytes ]; bis.read( byteData, 0, numBytes ); bis.close(); if ( numBytes < 2 || (byteData[0] != (byte) 0xFE || byteData[1] != (byte) 0xFF) ) throw new Exception( "Not a Font2DTest options file" ); String options = new String( byteData, "UTF-16" ); StringTokenizer perLine = new StringTokenizer( options, "\n" ); String title = perLine.nextToken(); if ( !title.equals( "Font2DTest Option File" )) throw new Exception( "Not a Font2DTest options file" ); /// Parse all options boolean displayGridOpt = Boolean.parseBoolean( perLine.nextToken() ); boolean force16ColsOpt = Boolean.parseBoolean( perLine.nextToken() ); boolean showFontInfoOpt = Boolean.parseBoolean( perLine.nextToken() ); String rangeNameOpt = perLine.nextToken(); int rangeStartOpt = Integer.parseInt( perLine.nextToken() ); int rangeEndOpt = Integer.parseInt( perLine.nextToken() ); String fontNameOpt = perLine.nextToken(); float fontSizeOpt = Float.parseFloat( perLine.nextToken() ); int fontStyleOpt = Integer.parseInt( perLine.nextToken() ); int fontTransformOpt = Integer.parseInt( perLine.nextToken() ); int g2TransformOpt = Integer.parseInt( perLine.nextToken() ); int textToUseOpt = Integer.parseInt( perLine.nextToken() ); int drawMethodOpt = Integer.parseInt( perLine.nextToken() ); int antialiasOpt = Integer.parseInt(perLine.nextToken()); int fractionalOpt = Integer.parseInt(perLine.nextToken()); int lcdContrast = Integer.parseInt(perLine.nextToken()); String userTextOpt[] = { "Font2DTest!" }; String dialogEntry = "Font2DTest!"; if (textToUseOpt == fp.USER_TEXT ) { int numLines = perLine.countTokens(), lineNumber = 0; if ( numLines != 0 ) { userTextOpt = new String[ numLines ]; dialogEntry = ""; for ( ; perLine.hasMoreElements(); lineNumber++ ) { userTextOpt[ lineNumber ] = perLine.nextToken(); dialogEntry += userTextOpt[ lineNumber ] + "\n"; } } } /// Reset GUIs displayGridCBMI.setState( displayGridOpt ); force16ColsCBMI.setState( force16ColsOpt ); showFontInfoCBMI.setState( showFontInfoOpt ); rm.setSelectedRange( rangeNameOpt, rangeStartOpt, rangeEndOpt ); fontMenu.setSelectedItem( fontNameOpt ); sizeField.setText( String.valueOf( fontSizeOpt )); styleMenu.setSelectedIndex( fontStyleOpt ); transformMenu.setSelectedIndex( fontTransformOpt ); transformMenuG2.setSelectedIndex( g2TransformOpt ); textMenu.setSelectedIndex( textToUseOpt ); methodsMenu.setSelectedIndex( drawMethodOpt ); antiAliasMenu.setSelectedIndex( antialiasOpt ); fracMetricsMenu.setSelectedIndex( fractionalOpt ); contrastSlider.setValue(lcdContrast); userTextArea.setText( dialogEntry ); updateGUI(); if ( textToUseOpt == fp.FILE_TEXT ) { tFileName = perLine.nextToken(); readTextFile(tFileName ); } /// Reset option variables and repaint fp.loadOptions( displayGridOpt, force16ColsOpt, rangeStartOpt, rangeEndOpt, fontNameOpt, fontSizeOpt, fontStyleOpt, fontTransformOpt, g2TransformOpt, textToUseOpt, drawMethodOpt, antialiasOpt, fractionalOpt, lcdContrast, userTextOpt ); if ( showFontInfoOpt ) { fireUpdateFontInfo(); fontInfoDialog.show(); } else fontInfoDialog.hide(); } catch ( Exception ex ) { fireChangeStatus( "ERROR: Failed to Load Options File; See Stack Trace", true ); ex.printStackTrace(); } } /// Loads a previously saved image private void loadComparisonPNG( String fileName ) { try { BufferedImage image = javax.imageio.ImageIO.read(new File(fileName)); JFrame f = new JFrame( "Comparison PNG" ); ImagePanel ip = new ImagePanel( image ); f.setResizable( false ); f.getContentPane().add( ip ); f.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { ( (JFrame) e.getSource() ).dispose(); } }); f.pack(); f.show(); } catch ( Exception ex ) { fireChangeStatus( "ERROR: Failed to Load PNG File; See Stack Trace", true ); ex.printStackTrace(); } } /// Interface functions... /// ActionListener interface function /// Responds to JMenuItem, JTextField and JButton actions public void actionPerformed( ActionEvent e ) { Object source = e.getSource(); if ( source instanceof JMenuItem ) { JMenuItem mi = (JMenuItem) source; String itemName = mi.getText(); if ( itemName.equals( "Save Selected Options..." )) { String fileName = promptFile( true, "options.txt" ); if ( fileName != null ) writeCurrentOptions( fileName ); } else if ( itemName.equals( "Load Options..." )) { String fileName = promptFile( false, "options.txt" ); if ( fileName != null ) loadOptions( fileName ); } else if ( itemName.equals( "Save as PNG..." )) { String fileName = promptFile( true, fontMenu.getSelectedItem() + ".png" ); if ( fileName != null ) fp.doSavePNG( fileName ); } else if ( itemName.equals( "Load PNG File to Compare..." )) { String fileName = promptFile( false, null ); if ( fileName != null ) loadComparisonPNG( fileName ); } else if ( itemName.equals( "Page Setup..." )) fp.doPageSetup(); else if ( itemName.equals( "Print..." )) printDialog.show(); else if ( itemName.equals( "Close" )) parent.dispose(); else if ( itemName.equals( "Exit" )) System.exit(0); } else if ( source instanceof JTextField ) { JTextField tf = (JTextField) source; float sz = 12f; try { sz = Float.parseFloat(sizeField.getText()); if (sz < 1f || sz > 120f) { sz = 12f; sizeField.setText("12"); } } catch (Exception se) { sizeField.setText("12"); } if ( tf == sizeField ) fp.setFontParams( fontMenu.getSelectedItem(), sz, styleMenu.getSelectedIndex(), transformMenu.getSelectedIndex() ); } else if ( source instanceof JButton ) { String itemName = ( (JButton) source ).getText(); /// Print dialog buttons... if ( itemName.equals( "Print" )) { for ( int i = 0; i < printModeCBs.length; i++ ) if ( printModeCBs[i].isSelected() ) { printDialog.hide(); fp.doPrint( i ); } } else if ( itemName.equals( "Cancel" )) printDialog.hide(); /// Update button from Usert Text JDialog... else if ( itemName.equals( "Update" )) fp.setTextToDraw( fp.USER_TEXT, null, parseUserText( userTextArea.getText() ), null ); } else if ( source instanceof JComboBox ) { JComboBox c = (JComboBox) source; /// RangeMenu handles actions by itself and then calls fireRangeChanged, /// so it is not listed or handled here if ( c == fontMenu || c == styleMenu || c == transformMenu ) { float sz = 12f; try { sz = Float.parseFloat(sizeField.getText()); if (sz < 1f || sz > 120f) { sz = 12f; sizeField.setText("12"); } } catch (Exception se) { sizeField.setText("12"); } fp.setFontParams(fontMenu.getSelectedItem(), sz, styleMenu.getSelectedIndex(), transformMenu.getSelectedIndex()); } else if ( c == methodsMenu ) fp.setDrawMethod( methodsMenu.getSelectedIndex() ); else if ( c == textMenu ) { if(canDisplayCheck) { fireRangeChanged(); } int selected = textMenu.getSelectedIndex(); if ( selected == fp.RANGE_TEXT ) fp.setTextToDraw( fp.RANGE_TEXT, rm.getSelectedRange(), null, null ); else if ( selected == fp.USER_TEXT ) fp.setTextToDraw( fp.USER_TEXT, null, parseUserText( userTextArea.getText() ), null ); else if ( selected == fp.FILE_TEXT ) { String fileName = promptFile( false, null ); if ( fileName != null ) { tFileName = fileName; readTextFile( fileName ); } else { /// User cancelled selection; reset to previous choice c.setSelectedIndex( currentTextChoice ); return; } } else if ( selected == fp.ALL_GLYPHS ) fp.setTextToDraw( fp.ALL_GLYPHS, null, null, null ); updateGUI(); currentTextChoice = selected; } else if ( c == transformMenuG2 ) { fp.setTransformG2( transformMenuG2.getSelectedIndex() ); } else if (c == antiAliasMenu || c == fracMetricsMenu) { if (c == antiAliasMenu) { boolean enabled = FontPanel.AAValues. isLCDMode(antiAliasMenu.getSelectedItem()); contrastSlider.setEnabled(enabled); } fp.setRenderingHints(antiAliasMenu.getSelectedItem(), fracMetricsMenu.getSelectedItem(), contrastSlider.getValue()); } } } public void stateChanged(ChangeEvent e) { Object source = e.getSource(); if (source instanceof JSlider) { fp.setRenderingHints(antiAliasMenu.getSelectedItem(), fracMetricsMenu.getSelectedItem(), contrastSlider.getValue()); } } /// ItemListener interface function /// Responds to JCheckBoxMenuItem, JComboBox and JCheckBox actions public void itemStateChanged( ItemEvent e ) { Object source = e.getSource(); if ( source instanceof JCheckBoxMenuItem ) { JCheckBoxMenuItem cbmi = (JCheckBoxMenuItem) source; if ( cbmi == displayGridCBMI ) fp.setGridDisplay( displayGridCBMI.getState() ); else if ( cbmi == force16ColsCBMI ) fp.setForce16Columns( force16ColsCBMI.getState() ); else if ( cbmi == showFontInfoCBMI ) { if ( showFontInfoCBMI.getState() ) { fireUpdateFontInfo(); fontInfoDialog.show(); } else fontInfoDialog.hide(); } } } private static void printUsage() { String usage = "Usage: java -jar Font2DTest.jar [options]\n" + "\nwhere options include:\n" + " -dcdc | -disablecandisplaycheck disable canDisplay check for font\n" + " -? | -help print this help message\n" + "\nExample :\n" + " To disable canDisplay check on font for ranges\n" + " java -jar Font2DTest.jar -dcdc"; System.out.println(usage); System.exit(0); } /// Main function public static void main(String argv[]) { if(argv.length > 0) { if(argv[0].equalsIgnoreCase("-disablecandisplaycheck") || argv[0].equalsIgnoreCase("-dcdc")) { canDisplayCheck = false; } else { printUsage(); } } UIManager.put("swing.boldMetal", Boolean.FALSE); final JFrame f = new JFrame( "Font2DTest" ); final Font2DTest f2dt = new Font2DTest( f, false ); f.addWindowListener( new WindowAdapter() { public void windowOpening( WindowEvent e ) { f2dt.repaint(); } public void windowClosing( WindowEvent e ) { System.exit(0); } }); f.getContentPane().add( f2dt ); f.pack(); f.show(); } /// Inner class definitions... /// Class to display just an image file /// Used to show the comparison PNG image private final class ImagePanel extends JPanel { private final BufferedImage bi; public ImagePanel( BufferedImage image ) { bi = image; } public Dimension getPreferredSize() { return new Dimension( bi.getWidth(), bi.getHeight() ); } public void paintComponent( Graphics g ) { g.drawImage( bi, 0, 0, this ); } } /// Classes made to avoid repetitive calls... (being lazy) private final class ButtonV2 extends JButton { public ButtonV2( String name, ActionListener al ) { super( name ); this.addActionListener( al ); } } private final class ChoiceV2 extends JComboBox { private BitSet bitSet = null; public ChoiceV2() {;} public ChoiceV2( ActionListener al ) { super(); this.addActionListener( al ); } public ChoiceV2( ActionListener al, boolean fontChoice) { this(al); if(fontChoice) { //Register this component in ToolTipManager setToolTipText(""); bitSet = new BitSet(); setRenderer(new ChoiceV2Renderer(this)); } } public String getToolTipText() { int index = this.getSelectedIndex(); String fontName = (String) this.getSelectedItem(); if(fontName != null && (textMenu.getSelectedIndex() == fp.RANGE_TEXT)) { if (getBit(index)) { return "Font \"" + fontName + "\" can display some characters in \"" + rm.getSelectedItem() + "\" range"; } else { return "Font \"" + fontName + "\" cannot display any characters in \"" + rm.getSelectedItem() + "\" range"; } } return super.getToolTipText(); } public void setBit(int bitIndex, boolean value) { bitSet.set(bitIndex, value); } public boolean getBit(int bitIndex) { return bitSet.get(bitIndex); } } private final class ChoiceV2Renderer extends DefaultListCellRenderer { private ImageIcon yesImage, blankImage; private ChoiceV2 choice = null; public ChoiceV2Renderer(ChoiceV2 choice) { BufferedImage yes = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB); Graphics2D g = yes.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(Color.BLUE); g.drawLine(0, 5, 3, 10); g.drawLine(1, 5, 4, 10); g.drawLine(3, 10, 10, 0); g.drawLine(4, 9, 9, 0); g.dispose(); BufferedImage blank = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB); yesImage = new ImageIcon(yes); blankImage = new ImageIcon(blank); this.choice = choice; } public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if(textMenu.getSelectedIndex() == fp.RANGE_TEXT) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); //For JComboBox if index is -1, its rendering the selected index. if(index == -1) { index = choice.getSelectedIndex(); } if(choice.getBit(index)) { setIcon(yesImage); } else { setIcon(blankImage); } } else { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); setIcon(blankImage); } return this; } } private final class LabelV2 extends JLabel { public LabelV2( String name ) { super( name ); } } private final class MenuItemV2 extends JMenuItem { public MenuItemV2( String name, ActionListener al ) { super( name ); this.addActionListener( al ); } } private final class CheckboxMenuItemV2 extends JCheckBoxMenuItem { public CheckboxMenuItemV2( String name, boolean b, ItemListener il ) { super( name, b ); this.addItemListener( il ); } } }