1 /* 2 * Copyright (c) 2000, 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 */ 43 44 import java.awt.BorderLayout; 45 import java.awt.Font; 46 import java.awt.event.ActionEvent; 47 import java.awt.event.ActionListener; 48 import java.awt.event.ItemEvent; 49 import java.awt.event.ItemListener; 50 51 import javax.swing.*; 52 53 import java.util.*; 54 import java.util.regex.*; 55 56 /** 57 * RangeMenu.java 58 * 59 * @author Shinsuke Fukuda 60 * @author Ankit Patel [Conversion to Swing - 01/07/30] 61 */ 62 63 /// Custom made choice menu that holds data for unicode range 64 65 public final class RangeMenu extends JComboBox implements ActionListener { 66 67 private static final int[][] UNICODE_RANGES = getUnicodeRanges(); 68 private static final String[] UNICODE_RANGE_NAMES = getUnicodeRangeNames(); 69 70 private boolean useCustomRange = false; 71 private int[] customRange = { 0x0000, 0x007f }; 72 73 /// Custom range dialog variables 74 private final JDialog customRangeDialog; 75 private final JTextField customRangeStart = new JTextField( "0000", 4 ); 76 private final JTextField customRangeEnd = new JTextField( "007F", 4 ); 77 private final int CUSTOM_RANGE_INDEX = UNICODE_RANGE_NAMES.length - 1; 78 79 /// Parent Font2DTest Object holder 80 private final Font2DTest parent; 81 82 public static final int SURROGATES_AREA_INDEX = 91; 83 84 public RangeMenu( Font2DTest demo, JFrame f ) { 85 super(); 86 parent = demo; 87 88 for ( int i = 0; i < UNICODE_RANGE_NAMES.length; i++ ) 89 addItem( UNICODE_RANGE_NAMES[i] ); 90 91 setSelectedIndex( 0 ); 92 addActionListener( this ); 93 94 /// Set up custom range dialog... 95 customRangeDialog = new JDialog( f, "Custom Unicode Range", true ); 96 customRangeDialog.setResizable( false ); 97 98 JPanel dialogTop = new JPanel(); 99 JPanel dialogBottom = new JPanel(); 100 JButton okButton = new JButton("OK"); 101 JLabel from = new JLabel( "From:" ); 102 JLabel to = new JLabel("To:"); 103 Font labelFont = new Font( "dialog", Font.BOLD, 12 ); 104 from.setFont( labelFont ); 105 to.setFont( labelFont ); 106 okButton.setFont( labelFont ); 107 108 dialogTop.add( from ); 109 dialogTop.add( customRangeStart ); 110 dialogTop.add( to ); 111 dialogTop.add( customRangeEnd ); 112 dialogBottom.add( okButton ); 113 okButton.addActionListener( this ); 114 115 customRangeDialog.getContentPane().setLayout( new BorderLayout() ); 116 customRangeDialog.getContentPane().add( "North", dialogTop ); 117 customRangeDialog.getContentPane().add( "South", dialogBottom ); 118 customRangeDialog.pack(); 119 } 120 121 /// Return the range that is currently selected 122 123 public int[] getSelectedRange() { 124 if ( useCustomRange ) { 125 int startIndex, endIndex; 126 String startText, endText; 127 String empty = ""; 128 try { 129 startText = customRangeStart.getText().trim(); 130 endText = customRangeEnd.getText().trim(); 131 if ( startText.equals(empty) && !endText.equals(empty) ) { 132 endIndex = Integer.parseInt( endText, 16 ); 133 startIndex = endIndex - 7*25; 134 } 135 else if ( !startText.equals(empty) && endText.equals(empty) ) { 136 startIndex = Integer.parseInt( startText, 16 ); 137 endIndex = startIndex + 7*25; 138 } 139 else { 140 startIndex = Integer.parseInt( customRangeStart.getText(), 16 ); 141 endIndex = Integer.parseInt( customRangeEnd.getText(), 16 ); 142 } 143 } 144 catch ( Exception e ) { 145 /// Error in parsing the hex number --- 146 /// Reset the range to what it was before and return that 147 customRangeStart.setText( Integer.toString( customRange[0], 16 )); 148 customRangeEnd.setText( Integer.toString( customRange[1], 16 )); 149 return customRange; 150 } 151 152 if ( startIndex < 0 ) 153 startIndex = 0; 154 if ( endIndex > 0xffff ) 155 endIndex = 0xffff; 156 if ( startIndex > endIndex ) 157 startIndex = endIndex; 158 159 customRange[0] = startIndex; 160 customRange[1] = endIndex; 161 return customRange; 162 } 163 else 164 return UNICODE_RANGES[ getSelectedIndex() ]; 165 } 166 167 /// Function used by loadOptions in Font2DTest main panel 168 /// to reset setting and range selection 169 public void setSelectedRange( String name, int start, int end ) { 170 setSelectedItem( name ); 171 customRange[0] = start; 172 customRange[1] = end; 173 parent.fireRangeChanged(); 174 } 175 176 /// ActionListener interface function 177 /// ABP 178 /// moved JComboBox event code into this fcn from 179 /// itemStateChanged() method. Part of change to Swing. 180 public void actionPerformed( ActionEvent e ) { 181 Object source = e.getSource(); 182 183 if ( source instanceof JComboBox ) { 184 String rangeName = (String)((JComboBox)source).getSelectedItem(); 185 186 if ( rangeName.equals("Custom...") ) { 187 useCustomRange = true; 188 customRangeDialog.setLocationRelativeTo(parent); 189 customRangeDialog.show(); 190 } 191 else { 192 useCustomRange = false; 193 } 194 parent.fireRangeChanged(); 195 } 196 else if ( source instanceof JButton ) { 197 /// Since it is only "OK" button that sends any action here... 198 customRangeDialog.hide(); 199 } 200 } 201 202 private static int[][] getUnicodeRanges() { 203 List<Integer> ranges = new ArrayList<>(); 204 ranges.add(0); 205 Character.UnicodeBlock currentBlock = Character.UnicodeBlock.of(0); 206 for (int cp = 0x000001; cp < 0x110000; cp++ ) { 207 Character.UnicodeBlock ub = Character.UnicodeBlock.of(cp); 208 if (currentBlock == null) { 209 if (ub != null) { 210 ranges.add(cp); 211 currentBlock = ub; 212 } 213 } else { // being in some unicode range 214 if (ub == null) { 215 ranges.add(cp - 1); 216 currentBlock = null; 217 } else if (cp == 0x10ffff) { // end of last block 218 ranges.add(cp); 219 } else if (! ub.equals(currentBlock)) { 220 ranges.add(cp - 1); 221 ranges.add(cp); 222 currentBlock = ub; 223 } 224 } 225 } 226 ranges.add(0x00); // for user defined range. 227 ranges.add(0x7f); // for user defined range. 228 229 int[][] returnval = new int[ranges.size() / 2][2]; 230 for (int i = 0 ; i < ranges.size() / 2 ; i++ ) { 231 returnval[i][0] = ranges.get(2*i); 232 returnval[i][1] = ranges.get(2*i + 1); 233 } 234 return returnval; 235 } 236 237 private static String[] getUnicodeRangeNames() { 238 String[] names = new String[UNICODE_RANGES.length]; 239 for (int i = 0 ; i < names.length ; i++ ) { 240 names[i] = titleCase( 241 Character.UnicodeBlock.of(UNICODE_RANGES[i][0]).toString()); 242 } 243 names[names.length - 1] = "Custom..."; 244 return names; 245 } 246 247 private static String titleCase(String str) { 248 str = str.replaceAll("_", " "); 249 Pattern p = Pattern.compile("(^|\\W)([a-z])"); 250 Matcher m = p.matcher(str.toLowerCase(Locale.ROOT)); 251 StringBuffer sb = new StringBuffer(); 252 while (m.find()) { 253 m.appendReplacement(sb, m.group(1) + m.group(2).toUpperCase(Locale.ROOT)); 254 } 255 m.appendTail(sb); 256 return sb.toString().replace("Cjk", "CJK").replace("Nko", "NKo"); 257 } 258 }