/** * */ package org.javabuilders.swing; import java.awt.Component; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JWindow; import javax.swing.KeyStroke; import org.javabuilders.BuildException; import org.javabuilders.Builder; import org.javabuilders.Node; /** * Utility methods for the Swing Builder * @author Jacek Furmankiewicz */ public class SwingJavaBuilderUtils { public static final String MNEMONIC = "&"; public final static String SEPARATOR = "+"; private final static String SEPARATOR_ESCAPED = "__"; private static Map<String,Integer> mnemonics = new HashMap<String, Integer>(); private static Map<String,Integer> actionEvents = new HashMap<String, Integer>(); private static List<String> functionKeys = new ArrayList<String>(); //initialize list of mnemonics private static char[] letters = {'1','2','3','4','5','6','7','8','9','0', 'q','w','e','r','t','y','u','i','o','p', 'a','s','d','f','g','h','j','k','l', 'z','x','c','v','b','n','m' }; static { for(char letter : letters) { mnemonics.put(String.valueOf(letter),(int)letter); } mnemonics.put("0", KeyEvent.VK_0); mnemonics.put("1", KeyEvent.VK_1); mnemonics.put("2", KeyEvent.VK_2); mnemonics.put("3", KeyEvent.VK_3); mnemonics.put("4", KeyEvent.VK_4); mnemonics.put("5", KeyEvent.VK_5); mnemonics.put("6", KeyEvent.VK_6); mnemonics.put("7", KeyEvent.VK_7); mnemonics.put("8", KeyEvent.VK_8); mnemonics.put("9", KeyEvent.VK_9); mnemonics.put("q", KeyEvent.VK_Q); mnemonics.put("w", KeyEvent.VK_W); mnemonics.put("e", KeyEvent.VK_E); mnemonics.put("r", KeyEvent.VK_R); mnemonics.put("t", KeyEvent.VK_T); mnemonics.put("y", KeyEvent.VK_Y); mnemonics.put("u", KeyEvent.VK_U); mnemonics.put("i", KeyEvent.VK_I); mnemonics.put("o", KeyEvent.VK_O); mnemonics.put("p", KeyEvent.VK_P); mnemonics.put("a", KeyEvent.VK_A); mnemonics.put("s", KeyEvent.VK_S); mnemonics.put("d", KeyEvent.VK_D); mnemonics.put("f", KeyEvent.VK_F); mnemonics.put("g", KeyEvent.VK_G); mnemonics.put("h", KeyEvent.VK_H); mnemonics.put("j", KeyEvent.VK_J); mnemonics.put("k", KeyEvent.VK_K); mnemonics.put("l", KeyEvent.VK_L); mnemonics.put("z", KeyEvent.VK_Z); mnemonics.put("x", KeyEvent.VK_X); mnemonics.put("c", KeyEvent.VK_C); mnemonics.put("v", KeyEvent.VK_V); mnemonics.put("b", KeyEvent.VK_B); mnemonics.put("n", KeyEvent.VK_N); mnemonics.put("m", KeyEvent.VK_M); actionEvents.put("ctrl", ActionEvent.CTRL_MASK); actionEvents.put("alt", ActionEvent.ALT_MASK); actionEvents.put("shift", ActionEvent.SHIFT_MASK); actionEvents.put("meta", ActionEvent.META_MASK); functionKeys.add("f1"); functionKeys.add("f2"); functionKeys.add("f3"); functionKeys.add("f4"); functionKeys.add("f5"); functionKeys.add("f6"); functionKeys.add("f7"); functionKeys.add("f8"); functionKeys.add("f9"); functionKeys.add("f10"); functionKeys.add("f11"); functionKeys.add("f12"); } /** * Returns action definition, parsed from text * @param text Text * @return Action definition */ public static ActionDefinition getActionDefintion(String text) { KeyStroke acc = null; ActionDefinition def = new ActionDefinition(); String[] parts = null; //handle cases with embedded accelerator if (text.indexOf("\t") >= 0) { //has embedded accelerator, e.g. "Save\tCtrl+S", like in SWT parts = text.split("\t"); } else if (text.indexOf("\\t") >= 0) { //happens when embedded in text on the Java side, split("\\t") does not work... int index = text.indexOf("\\t"); parts = new String[2]; parts[0] = text.substring(0,index); parts[1] = text.substring(index + 2); } if (parts != null && parts.length >=2) { text = parts[0]; acc = getAccelerator(parts[1]); def.setAccelerator(acc); def.setAcceleratorText(parts[1]); } //handle potential mnemonic int index = text.indexOf(MNEMONIC); if (index >= 0 && index < (text.length() - 1)) { //embedded mnemonic String mnemonicLetter = String.valueOf(text.charAt(index + 1)).toLowerCase(); if (mnemonics.containsKey(mnemonicLetter)) { text = text.replace(MNEMONIC, ""); def.setText(text); def.setMnemonic(mnemonics.get(mnemonicLetter)); } } else { def.setText(text); } return def; } /** * @param accelerator Accelerator string * @return Accelerator key stroke */ public static KeyStroke getAccelerator(String accelerator) { accelerator = accelerator.toLowerCase(); accelerator = accelerator.replace(SEPARATOR,SEPARATOR_ESCAPED); //required for split() to work, "+" is a reserver regular expression character String[] parts = accelerator.split(SEPARATOR_ESCAPED); int keyEvent = 0; KeyStroke keyStroke = null; if (parts.length == 1 && functionKeys.contains(accelerator)) { keyStroke = KeyStroke.getKeyStroke(accelerator.toUpperCase()); } else if (parts.length >= 2) { int actionEvent = 0; for(String part : parts) { if (mnemonics.containsKey(part)) { keyEvent = mnemonics.get(part); } else { //must be an action event if (actionEvents.containsKey(part)) { actionEvent += actionEvents.get(part); } else { throw new BuildException("Invalid accelerator value: {0}. Valid values: ctrl|shift|alt|meta+key, e.g. Ctrl+S", accelerator); } } keyStroke = KeyStroke.getKeyStroke(keyEvent, actionEvent); } } return keyStroke; } /** * Utility method to find the component by its name * @return Component if found, null if not * @throws BuildException * */ public static Component getComponent(Node componentsNode, String name) throws BuildException { //prototypes are prefixed with $ if (name != null && name.startsWith(Builder.PROTOTYPE_FIELD_PREFIX)) { name = name.substring(1); } if (Builder.CONTENT.equals(componentsNode.getKey())) { Component component = null; for(Node child : componentsNode.getChildNodes()) { if (child.getMainObject() instanceof Component) { Component temp = (Component)child.getMainObject(); if (name.equals(temp.getName())) { component = temp; break; } } } return component; } else { throw new BuildException("componentsNode is not a valid Components node"); } } /** * Finds out if a component has already been added to a parent * @param parent * @param component * @return */ public static boolean isComponentAlreadyAdded(Container parent, Component component) { boolean isAdded = false; for(int i = 0; i < parent.getComponentCount();i++) { if (parent.getComponent(i).equals(component)) { isAdded = true; break; } } return isAdded; } /** * Finds the top level parent (frame/dialog/window) of any component * @param component Component * @return Parent or null if none found */ public static Component getTopLevelParent(Object component) { Component top = null; if (component instanceof Component) { Component c = (Component)component; while (c.getParent() != null) { c = c.getParent(); } top = c; } return top; } /** * Gets the parent JComponent, using nothing but the Node hierarchy * @param current Current node * @return JComponent or null if none found */ public static Container getParentContainer(Node current) { Container c = null; Node parent = current.getParent(); while (parent != null) { Object main = parent.getMainObject(); if (main instanceof Container) { c = (Container) main; } else if (main instanceof JFrame) { c = ((JFrame)main).getContentPane(); } else if (main instanceof JDialog) { c = ((JDialog)main).getContentPane(); } else if (main instanceof JWindow) { c = ((JWindow)main).getContentPane(); } if (c != null) { break; } else { parent = parent.getParent(); } } return c; } /** * Class that represents an action item's properties */ public static class ActionDefinition { private String text; private Integer mnemonic; private KeyStroke accelerator; private String acceleratorText; public String getText() { return text; } public void setText(String text) { this.text = text; } public Integer getMnemonic() { return mnemonic; } public void setMnemonic(Integer mnemonic) { this.mnemonic = mnemonic; } public KeyStroke getAccelerator() { return accelerator; } public void setAccelerator(KeyStroke accelerator) { this.accelerator = accelerator; } public String getAcceleratorText() { return acceleratorText; } public void setAcceleratorText(String acceleratorText) { this.acceleratorText = acceleratorText; } } }