1/* 2 3 Licensed to the Apache Software Foundation (ASF) under one or more 4 contributor license agreements. See the NOTICE file distributed with 5 this work for additional information regarding copyright ownership. 6 The ASF licenses this file to You under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with 8 the License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 18 */ 19package components; 20 21import java.net.URL; 22import java.util.Iterator; 23import java.util.List; 24import java.util.MissingResourceException; 25import java.util.ResourceBundle; 26 27import javax.swing.AbstractButton; 28import javax.swing.Action; 29import javax.swing.ButtonGroup; 30import javax.swing.ImageIcon; 31import javax.swing.JCheckBoxMenuItem; 32import javax.swing.JComponent; 33import javax.swing.JMenu; 34import javax.swing.JMenuBar; 35import javax.swing.JMenuItem; 36import javax.swing.JRadioButtonMenuItem; 37import javax.swing.JSeparator; 38import javax.swing.KeyStroke; 39 40import org.apache.batik.util.resources.ResourceFormatException; 41import org.apache.batik.util.resources.ResourceManager; 42 43/** 44 * This class represents a menu factory which builds 45 * menubars and menus from the content of a resource file. <br> 46 * 47 * The resource entries format is (for a menubar named 'MenuBar'):<br> 48 * <pre> 49 * MenuBar = Menu1 Menu2 ... 50 * 51 * Menu1.type = RADIO | CHECK | MENU | ITEM 52 * Menu1 = Item1 Item2 - Item3 ... 53 * Menu1.text = text 54 * Menu1.icon = icon_name 55 * Menu1.mnemonic = mnemonic 56 * Menu1.accelerator = accelerator 57 * Menu1.action = action_name 58 * Menu1.selected = true | false 59 * Menu1.enabled = true | false 60 * ... 61 * mnemonic is a single character 62 * accelerator is of the form described in {@link javax.swing.KeyStroke#getKeyStroke(String)}. 63 * '-' represents a separator 64 * </pre> 65 * All entries are optional except the '.type' entry 66 * Consecutive RADIO items are put in a ButtonGroup 67 * 68 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a> 69 * @version $Id: MenuFactory.java,v 1.1 2013/02/21 11:24:35 jschimpf Exp $ 70 */ 71public class MenuFactory extends ResourceManager { 72 // Constants 73 // 74 private static final String TYPE_MENU = "MENU"; 75 private static final String TYPE_ITEM = "ITEM"; 76 private static final String TYPE_RADIO = "RADIO"; 77 private static final String TYPE_CHECK = "CHECK"; 78 private static final String SEPARATOR = "-"; 79 80 private static final String TYPE_SUFFIX = ".type"; 81 private static final String TEXT_SUFFIX = ".text"; 82 private static final String MNEMONIC_SUFFIX = ".mnemonic"; 83 private static final String ACCELERATOR_SUFFIX = ".accelerator"; 84 private static final String ACTION_SUFFIX = ".action"; 85 private static final String SELECTED_SUFFIX = ".selected"; 86 private static final String ENABLED_SUFFIX = ".enabled"; 87 private static final String ICON_SUFFIX = ".icon"; 88 89 /** 90 * The table which contains the actions 91 */ 92 private ActionMap actions; 93 94 /** 95 * The current radio group 96 */ 97 private ButtonGroup buttonGroup; 98 99 /** 100 * Creates a new menu factory 101 * @param rb the resource bundle that contains the menu bar 102 * description. 103 * @param am the actions to add to menu items 104 */ 105 public MenuFactory(ResourceBundle rb, ActionMap am) { 106 super(rb); 107 actions = am; 108 buttonGroup = null; 109 } 110 111 /** 112 * Creates and returns a swing menu bar 113 * @param name the name of the menu bar in the resource bundle 114 * @throws MissingResourceException if one of the keys that compose the 115 * menu is missing. 116 * It is not thrown if the mnemonic, the accelerator and the 117 * action keys are missing 118 * @throws ResourceFormatException if the mnemonic is not a single 119 * character and if the accelerator is malformed 120 * @throws MissingListenerException if an item action is not found in the 121 * action map 122 */ 123 public JMenuBar createJMenuBar(String name) 124 throws MissingResourceException, 125 ResourceFormatException, 126 MissingListenerException { 127 return createJMenuBar(name, null); 128 } 129 130 /** 131 * Creates and returns a swing menu bar 132 * @param name the name of the menu bar in the resource bundle 133 * @param specialization the name of the specialization to look for 134 * @throws MissingResourceException if one of the keys that compose the 135 * menu is missing. 136 * It is not thrown if the mnemonic, the accelerator and the 137 * action keys are missing 138 * @throws ResourceFormatException if the mnemonic is not a single 139 * character and if the accelerator is malformed 140 * @throws MissingListenerException if an item action is not found in the 141 * action map 142 */ 143 public JMenuBar createJMenuBar(String name, String specialization) 144 throws MissingResourceException, 145 ResourceFormatException, 146 MissingListenerException { 147 JMenuBar result = new JMenuBar(); 148 List menus = getSpecializedStringList(name, specialization); 149 Iterator it = menus.iterator(); 150 151 while (it.hasNext()) { 152 result.add(createJMenuComponent((String)it.next(), specialization)); 153 } 154 return result; 155 } 156 157 /** 158 * Gets a possibly specialized resource string. 159 * This will first look for 160 * <code>name + '.' + specialization</code>, and if that resource 161 * doesn't exist, <code>name</code>. 162 */ 163 protected String getSpecializedString(String name, String specialization) { 164 String s; 165 try { 166 s = getString(name + '.' + specialization); 167 } catch (MissingResourceException mre) { 168 s = getString(name); 169 } 170 return s; 171 } 172 173 /** 174 * Gets a possibly specialized resource string list. 175 * This will first look for 176 * <code>name + '.' + specialization</code>, and if that resource 177 * doesn't exist, <code>name</code>. 178 */ 179 protected List getSpecializedStringList(String name, 180 String specialization) { 181 List l; 182 try { 183 l = getStringList(name + '.' + specialization); 184 } catch (MissingResourceException mre) { 185 l = getStringList(name); 186 } 187 return l; 188 } 189 190 /** 191 * Gets a possibly specialized resource boolean. 192 * This will first look for 193 * <code>name + '.' + specialization</code>, and if that resource 194 * doesn't exist, <code>name</code>. 195 */ 196 protected boolean getSpecializedBoolean(String name, 197 String specialization) { 198 boolean b; 199 try { 200 b = getBoolean(name + '.' + specialization); 201 } catch (MissingResourceException mre) { 202 b = getBoolean(name); 203 } 204 return b; 205 } 206 207 /** 208 * Creates and returns a menu item or a separator 209 * @param name the name of the menu item or "-" to create a separator 210 * @param specialization the name of the specialization to look for 211 * @throws MissingResourceException if key is not the name of a menu item. 212 * It is not thrown if the mnemonic, the accelerator and the 213 * action keys are missing 214 * @throws ResourceFormatException in case of malformed entry 215 * @throws MissingListenerException if an item action is not found in the 216 * action map 217 */ 218 protected JComponent createJMenuComponent(String name, 219 String specialization) 220 throws MissingResourceException, 221 ResourceFormatException, 222 MissingListenerException { 223 if (name.equals(SEPARATOR)) { 224 buttonGroup = null; 225 return new JSeparator(); 226 } 227 String type = getSpecializedString(name + TYPE_SUFFIX, 228 specialization); 229 JComponent item = null; 230 231 if (type.equals(TYPE_RADIO)) { 232 if (buttonGroup == null) { 233 buttonGroup = new ButtonGroup(); 234 } 235 } else { 236 buttonGroup = null; 237 } 238 239 if (type.equals(TYPE_MENU)) { 240 item = createJMenu(name, specialization); 241 } else if (type.equals(TYPE_ITEM)) { 242 item = createJMenuItem(name, specialization); 243 } else if (type.equals(TYPE_RADIO)) { 244 item = createJRadioButtonMenuItem(name, specialization); 245 buttonGroup.add((AbstractButton)item); 246 } else if (type.equals(TYPE_CHECK)) { 247 item = createJCheckBoxMenuItem(name, specialization); 248 } else { 249 throw new ResourceFormatException("Malformed resource", 250 bundle.getClass().getName(), 251 name+TYPE_SUFFIX); 252 } 253 254 return item; 255 } 256 257 /** 258 * Creates and returns a new swing menu 259 * @param name the name of the menu bar in the resource bundle 260 * @throws MissingResourceException if one of the keys that compose the 261 * menu is missing. 262 * It is not thrown if the mnemonic, the accelerator and the 263 * action keys are missing 264 * @throws ResourceFormatException if the mnemonic is not a single 265 * character. 266 * @throws MissingListenerException if a item action is not found in the 267 * action map. 268 */ 269 public JMenu createJMenu(String name) 270 throws MissingResourceException, 271 ResourceFormatException, 272 MissingListenerException { 273 return createJMenu(name, null); 274 } 275 276 /** 277 * Creates and returns a new swing menu 278 * @param name the name of the menu bar in the resource bundle 279 * @param specialization the name of the specialization to look for 280 * @throws MissingResourceException if one of the keys that compose the 281 * menu is missing. 282 * It is not thrown if the mnemonic, the accelerator and the 283 * action keys are missing 284 * @throws ResourceFormatException if the mnemonic is not a single 285 * character. 286 * @throws MissingListenerException if a item action is not found in the 287 * action map. 288 */ 289 public JMenu createJMenu(String name, String specialization) 290 throws MissingResourceException, 291 ResourceFormatException, 292 MissingListenerException { 293 JMenu result = new JMenu(getSpecializedString(name + TEXT_SUFFIX, 294 specialization)); 295 initializeJMenuItem(result, name, specialization); 296 297 List items = getSpecializedStringList(name, specialization); 298 Iterator it = items.iterator(); 299 300 while (it.hasNext()) { 301 result.add(createJMenuComponent((String)it.next(), specialization)); 302 } 303 return result; 304 } 305 306 /** 307 * Creates and returns a new swing menu item 308 * @param name the name of the menu item 309 * @throws MissingResourceException if one of the keys that compose the 310 * menu item is missing. 311 * It is not thrown if the mnemonic, the accelerator and the 312 * action keys are missing 313 * @throws ResourceFormatException if the mnemonic is not a single 314 * character. 315 * @throws MissingListenerException if then item action is not found in 316 * the action map. 317 */ 318 public JMenuItem createJMenuItem(String name) 319 throws MissingResourceException, 320 ResourceFormatException, 321 MissingListenerException { 322 return createJMenuItem(name, null); 323 } 324 325 /** 326 * Creates and returns a new swing menu item 327 * @param name the name of the menu item 328 * @param specialization the name of the specialization to look for 329 * @throws MissingResourceException if one of the keys that compose the 330 * menu item is missing. 331 * It is not thrown if the mnemonic, the accelerator and the 332 * action keys are missing 333 * @throws ResourceFormatException if the mnemonic is not a single 334 * character. 335 * @throws MissingListenerException if then item action is not found in 336 * the action map. 337 */ 338 public JMenuItem createJMenuItem(String name, String specialization) 339 throws MissingResourceException, 340 ResourceFormatException, 341 MissingListenerException { 342 JMenuItem result = new JMenuItem(getSpecializedString(name + TEXT_SUFFIX, 343 specialization)); 344 initializeJMenuItem(result, name, specialization); 345 return result; 346 } 347 348 /** 349 * Creates and returns a new swing radio button menu item 350 * @param name the name of the menu item 351 * @throws MissingResourceException if one of the keys that compose the 352 * menu item is missing. 353 * It is not thrown if the mnemonic, the accelerator and the 354 * action keys are missing 355 * @throws ResourceFormatException if the mnemonic is not a single 356 * character. 357 * @throws MissingListenerException if then item action is not found in 358 * the action map. 359 */ 360 public JRadioButtonMenuItem createJRadioButtonMenuItem(String name) 361 throws MissingResourceException, 362 ResourceFormatException, 363 MissingListenerException { 364 return createJRadioButtonMenuItem(name, null); 365 } 366 367 /** 368 * Creates and returns a new swing radio button menu item 369 * @param name the name of the menu item 370 * @param specialization the name of the specialization to look for 371 * @throws MissingResourceException if one of the keys that compose the 372 * menu item is missing. 373 * It is not thrown if the mnemonic, the accelerator and the 374 * action keys are missing 375 * @throws ResourceFormatException if the mnemonic is not a single 376 * character. 377 * @throws MissingListenerException if then item action is not found in 378 * the action map. 379 */ 380 public JRadioButtonMenuItem createJRadioButtonMenuItem 381 (String name, String specialization) 382 throws MissingResourceException, 383 ResourceFormatException, 384 MissingListenerException { 385 JRadioButtonMenuItem result; 386 result = new JRadioButtonMenuItem 387 (getSpecializedString(name + TEXT_SUFFIX, specialization)); 388 initializeJMenuItem(result, name, specialization); 389 390 // is the item selected? 391 try { 392 result.setSelected(getSpecializedBoolean(name + SELECTED_SUFFIX, 393 specialization)); 394 } catch (MissingResourceException e) { 395 } 396 397 return result; 398 } 399 400 /** 401 * Creates and returns a new swing check box menu item 402 * @param name the name of the menu item 403 * @throws MissingResourceException if one of the keys that compose the 404 * menu item is missing. 405 * It is not thrown if the mnemonic, the accelerator and the 406 * action keys are missing 407 * @throws ResourceFormatException if the mnemonic is not a single 408 * character. 409 * @throws MissingListenerException if then item action is not found in 410 * the action map. 411 */ 412 public JCheckBoxMenuItem createJCheckBoxMenuItem(String name) 413 throws MissingResourceException, 414 ResourceFormatException, 415 MissingListenerException { 416 return createJCheckBoxMenuItem(name, null); 417 } 418 419 /** 420 * Creates and returns a new swing check box menu item 421 * @param name the name of the menu item 422 * @param specialization the name of the specialization to look for 423 * @throws MissingResourceException if one of the keys that compose the 424 * menu item is missing. 425 * It is not thrown if the mnemonic, the accelerator and the 426 * action keys are missing 427 * @throws ResourceFormatException if the mnemonic is not a single 428 * character. 429 * @throws MissingListenerException if then item action is not found in 430 * the action map. 431 */ 432 public JCheckBoxMenuItem createJCheckBoxMenuItem(String name, 433 String specialization) 434 throws MissingResourceException, 435 ResourceFormatException, 436 MissingListenerException { 437 JCheckBoxMenuItem result; 438 result = new JCheckBoxMenuItem(getSpecializedString(name + TEXT_SUFFIX, 439 specialization)); 440 initializeJMenuItem(result, name, specialization); 441 442 // is the item selected? 443 try { 444 result.setSelected(getSpecializedBoolean(name + SELECTED_SUFFIX, 445 specialization)); 446 } catch (MissingResourceException e) { 447 } 448 449 return result; 450 } 451 452 /** 453 * Initializes a swing menu item 454 * @param item the menu item to initialize 455 * @param name the name of the menu item 456 * @param specialization the name of the specialization to look for 457 * @throws ResourceFormatException if the mnemonic is not a single 458 * character. 459 * @throws MissingListenerException if then item action is not found in 460 * the action map. 461 */ 462 protected void initializeJMenuItem(JMenuItem item, String name, 463 String specialization) 464 throws ResourceFormatException, 465 MissingListenerException { 466 // Action 467 try { 468 Action a = actions.getAction 469 (getSpecializedString(name + ACTION_SUFFIX, specialization)); 470 if (a == null) { 471 throw new MissingListenerException("", "Action", 472 name+ACTION_SUFFIX); 473 } 474 item.setAction(a); 475 item.setText(getSpecializedString(name + TEXT_SUFFIX, 476 specialization)); 477 if (a instanceof JComponentModifier) { 478 ((JComponentModifier)a).addJComponent(item); 479 } 480 } catch (MissingResourceException e) { 481 } 482 483 // Icon 484 try { 485 String s = getSpecializedString(name + ICON_SUFFIX, specialization); 486 URL url = actions.getClass().getResource(s); 487 if (url != null) { 488 item.setIcon(new ImageIcon(url)); 489 } 490 } catch (MissingResourceException e) { 491 } 492 493 // Mnemonic 494 try { 495 String str = getSpecializedString(name + MNEMONIC_SUFFIX, 496 specialization); 497 if (str.length() == 1) { 498 item.setMnemonic(str.charAt(0)); 499 } else { 500 throw new ResourceFormatException("Malformed mnemonic", 501 bundle.getClass().getName(), 502 name+MNEMONIC_SUFFIX); 503 } 504 } catch (MissingResourceException e) { 505 } 506 507 // Accelerator 508 try { 509 if (!(item instanceof JMenu)) { 510 String str = getSpecializedString(name + ACCELERATOR_SUFFIX, 511 specialization); 512 KeyStroke ks = KeyStroke.getKeyStroke(str); 513 if (ks != null) { 514 item.setAccelerator(ks); 515 } else { 516 throw new ResourceFormatException 517 ("Malformed accelerator", 518 bundle.getClass().getName(), 519 name+ACCELERATOR_SUFFIX); 520 } 521 } 522 } catch (MissingResourceException e) { 523 } 524 525 // is the item enabled? 526 try { 527 item.setEnabled(getSpecializedBoolean(name + ENABLED_SUFFIX, 528 specialization)); 529 } catch (MissingResourceException e) { 530 } 531 } 532} 533