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