001: package org.uispec4j;
002:
003: import junit.framework.Assert;
004: import org.uispec4j.assertion.Assertion;
005: import org.uispec4j.finder.StringMatcher;
006: import org.uispec4j.utils.ArrayUtils;
007: import org.uispec4j.xml.XmlAssert;
008: import org.uispec4j.xml.XmlWriter;
009:
010: import javax.swing.*;
011: import java.awt.*;
012: import java.io.StringWriter;
013: import java.util.ArrayList;
014: import java.util.List;
015:
016: /**
017: * Wrapper for menu items (commands or sub-menus) such as JMenu, JMenuItem or JPopupMenu.<p/>
018: * A given MenuItem can be either a command, or a sub-menu containing other MenuItem
019: * components.
020: */
021: public class MenuItem extends AbstractUIComponent {
022: public static final String TYPE_NAME = "menu";
023: public static final Class[] SWING_CLASSES = { JMenuItem.class,
024: JPopupMenu.class };
025:
026: private final MenuWrapper wrapper;
027:
028: public MenuItem(JMenuItem menu) {
029: this .wrapper = new JMenuItemWrapper(menu);
030: }
031:
032: public MenuItem(final JPopupMenu menu) {
033: this .wrapper = new JPopupMenuWrapper(menu);
034: }
035:
036: public String getDescriptionTypeName() {
037: return TYPE_NAME;
038: }
039:
040: public Component getAwtComponent() {
041: return wrapper.getAwtComponent();
042: }
043:
044: public void click() {
045: wrapper.click();
046: }
047:
048: public Trigger triggerClick() {
049: return new Trigger() {
050: public void run() {
051: MenuItem.this .click();
052: }
053: };
054: }
055:
056: /** Returns a submenu given its name, or raises an exception if it was not found. */
057: public MenuItem getSubMenu(String subMenuItem) {
058: MenuItem menuItem = retrieveMatchingSubMenu(subMenuItem,
059: StringMatcher.identity(subMenuItem));
060: if (menuItem == null) {
061: menuItem = retrieveMatchingSubMenu(subMenuItem,
062: StringMatcher.substring(subMenuItem));
063: }
064: if (menuItem == null) {
065: Assert.fail("There is no menu item matching '"
066: + subMenuItem + "' - actual elements: "
067: + ArrayUtils.toString(getSubElementNames()));
068: }
069: return menuItem;
070: }
071:
072: public Assertion contentEquals(final String[] expectedNames) {
073: return new Assertion() {
074: public void check() {
075: ArrayUtils.assertEquals(expectedNames,
076: getSubElementNames());
077: }
078: };
079: }
080:
081: /** Returns the names of the items found in this MenuItem in case where it is a submenu.
082: * Separators are not represented in this list.
083: */
084: private String[] getSubElementNames() {
085: List actualWrappersList = new ArrayList();
086: MenuWrapper[] subMenus = wrapper.getSubElements(true);
087: for (int i = 0; i < subMenus.length; i++) {
088: MenuWrapper menuItem = subMenus[i];
089: actualWrappersList.add(menuItem.getText());
090: }
091: return (String[]) actualWrappersList
092: .toArray(new String[actualWrappersList.size()]);
093: }
094:
095: public Assertion contentEquals(final String xmlContent) {
096: return new Assertion() {
097: public void check() {
098: StringWriter writer = new StringWriter();
099: XmlWriter.Tag tag = XmlWriter.startTag(writer,
100: getDescriptionTypeName());
101: if (wrapper.getText() != null) {
102: tag.addAttribute("name", wrapper.getText());
103: }
104: computeContent(tag, wrapper.getSubElements(false));
105: tag.end();
106: XmlAssert.assertEquals(xmlContent, writer.toString());
107: }
108: };
109: }
110:
111: private void computeContent(XmlWriter.Tag tag,
112: MenuWrapper[] elements) {
113: for (int i = 0; i < elements.length; i++) {
114: if (elements[i].isSeparator()) {
115: tag.start("separator").end();
116: } else {
117: XmlWriter.Tag menuTag = tag.start("menu").addAttribute(
118: "name", elements[i].getText());
119: computeContent(menuTag, elements[i]
120: .getSubElements(false));
121: menuTag.end();
122: }
123: }
124: }
125:
126: private MenuItem retrieveMatchingSubMenu(String toFind,
127: StringMatcher menuMatcher) {
128: MenuItem subMenuItem = null;
129: MenuWrapper[] subMenus = wrapper.getSubElements(true);
130: for (int i = 0; i < subMenus.length; i++) {
131: MenuWrapper subMenu = subMenus[i];
132: if (isSubMenuMatching(subMenu.getText(), menuMatcher,
133: toFind, subMenuItem != null)) {
134: subMenuItem = subMenu.toItem();
135: }
136: }
137: return subMenuItem;
138: }
139:
140: private boolean isSubMenuMatching(String name,
141: StringMatcher menuMatcher, String toFind,
142: boolean firstMatchFound) {
143: if (menuMatcher.matches(name)) {
144: if (firstMatchFound) {
145: Assert
146: .fail("Could not retrieve subMenu item : There are more than one component matching '"
147: + toFind + "'");
148: }
149: return true;
150: }
151: return false;
152: }
153:
154: private interface MenuWrapper {
155: String getText();
156:
157: MenuWrapper[] getSubElements(boolean skipSeparators);
158:
159: void click();
160:
161: Component getAwtComponent();
162:
163: boolean isSeparator();
164:
165: MenuItem toItem();
166: }
167:
168: private class JMenuItemWrapper implements MenuWrapper {
169: private JMenuItem menuItem;
170:
171: public JMenuItemWrapper(JMenuItem menuItem) {
172: this .menuItem = menuItem;
173: }
174:
175: public void click() {
176: Assert
177: .assertTrue(
178: "The menu item is not enabled, it cannot be activated",
179: menuItem.isEnabled());
180: AbstractButton.doClick(menuItem);
181: }
182:
183: public MenuWrapper[] getSubElements(boolean skipSeparators) {
184: if (!(menuItem instanceof JMenu)) {
185: return new MenuWrapper[0];
186: }
187: JMenu menu = (JMenu) menuItem;
188: List result = new ArrayList();
189: Component[] menuComponents = menu.getMenuComponents();
190: for (int i = 0; i < menuComponents.length; i++) {
191: Component menuComponent = menuComponents[i];
192: if (menuComponent instanceof JMenuItem) {
193: result.add(new JMenuItemWrapper(
194: (JMenuItem) menuComponent));
195: } else if ((menuComponent instanceof JPopupMenu.Separator)
196: && !skipSeparators) {
197: result.add(new SeparatorWrapper());
198: }
199: }
200: return (MenuWrapper[]) result
201: .toArray(new MenuWrapper[result.size()]);
202: }
203:
204: public String getText() {
205: return menuItem.getText();
206: }
207:
208: public Component getAwtComponent() {
209: return menuItem;
210: }
211:
212: public boolean isSeparator() {
213: return false;
214: }
215:
216: public MenuItem toItem() {
217: return new MenuItem(menuItem);
218: }
219: }
220:
221: private class JPopupMenuWrapper implements MenuWrapper {
222: private JPopupMenu popupMenu;
223:
224: public JPopupMenuWrapper(JPopupMenu popupMenu) {
225: this .popupMenu = popupMenu;
226: }
227:
228: public void click() {
229: Assert
230: .fail("This operation is not supported. You must first select a sub menu among: "
231: + ArrayUtils.toString(getSubElementNames()));
232: }
233:
234: public MenuWrapper[] getSubElements(boolean skipSeparators) {
235: Component[] components = popupMenu.getComponents();
236: List elements = new ArrayList();
237: for (int i = 0; i < components.length; i++) {
238: Component component = components[i];
239: if (component instanceof JMenuItem) {
240: elements.add(new JMenuItemWrapper(
241: (JMenuItem) component));
242: } else if ((component instanceof JPopupMenu.Separator)) {
243: if (!skipSeparators) {
244: elements.add(new SeparatorWrapper());
245: }
246: } else {
247: Assert.fail("Unexpected menu item of class: "
248: + component.getClass());
249: }
250: }
251: return (MenuWrapper[]) elements
252: .toArray(new MenuWrapper[elements.size()]);
253: }
254:
255: public String getText() {
256: return popupMenu.getLabel();
257: }
258:
259: public Component getAwtComponent() {
260: return popupMenu;
261: }
262:
263: public boolean isSeparator() {
264: return false;
265: }
266:
267: public MenuItem toItem() {
268: return new MenuItem(popupMenu);
269: }
270: }
271:
272: private static class SeparatorWrapper implements MenuWrapper {
273: public void click() {
274: }
275:
276: public Component getAwtComponent() {
277: return null;
278: }
279:
280: public MenuWrapper[] getSubElements(boolean skipSeparators) {
281: return new MenuWrapper[0];
282: }
283:
284: public String getText() {
285: return null;
286: }
287:
288: public boolean isSeparator() {
289: return true;
290: }
291:
292: public MenuItem toItem() {
293: throw new UnsupportedOperationException();
294: }
295: }
296: }
|