| /* |
| * 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 ); |
| } |
| } |
| } |