Path: blob/master/src/demo/share/jfc/Font2DTest/Font2DTest.java
41152 views
/*1* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/38394041import java.awt.Color;42import java.awt.Component;43import java.awt.BorderLayout;44import java.awt.CheckboxGroup;45import java.awt.Container;46import java.awt.Dimension;47import java.awt.Font;48import java.awt.Graphics;49import java.awt.Graphics2D;50import java.awt.GraphicsEnvironment;51import java.awt.GridBagConstraints;52import java.awt.GridBagLayout;53import java.awt.GridLayout;54import java.awt.Insets;55import java.awt.RenderingHints;56import java.awt.Toolkit;57import java.awt.event.ActionEvent;58import java.awt.event.ActionListener;59import java.awt.event.ItemEvent;60import java.awt.event.ItemListener;61import java.awt.event.WindowAdapter;62import java.awt.event.WindowEvent;63import java.awt.image.BufferedImage;64import java.io.BufferedInputStream;65import java.io.BufferedOutputStream;66import java.io.File;67import java.io.FileInputStream;68import java.io.FileOutputStream;69import java.util.StringTokenizer;70import java.util.BitSet;71import javax.swing.*;72import javax.swing.event.*;7374/**75* Font2DTest.java76*77* @author Shinsuke Fukuda78* @author Ankit Patel [Conversion to Swing - 01/07/30]79*/8081/// Main Font2DTest Class8283public final class Font2DTest extends JPanel84implements ActionListener, ItemListener, ChangeListener {8586/// JFrame that will contain Font2DTest87private final JFrame parent;88/// FontPanel class that will contain all graphical output89private final FontPanel fp;90/// RangeMenu class that contains info about the unicode ranges91private final RangeMenu rm;9293/// Other menus to set parameters for text drawing94private final ChoiceV2 fontMenu;95private final JTextField sizeField;96private final ChoiceV2 styleMenu;97private final ChoiceV2 textMenu;98private int currentTextChoice = 0;99private final ChoiceV2 transformMenu;100private final ChoiceV2 transformMenuG2;101private final ChoiceV2 methodsMenu;102private final JComboBox<FontPanel.AAValues> antiAliasMenu;103private final JComboBox<FontPanel.FMValues> fracMetricsMenu;104105private final JSlider contrastSlider;106107/// CheckboxMenuItems108private CheckboxMenuItemV2 displayGridCBMI;109private CheckboxMenuItemV2 force16ColsCBMI;110private CheckboxMenuItemV2 showFontInfoCBMI;111112/// JDialog boxes113private JDialog userTextDialog;114private JTextArea userTextArea;115private JDialog printDialog;116private JDialog fontInfoDialog;117private LabelV2[] fontInfos = new LabelV2[2];118private JFileChooser filePromptDialog = null;119120private ButtonGroup printCBGroup;121private JRadioButton[] printModeCBs = new JRadioButton[3];122123/// Status bar124private final LabelV2 statusBar;125126private int[] fontStyles = {Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD | Font.ITALIC};127128/// Text filename129private String tFileName;130131// Enabled or disabled status of canDisplay check132private static boolean canDisplayCheck = true;133134/// Initialize GUI variables and its layouts135public Font2DTest( JFrame f, boolean isApplet ) {136parent = f;137138rm = new RangeMenu( this, parent );139fp = new FontPanel( this, parent );140statusBar = new LabelV2("");141142fontMenu = new ChoiceV2( this, canDisplayCheck );143sizeField = new JTextField( "12", 3 );144sizeField.addActionListener( this );145styleMenu = new ChoiceV2( this );146textMenu = new ChoiceV2( ); // listener added later147transformMenu = new ChoiceV2( this );148transformMenuG2 = new ChoiceV2( this );149methodsMenu = new ChoiceV2( this );150151antiAliasMenu =152new JComboBox<>(FontPanel.AAValues.values());153antiAliasMenu.addActionListener(this);154fracMetricsMenu =155new JComboBox<>(FontPanel.FMValues.values());156fracMetricsMenu.addActionListener(this);157158contrastSlider = new JSlider(JSlider.HORIZONTAL, 100, 250,159FontPanel.getDefaultLCDContrast().intValue());160contrastSlider.setEnabled(false);161contrastSlider.setMajorTickSpacing(20);162contrastSlider.setMinorTickSpacing(10);163contrastSlider.setPaintTicks(true);164contrastSlider.setPaintLabels(true);165contrastSlider.addChangeListener(this);166setupPanel();167setupMenu( isApplet );168setupDialog( isApplet );169170if(canDisplayCheck) {171fireRangeChanged();172}173}174175/// Set up the main interface panel176private void setupPanel() {177GridBagLayout gbl = new GridBagLayout();178GridBagConstraints gbc = new GridBagConstraints();179gbc.fill = GridBagConstraints.HORIZONTAL;180gbc.weightx = 1;181gbc.insets = new Insets( 2, 0, 2, 2 );182this.setLayout( gbl );183184addLabeledComponentToGBL( "Font: ", fontMenu, gbl, gbc, this );185addLabeledComponentToGBL( "Size: ", sizeField, gbl, gbc, this );186gbc.gridwidth = GridBagConstraints.REMAINDER;187addLabeledComponentToGBL( "Font Transform:",188transformMenu, gbl, gbc, this );189gbc.gridwidth = 1;190191addLabeledComponentToGBL( "Range: ", rm, gbl, gbc, this );192addLabeledComponentToGBL( "Style: ", styleMenu, gbl, gbc, this );193gbc.gridwidth = GridBagConstraints.REMAINDER;194addLabeledComponentToGBL( "Graphics Transform: ",195transformMenuG2, gbl, gbc, this );196gbc.gridwidth = 1;197198gbc.anchor = GridBagConstraints.WEST;199addLabeledComponentToGBL( "Method: ", methodsMenu, gbl, gbc, this );200addLabeledComponentToGBL("", null, gbl, gbc, this);201gbc.anchor = GridBagConstraints.EAST;202gbc.gridwidth = GridBagConstraints.REMAINDER;203addLabeledComponentToGBL( "Text to use:", textMenu, gbl, gbc, this );204205gbc.weightx=1;206gbc.gridwidth = 1;207gbc.fill = GridBagConstraints.HORIZONTAL;208gbc.anchor = GridBagConstraints.WEST;209addLabeledComponentToGBL("LCD contrast: ",210contrastSlider, gbl, gbc, this);211212gbc.gridwidth = 1;213gbc.fill = GridBagConstraints.NONE;214addLabeledComponentToGBL("Antialiasing: ",215antiAliasMenu, gbl, gbc, this);216217gbc.anchor = GridBagConstraints.EAST;218gbc.gridwidth = GridBagConstraints.REMAINDER;219addLabeledComponentToGBL("Fractional metrics: ",220fracMetricsMenu, gbl, gbc, this);221222gbc.weightx = 1;223gbc.weighty = 1;224gbc.anchor = GridBagConstraints.WEST;225gbc.insets = new Insets( 2, 0, 0, 2 );226gbc.fill = GridBagConstraints.BOTH;227gbl.setConstraints( fp, gbc );228this.add( fp );229230gbc.weighty = 0;231gbc.insets = new Insets( 0, 2, 0, 0 );232gbl.setConstraints( statusBar, gbc );233this.add( statusBar );234}235236/// Adds a component to a container with a label to its left in GridBagLayout237private void addLabeledComponentToGBL( String name,238JComponent c,239GridBagLayout gbl,240GridBagConstraints gbc,241Container target ) {242LabelV2 l = new LabelV2( name );243GridBagConstraints gbcLabel = (GridBagConstraints) gbc.clone();244gbcLabel.insets = new Insets( 2, 2, 2, 0 );245gbcLabel.gridwidth = 1;246gbcLabel.weightx = 0;247248if ( c == null )249c = new JLabel( "" );250251gbl.setConstraints( l, gbcLabel );252target.add( l );253gbl.setConstraints( c, gbc );254target.add( c );255}256257/// Sets up menu entries258private void setupMenu( boolean isApplet ) {259JMenu fileMenu = new JMenu( "File" );260JMenu optionMenu = new JMenu( "Option" );261262fileMenu.add( new MenuItemV2( "Save Selected Options...", this ));263fileMenu.add( new MenuItemV2( "Load Options...", this ));264fileMenu.addSeparator();265fileMenu.add( new MenuItemV2( "Save as PNG...", this ));266fileMenu.add( new MenuItemV2( "Load PNG File to Compare...", this ));267fileMenu.add( new MenuItemV2( "Page Setup...", this ));268fileMenu.add( new MenuItemV2( "Print...", this ));269fileMenu.addSeparator();270if ( !isApplet )271fileMenu.add( new MenuItemV2( "Exit", this ));272else273fileMenu.add( new MenuItemV2( "Close", this ));274275displayGridCBMI = new CheckboxMenuItemV2( "Display Grid", true, this );276force16ColsCBMI = new CheckboxMenuItemV2( "Force 16 Columns", false, this );277showFontInfoCBMI = new CheckboxMenuItemV2( "Display Font Info", false, this );278optionMenu.add( displayGridCBMI );279optionMenu.add( force16ColsCBMI );280optionMenu.add( showFontInfoCBMI );281282JMenuBar mb = parent.getJMenuBar();283if ( mb == null )284mb = new JMenuBar();285mb.add( fileMenu );286mb.add( optionMenu );287288parent.setJMenuBar( mb );289290String[] fontList =291GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();292293for ( int i = 0; i < fontList.length; i++ )294fontMenu.addItem( fontList[i] );295fontMenu.setSelectedItem( "Dialog" );296297styleMenu.addItem( "Plain" );298styleMenu.addItem( "Bold" );299styleMenu.addItem( "Italic" );300styleMenu.addItem( "Bold Italic" );301302transformMenu.addItem( "None" );303transformMenu.addItem( "Scale" );304transformMenu.addItem( "Shear" );305transformMenu.addItem( "Rotate" );306307transformMenuG2.addItem( "None" );308transformMenuG2.addItem( "Scale" );309transformMenuG2.addItem( "Shear" );310transformMenuG2.addItem( "Rotate" );311312methodsMenu.addItem( "drawString" );313methodsMenu.addItem( "drawChars" );314methodsMenu.addItem( "drawBytes" );315methodsMenu.addItem( "drawGlyphVector" );316methodsMenu.addItem( "TextLayout.draw" );317methodsMenu.addItem( "GlyphVector.getOutline + draw" );318methodsMenu.addItem( "TextLayout.getOutline + draw" );319320textMenu.addItem( "Unicode Range" );321textMenu.addItem( "All Glyphs" );322textMenu.addItem( "User Text" );323textMenu.addItem( "Text File" );324textMenu.addActionListener ( this ); // listener added later so unneeded events not thrown325}326327/// Sets up the all dialogs used in Font2DTest...328private void setupDialog( boolean isApplet ) {329if (!isApplet)330filePromptDialog = new JFileChooser( );331else332filePromptDialog = null;333334/// Prepare user text dialog...335userTextDialog = new JDialog( parent, "User Text", false );336JPanel dialogTopPanel = new JPanel();337JPanel dialogBottomPanel = new JPanel();338LabelV2 message1 = new LabelV2( "Enter text below and then press update" );339LabelV2 message2 = new LabelV2( "(Unicode char can be denoted by \\uXXXX)" );340LabelV2 message3 = new LabelV2( "(Supplementary chars can be denoted by \\UXXXXXX)" );341userTextArea = new JTextArea( "Font2DTest!" );342ButtonV2 bUpdate = new ButtonV2( "Update", this );343userTextArea.setFont( new Font( "dialog", Font.PLAIN, 12 ));344dialogTopPanel.setLayout( new GridLayout( 3, 1 ));345dialogTopPanel.add( message1 );346dialogTopPanel.add( message2 );347dialogTopPanel.add( message3 );348dialogBottomPanel.add( bUpdate );349//ABP350JScrollPane userTextAreaSP = new JScrollPane(userTextArea);351userTextAreaSP.setPreferredSize(new Dimension(300, 100));352353userTextDialog.getContentPane().setLayout( new BorderLayout() );354userTextDialog.getContentPane().add( "North", dialogTopPanel );355userTextDialog.getContentPane().add( "Center", userTextAreaSP );356userTextDialog.getContentPane().add( "South", dialogBottomPanel );357userTextDialog.pack();358userTextDialog.addWindowListener( new WindowAdapter() {359public void windowClosing( WindowEvent e ) {360userTextDialog.setVisible(false);361}362});363364/// Prepare printing dialog...365printCBGroup = new ButtonGroup();366printModeCBs[ fp.ONE_PAGE ] =367new JRadioButton( "Print one page from currently displayed character/line",368true );369printModeCBs[ fp.CUR_RANGE ] =370new JRadioButton( "Print all characters in currently selected range",371false );372printModeCBs[ fp.ALL_TEXT ] =373new JRadioButton( "Print all lines of text",374false );375LabelV2 l =376new LabelV2( "Note: Page range in native \"Print\" dialog will not affect the result" );377JPanel buttonPanel = new JPanel();378printModeCBs[ fp.ALL_TEXT ].setEnabled( false );379buttonPanel.add( new ButtonV2( "Print", this ));380buttonPanel.add( new ButtonV2( "Cancel", this ));381382printDialog = new JDialog( parent, "Print...", true );383printDialog.setResizable( false );384printDialog.addWindowListener( new WindowAdapter() {385public void windowClosing( WindowEvent e ) {386printDialog.setVisible(false);387}388});389printDialog.getContentPane().setLayout( new GridLayout( printModeCBs.length + 2, 1 ));390printDialog.getContentPane().add( l );391for ( int i = 0; i < printModeCBs.length; i++ ) {392printCBGroup.add( printModeCBs[i] );393printDialog.getContentPane().add( printModeCBs[i] );394}395printDialog.getContentPane().add( buttonPanel );396printDialog.pack();397398/// Prepare font information dialog...399fontInfoDialog = new JDialog( parent, "Font info", false );400fontInfoDialog.setResizable( false );401fontInfoDialog.addWindowListener( new WindowAdapter() {402public void windowClosing( WindowEvent e ) {403fontInfoDialog.setVisible(false);404showFontInfoCBMI.setState( false );405}406});407JPanel fontInfoPanel = new JPanel();408fontInfoPanel.setLayout( new GridLayout( fontInfos.length, 1 ));409for ( int i = 0; i < fontInfos.length; i++ ) {410fontInfos[i] = new LabelV2("");411fontInfoPanel.add( fontInfos[i] );412}413fontInfoDialog.getContentPane().add( fontInfoPanel );414415/// Move the location of the dialog...416userTextDialog.setLocation( 200, 300 );417fontInfoDialog.setLocation( 0, 400 );418}419420/// RangeMenu object signals using this function421/// when Unicode range has been changed and text needs to be redrawn422public void fireRangeChanged() {423int[] range = rm.getSelectedRange();424fp.setTextToDraw( fp.RANGE_TEXT, range, null, null );425if(canDisplayCheck) {426setupFontList(range[0], range[1]);427}428if ( showFontInfoCBMI.getState() )429fireUpdateFontInfo();430}431432/// Changes the message on the status bar433public void fireChangeStatus( String message, boolean error ) {434/// If this is not ran as an applet, use own status bar,435/// Otherwise, use the appletviewer/browser's status bar436statusBar.setText( message );437if ( error )438fp.showingError = true;439else440fp.showingError = false;441}442443/// Updates the information about the selected font444public void fireUpdateFontInfo() {445if ( showFontInfoCBMI.getState() ) {446String[] infos = fp.getFontInfo();447for ( int i = 0; i < fontInfos.length; i++ )448fontInfos[i].setText( infos[i] );449fontInfoDialog.pack();450}451}452453private void setupFontList(int rangeStart, int rangeEnd) {454455int listCount = fontMenu.getItemCount();456int size = 16;457458try {459size = Float.valueOf(sizeField.getText()).intValue();460}461catch ( Exception e ) {462System.out.println("Invalid font size in the size textField. Using default value of 16");463}464465int style = fontStyles[styleMenu.getSelectedIndex()];466Font f;467for (int i = 0; i < listCount; i++) {468String fontName = fontMenu.getItemAt(i);469f = new Font(fontName, style, size);470if ((rm.getSelectedIndex() != RangeMenu.SURROGATES_AREA_INDEX) &&471canDisplayRange(f, rangeStart, rangeEnd)) {472fontMenu.setBit(i, true);473}474else {475fontMenu.setBit(i, false);476}477}478479fontMenu.repaint();480}481482protected boolean canDisplayRange(Font font, int rangeStart, int rangeEnd) {483for (int i = rangeStart; i < rangeEnd; i++) {484if (font.canDisplay(i)) {485return true;486}487}488return false;489}490491/// Displays a file load/save dialog and returns the specified file492private String promptFile( boolean isSave, String initFileName ) {493int retVal;494String str;495496/// ABP497if ( filePromptDialog == null)498return null;499500if ( isSave ) {501filePromptDialog.setDialogType( JFileChooser.SAVE_DIALOG );502filePromptDialog.setDialogTitle( "Save..." );503str = "Save";504505506}507else {508filePromptDialog.setDialogType( JFileChooser.OPEN_DIALOG );509filePromptDialog.setDialogTitle( "Load..." );510str = "Load";511}512513if (initFileName != null)514filePromptDialog.setSelectedFile( new File( initFileName ) );515retVal = filePromptDialog.showDialog( this, str );516517if ( retVal == JFileChooser.APPROVE_OPTION ) {518File file = filePromptDialog.getSelectedFile();519String fileName = file.getAbsolutePath();520if ( fileName != null ) {521return fileName;522}523}524525return null;526}527528/// Converts user text into arrays of String, delimited at newline character529/// Also replaces any valid escape sequence with appropriate unicode character530/// Support \\UXXXXXX notation for surrogates531private String[] parseUserText( String orig ) {532int length = orig.length();533StringTokenizer perLine = new StringTokenizer( orig, "\n" );534String[] textLines = new String[ perLine.countTokens() ];535int lineNumber = 0;536537while ( perLine.hasMoreElements() ) {538StringBuffer converted = new StringBuffer();539String oneLine = perLine.nextToken();540int lineLength = oneLine.length();541int prevEscapeEnd = 0;542int nextEscape = -1;543do {544int nextBMPEscape = oneLine.indexOf( "\\u", prevEscapeEnd );545int nextSupEscape = oneLine.indexOf( "\\U", prevEscapeEnd );546nextEscape = (nextBMPEscape < 0)547? ((nextSupEscape < 0)548? -1549: nextSupEscape)550: ((nextSupEscape < 0)551? nextBMPEscape552: Math.min(nextBMPEscape, nextSupEscape));553554if ( nextEscape != -1 ) {555if ( prevEscapeEnd < nextEscape )556converted.append( oneLine.substring( prevEscapeEnd, nextEscape ));557558prevEscapeEnd = nextEscape + (nextEscape == nextBMPEscape ? 6 : 8);559try {560String hex = oneLine.substring( nextEscape + 2, prevEscapeEnd );561if (nextEscape == nextBMPEscape) {562converted.append( (char) Integer.parseInt( hex, 16 ));563} else {564converted.append( new String( Character.toChars( Integer.parseInt( hex, 16 ))));565}566}567catch ( Exception e ) {568int copyLimit = Math.min(lineLength, prevEscapeEnd);569converted.append( oneLine.substring( nextEscape, copyLimit ));570}571}572} while (nextEscape != -1);573if ( prevEscapeEnd < lineLength )574converted.append( oneLine.substring( prevEscapeEnd, lineLength ));575textLines[ lineNumber++ ] = converted.toString();576}577return textLines;578}579580/// Reads the text from specified file, detecting UTF-16 encoding581/// Then breaks the text into String array, delimited at every line break582private void readTextFile( String fileName ) {583try {584String fileText;585String[] textLines;586BufferedInputStream bis =587new BufferedInputStream( new FileInputStream( fileName ));588int numBytes = bis.available();589if (numBytes == 0) {590throw new Exception("Text file " + fileName + " is empty");591}592byte[] byteData = new byte[ numBytes ];593bis.read( byteData, 0, numBytes );594bis.close();595596/// If byte mark is found, then use UTF-16 encoding to convert bytes...597if (numBytes >= 2 &&598(( byteData[0] == (byte) 0xFF && byteData[1] == (byte) 0xFE ) ||599( byteData[0] == (byte) 0xFE && byteData[1] == (byte) 0xFF )))600fileText = new String( byteData, "UTF-16" );601/// Otherwise, use system default encoding602else603fileText = new String( byteData );604605int length = fileText.length();606StringTokenizer perLine = new StringTokenizer( fileText, "\n" );607/// Determine "Return Char" used in this file608/// This simply finds first occurrence of CR, CR+LF or LF...609for ( int i = 0; i < length; i++ ) {610char iTh = fileText.charAt( i );611if ( iTh == '\r' ) {612if ( i < length - 1 && fileText.charAt( i + 1 ) == '\n' )613perLine = new StringTokenizer( fileText, "\r\n" );614else615perLine = new StringTokenizer( fileText, "\r" );616break;617}618else if ( iTh == '\n' )619/// Use the one already created620break;621}622int lineNumber = 0, numLines = perLine.countTokens();623textLines = new String[ numLines ];624625while ( perLine.hasMoreElements() ) {626String oneLine = perLine.nextToken();627if ( oneLine == null )628/// To make LineBreakMeasurer to return a valid TextLayout629/// on an empty line, simply feed it a space char...630oneLine = " ";631textLines[ lineNumber++ ] = oneLine;632}633fp.setTextToDraw( fp.FILE_TEXT, null, null, textLines );634rm.setEnabled( false );635methodsMenu.setEnabled( false );636}637catch ( Exception ex ) {638fireChangeStatus( "ERROR: Failed to Read Text File; See Stack Trace", true );639ex.printStackTrace();640}641}642643/// Returns a String storing current configuration644private void writeCurrentOptions( String fileName ) {645try {646String curOptions = fp.getCurrentOptions();647BufferedOutputStream bos =648new BufferedOutputStream( new FileOutputStream( fileName ));649/// Prepend title and the option that is only obtainable here650int[] range = rm.getSelectedRange();651String completeOptions =652( "Font2DTest Option File\n" +653displayGridCBMI.getState() + "\n" +654force16ColsCBMI.getState() + "\n" +655showFontInfoCBMI.getState() + "\n" +656rm.getSelectedItem() + "\n" +657range[0] + "\n" + range[1] + "\n" + curOptions + tFileName);658byte[] toBeWritten = completeOptions.getBytes( "UTF-16" );659bos.write( toBeWritten, 0, toBeWritten.length );660bos.close();661}662catch ( Exception ex ) {663fireChangeStatus( "ERROR: Failed to Save Options File; See Stack Trace", true );664ex.printStackTrace();665}666}667668/// Updates GUI visibility/status after some parameters have changed669private void updateGUI() {670int selectedText = textMenu.getSelectedIndex();671672/// Set the visibility of User Text dialog673if ( selectedText == fp.USER_TEXT )674userTextDialog.setVisible(true);675else676userTextDialog.setVisible(false);677/// Change the visibility/status/availability of Print JDialog buttons678printModeCBs[ fp.ONE_PAGE ].setSelected( true );679if ( selectedText == fp.FILE_TEXT || selectedText == fp.USER_TEXT ) {680/// ABP681/// update methodsMenu to show that TextLayout.draw is being used682/// when we are in FILE_TEXT mode683if ( selectedText == fp.FILE_TEXT )684methodsMenu.setSelectedItem("TextLayout.draw");685methodsMenu.setEnabled( selectedText == fp.USER_TEXT );686printModeCBs[ fp.CUR_RANGE ].setEnabled( false );687printModeCBs[ fp.ALL_TEXT ].setEnabled( true );688}689else {690/// ABP691/// update methodsMenu to show that drawGlyph is being used692/// when we are in ALL_GLYPHS mode693if ( selectedText == fp.ALL_GLYPHS )694methodsMenu.setSelectedItem("drawGlyphVector");695methodsMenu.setEnabled( selectedText == fp.RANGE_TEXT );696printModeCBs[ fp.CUR_RANGE ].setEnabled( true );697printModeCBs[ fp.ALL_TEXT ].setEnabled( false );698}699/// Modify RangeMenu and fontInfo label availabilty700if ( selectedText == fp.RANGE_TEXT ) {701fontInfos[1].setVisible( true );702rm.setEnabled( true );703}704else {705fontInfos[1].setVisible( false );706rm.setEnabled( false );707}708}709710/// Loads saved options and applies them711private void loadOptions( String fileName ) {712try {713BufferedInputStream bis =714new BufferedInputStream( new FileInputStream( fileName ));715int numBytes = bis.available();716byte[] byteData = new byte[ numBytes ];717bis.read( byteData, 0, numBytes );718bis.close();719if ( numBytes < 2 ||720(byteData[0] != (byte) 0xFE || byteData[1] != (byte) 0xFF) )721throw new Exception( "Not a Font2DTest options file" );722723String options = new String( byteData, "UTF-16" );724StringTokenizer perLine = new StringTokenizer( options, "\n" );725String title = perLine.nextToken();726if ( !title.equals( "Font2DTest Option File" ))727throw new Exception( "Not a Font2DTest options file" );728729/// Parse all options730boolean displayGridOpt = Boolean.parseBoolean( perLine.nextToken() );731boolean force16ColsOpt = Boolean.parseBoolean( perLine.nextToken() );732boolean showFontInfoOpt = Boolean.parseBoolean( perLine.nextToken() );733String rangeNameOpt = perLine.nextToken();734int rangeStartOpt = Integer.parseInt( perLine.nextToken() );735int rangeEndOpt = Integer.parseInt( perLine.nextToken() );736String fontNameOpt = perLine.nextToken();737float fontSizeOpt = Float.parseFloat( perLine.nextToken() );738int fontStyleOpt = Integer.parseInt( perLine.nextToken() );739int fontTransformOpt = Integer.parseInt( perLine.nextToken() );740int g2TransformOpt = Integer.parseInt( perLine.nextToken() );741int textToUseOpt = Integer.parseInt( perLine.nextToken() );742int drawMethodOpt = Integer.parseInt( perLine.nextToken() );743int antialiasOpt = Integer.parseInt(perLine.nextToken());744int fractionalOpt = Integer.parseInt(perLine.nextToken());745int lcdContrast = Integer.parseInt(perLine.nextToken());746String[] userTextOpt = { "Font2DTest!" };747String dialogEntry = "Font2DTest!";748if (textToUseOpt == fp.USER_TEXT ) {749int numLines = perLine.countTokens(), lineNumber = 0;750if ( numLines != 0 ) {751userTextOpt = new String[ numLines ];752dialogEntry = "";753for ( ; perLine.hasMoreElements(); lineNumber++ ) {754userTextOpt[ lineNumber ] = perLine.nextToken();755dialogEntry += userTextOpt[ lineNumber ] + "\n";756}757}758}759760/// Reset GUIs761displayGridCBMI.setState( displayGridOpt );762force16ColsCBMI.setState( force16ColsOpt );763showFontInfoCBMI.setState( showFontInfoOpt );764rm.setSelectedRange( rangeNameOpt, rangeStartOpt, rangeEndOpt );765fontMenu.setSelectedItem( fontNameOpt );766sizeField.setText( String.valueOf( fontSizeOpt ));767styleMenu.setSelectedIndex( fontStyleOpt );768transformMenu.setSelectedIndex( fontTransformOpt );769transformMenuG2.setSelectedIndex( g2TransformOpt );770textMenu.setSelectedIndex( textToUseOpt );771methodsMenu.setSelectedIndex( drawMethodOpt );772antiAliasMenu.setSelectedIndex( antialiasOpt );773fracMetricsMenu.setSelectedIndex( fractionalOpt );774contrastSlider.setValue(lcdContrast);775776userTextArea.setText( dialogEntry );777updateGUI();778779if ( textToUseOpt == fp.FILE_TEXT ) {780tFileName = perLine.nextToken();781readTextFile(tFileName );782}783784/// Reset option variables and repaint785fp.loadOptions( displayGridOpt, force16ColsOpt,786rangeStartOpt, rangeEndOpt,787fontNameOpt, fontSizeOpt,788fontStyleOpt, fontTransformOpt, g2TransformOpt,789textToUseOpt, drawMethodOpt,790antialiasOpt, fractionalOpt,791lcdContrast, userTextOpt );792if ( showFontInfoOpt ) {793fireUpdateFontInfo();794fontInfoDialog.setVisible(true);795}796else797fontInfoDialog.setVisible(false);798}799catch ( Exception ex ) {800fireChangeStatus( "ERROR: Failed to Load Options File; See Stack Trace", true );801ex.printStackTrace();802}803}804805/// Loads a previously saved image806private void loadComparisonPNG( String fileName ) {807try {808BufferedImage image =809javax.imageio.ImageIO.read(new File(fileName));810JFrame f = new JFrame( "Comparison PNG" );811ImagePanel ip = new ImagePanel( image );812f.setResizable( false );813f.getContentPane().add( ip );814f.addWindowListener( new WindowAdapter() {815public void windowClosing( WindowEvent e ) {816( (JFrame) e.getSource() ).dispose();817}818});819f.pack();820f.setVisible(true);821}822catch ( Exception ex ) {823fireChangeStatus( "ERROR: Failed to Load PNG File; See Stack Trace", true );824ex.printStackTrace();825}826}827828/// Interface functions...829830/// ActionListener interface function831/// Responds to JMenuItem, JTextField and JButton actions832public void actionPerformed( ActionEvent e ) {833Object source = e.getSource();834835if ( source instanceof JMenuItem ) {836JMenuItem mi = (JMenuItem) source;837String itemName = mi.getText();838839if ( itemName.equals( "Save Selected Options..." )) {840String fileName = promptFile( true, "options.txt" );841if ( fileName != null )842writeCurrentOptions( fileName );843}844else if ( itemName.equals( "Load Options..." )) {845String fileName = promptFile( false, "options.txt" );846if ( fileName != null )847loadOptions( fileName );848}849else if ( itemName.equals( "Save as PNG..." )) {850String fileName = promptFile( true, fontMenu.getSelectedItem() + ".png" );851if ( fileName != null )852fp.doSavePNG( fileName );853}854else if ( itemName.equals( "Load PNG File to Compare..." )) {855String fileName = promptFile( false, null );856if ( fileName != null )857loadComparisonPNG( fileName );858}859else if ( itemName.equals( "Page Setup..." ))860fp.doPageSetup();861else if ( itemName.equals( "Print..." ))862printDialog.setVisible(true);863else if ( itemName.equals( "Close" ))864parent.dispose();865else if ( itemName.equals( "Exit" ))866System.exit(0);867}868869else if ( source instanceof JTextField ) {870JTextField tf = (JTextField) source;871float sz = 12f;872try {873sz = Float.parseFloat(sizeField.getText());874if (sz < 1f || sz > 120f) {875sz = 12f;876sizeField.setText("12");877}878} catch (Exception se) {879sizeField.setText("12");880}881if ( tf == sizeField )882fp.setFontParams( fontMenu.getSelectedItem(),883sz,884styleMenu.getSelectedIndex(),885transformMenu.getSelectedIndex() );886}887888else if ( source instanceof JButton ) {889String itemName = ( (JButton) source ).getText();890/// Print dialog buttons...891if ( itemName.equals( "Print" )) {892for ( int i = 0; i < printModeCBs.length; i++ )893if ( printModeCBs[i].isSelected() ) {894printDialog.setVisible(false);895fp.doPrint( i );896}897}898else if ( itemName.equals( "Cancel" ))899printDialog.setVisible(false);900/// Update button from Usert Text JDialog...901else if ( itemName.equals( "Update" ))902fp.setTextToDraw( fp.USER_TEXT, null,903parseUserText( userTextArea.getText() ), null );904}905else if ( source instanceof JComboBox ) {906JComboBox<?> c = (JComboBox<?>) source;907908/// RangeMenu handles actions by itself and then calls fireRangeChanged,909/// so it is not listed or handled here910if ( c == fontMenu || c == styleMenu || c == transformMenu ) {911float sz = 12f;912try {913sz = Float.parseFloat(sizeField.getText());914if (sz < 1f || sz > 120f) {915sz = 12f;916sizeField.setText("12");917}918} catch (Exception se) {919sizeField.setText("12");920}921fp.setFontParams(fontMenu.getSelectedItem(),922sz,923styleMenu.getSelectedIndex(),924transformMenu.getSelectedIndex());925} else if ( c == methodsMenu )926fp.setDrawMethod( methodsMenu.getSelectedIndex() );927else if ( c == textMenu ) {928929if(canDisplayCheck) {930fireRangeChanged();931}932933int selected = textMenu.getSelectedIndex();934935if ( selected == fp.RANGE_TEXT )936fp.setTextToDraw( fp.RANGE_TEXT, rm.getSelectedRange(),937null, null );938else if ( selected == fp.USER_TEXT )939fp.setTextToDraw( fp.USER_TEXT, null,940parseUserText( userTextArea.getText() ), null );941else if ( selected == fp.FILE_TEXT ) {942String fileName = promptFile( false, null );943if ( fileName != null ) {944tFileName = fileName;945readTextFile( fileName );946} else {947/// User cancelled selection; reset to previous choice948c.setSelectedIndex( currentTextChoice );949return;950}951}952else if ( selected == fp.ALL_GLYPHS )953fp.setTextToDraw( fp.ALL_GLYPHS, null, null, null );954955updateGUI();956currentTextChoice = selected;957}958else if ( c == transformMenuG2 ) {959fp.setTransformG2( transformMenuG2.getSelectedIndex() );960}961else if (c == antiAliasMenu || c == fracMetricsMenu) {962if (c == antiAliasMenu) {963boolean enabled = FontPanel.AAValues.964isLCDMode(antiAliasMenu.getSelectedItem());965contrastSlider.setEnabled(enabled);966}967fp.setRenderingHints(antiAliasMenu.getSelectedItem(),968fracMetricsMenu.getSelectedItem(),969contrastSlider.getValue());970}971}972}973974public void stateChanged(ChangeEvent e) {975Object source = e.getSource();976if (source instanceof JSlider) {977fp.setRenderingHints(antiAliasMenu.getSelectedItem(),978fracMetricsMenu.getSelectedItem(),979contrastSlider.getValue());980}981}982983/// ItemListener interface function984/// Responds to JCheckBoxMenuItem, JComboBox and JCheckBox actions985public void itemStateChanged( ItemEvent e ) {986Object source = e.getSource();987988if ( source instanceof JCheckBoxMenuItem ) {989JCheckBoxMenuItem cbmi = (JCheckBoxMenuItem) source;990if ( cbmi == displayGridCBMI )991fp.setGridDisplay( displayGridCBMI.getState() );992else if ( cbmi == force16ColsCBMI )993fp.setForce16Columns( force16ColsCBMI.getState() );994else if ( cbmi == showFontInfoCBMI ) {995if ( showFontInfoCBMI.getState() ) {996fireUpdateFontInfo();997fontInfoDialog.setVisible(true);998}999else1000fontInfoDialog.setVisible(false);1001}1002}1003}10041005private static void printUsage() {1006String usage = "Usage: java -jar Font2DTest.jar [options]\n" +1007"\nwhere options include:\n" +1008" -dcdc | -disablecandisplaycheck disable canDisplay check for font\n" +1009" -? | -help print this help message\n" +1010"\nExample :\n" +1011" To disable canDisplay check on font for ranges\n" +1012" java -jar Font2DTest.jar -dcdc";1013System.out.println(usage);1014System.exit(0);1015}10161017/// Main function1018public static void main(String[] argv) {10191020if(argv.length > 0) {1021if(argv[0].equalsIgnoreCase("-disablecandisplaycheck") ||1022argv[0].equalsIgnoreCase("-dcdc")) {1023canDisplayCheck = false;1024}1025else {1026printUsage();1027}1028}10291030UIManager.put("swing.boldMetal", Boolean.FALSE);1031final JFrame f = new JFrame( "Font2DTest" );1032final Font2DTest f2dt = new Font2DTest( f, false );1033f.addWindowListener( new WindowAdapter() {1034public void windowOpening( WindowEvent e ) { f2dt.repaint(); }1035public void windowClosing( WindowEvent e ) { System.exit(0); }1036});10371038f.getContentPane().add( f2dt );1039f.pack();1040f.setVisible(true);1041}10421043/// Inner class definitions...10441045/// Class to display just an image file1046/// Used to show the comparison PNG image1047private final class ImagePanel extends JPanel {1048private final BufferedImage bi;10491050public ImagePanel( BufferedImage image ) {1051bi = image;1052}10531054public Dimension getPreferredSize() {1055return new Dimension( bi.getWidth(), bi.getHeight() );1056}10571058public void paintComponent( Graphics g ) {1059g.drawImage( bi, 0, 0, this );1060}1061}10621063/// Classes made to avoid repetitive calls... (being lazy)1064private final class ButtonV2 extends JButton {1065public ButtonV2( String name, ActionListener al ) {1066super( name );1067this.addActionListener( al );1068}1069}10701071private final class ChoiceV2 extends JComboBox<String> {10721073private BitSet bitSet = null;10741075public ChoiceV2() {;}10761077public ChoiceV2( ActionListener al ) {1078super();1079this.addActionListener( al );1080}10811082public ChoiceV2( ActionListener al, boolean fontChoice) {1083this(al);1084if(fontChoice) {1085//Register this component in ToolTipManager1086setToolTipText("");1087bitSet = new BitSet();1088setRenderer(new ChoiceV2Renderer(this));1089}1090}10911092public String getToolTipText() {1093int index = this.getSelectedIndex();1094String fontName = (String) this.getSelectedItem();1095if(fontName != null &&1096(textMenu.getSelectedIndex() == fp.RANGE_TEXT)) {1097if (getBit(index)) {1098return "Font \"" + fontName + "\" can display some characters in \"" +1099rm.getSelectedItem() + "\" range";1100}1101else {1102return "Font \"" + fontName + "\" cannot display any characters in \"" +1103rm.getSelectedItem() + "\" range";1104}1105}1106return super.getToolTipText();1107}11081109public void setBit(int bitIndex, boolean value) {1110bitSet.set(bitIndex, value);1111}11121113public boolean getBit(int bitIndex) {1114return bitSet.get(bitIndex);1115}1116}11171118private final class ChoiceV2Renderer extends DefaultListCellRenderer {11191120private ImageIcon yesImage, blankImage;1121private ChoiceV2 choice = null;11221123public ChoiceV2Renderer(ChoiceV2 choice) {1124BufferedImage yes =1125new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);1126Graphics2D g = yes.createGraphics();1127g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,1128RenderingHints.VALUE_ANTIALIAS_ON);1129g.setColor(Color.BLUE);1130g.drawLine(0, 5, 3, 10);1131g.drawLine(1, 5, 4, 10);1132g.drawLine(3, 10, 10, 0);1133g.drawLine(4, 9, 9, 0);1134g.dispose();1135BufferedImage blank =1136new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);1137yesImage = new ImageIcon(yes);1138blankImage = new ImageIcon(blank);1139this.choice = choice;1140}11411142public Component getListCellRendererComponent(JList<?> list,1143Object value,1144int index,1145boolean isSelected,1146boolean cellHasFocus) {11471148if(textMenu.getSelectedIndex() == fp.RANGE_TEXT) {11491150super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);11511152//For JComboBox if index is -1, its rendering the selected index.1153if(index == -1) {1154index = choice.getSelectedIndex();1155}11561157if(choice.getBit(index)) {1158setIcon(yesImage);1159}1160else {1161setIcon(blankImage);1162}11631164} else {1165super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);1166setIcon(blankImage);1167}11681169return this;1170}1171}11721173private final class LabelV2 extends JLabel {1174public LabelV2( String name ) {1175super( name );1176}1177}11781179private final class MenuItemV2 extends JMenuItem {1180public MenuItemV2( String name, ActionListener al ) {1181super( name );1182this.addActionListener( al );1183}1184}11851186private final class CheckboxMenuItemV2 extends JCheckBoxMenuItem {1187public CheckboxMenuItemV2( String name, boolean b, ItemListener il ) {1188super( name, b );1189this.addItemListener( il );1190}1191}1192}119311941195