/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.codegen.generator; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import com.windowtester.codegen.ITestCaseBuilder; import com.windowtester.codegen.TestCaseGenerator; import com.windowtester.codegen.assembly.block.CodeBlock; import com.windowtester.codegen.assembly.unit.ImportUnit; import com.windowtester.codegen.swing.SwingCodeBlockBuilder; import com.windowtester.codegen.swing.SwingTestCaseBuilder; import com.windowtester.codegen.swt.SWTCodeBlockBuilder; import com.windowtester.codegen.util.CodeGenSnippetBuilder; import com.windowtester.codegen.util.LocatorUtil; import com.windowtester.internal.runtime.Adapter; import com.windowtester.internal.runtime.DefaultCodeGenerator; import com.windowtester.internal.runtime.ICodeGenerator; import com.windowtester.internal.runtime.ICodegenParticipant; import com.windowtester.internal.runtime.IWidgetIdentifier; import com.windowtester.internal.runtime.MouseConfig; import com.windowtester.internal.runtime.PropertySet.PropertyMapping; import com.windowtester.internal.runtime.finder.IIdentifierHintProvider; import com.windowtester.internal.runtime.locator.IdentifierAdapter; import com.windowtester.internal.runtime.reflect.Reflector; import com.windowtester.recorder.event.IUISemanticEvent; import com.windowtester.recorder.event.user.ICheckable; import com.windowtester.recorder.event.user.IMaskable; import com.windowtester.recorder.event.user.SemanticComboSelectionEvent; import com.windowtester.recorder.event.user.SemanticFocusEvent; import com.windowtester.recorder.event.user.SemanticListSelectionEvent; import com.windowtester.recorder.event.user.SemanticMenuSelectionEvent; import com.windowtester.recorder.event.user.SemanticMoveEvent; import com.windowtester.recorder.event.user.SemanticResizeEvent; import com.windowtester.recorder.event.user.SemanticShellClosingEvent; import com.windowtester.recorder.event.user.SemanticShellDisposedEvent; import com.windowtester.recorder.event.user.SemanticShellShowingEvent; import com.windowtester.recorder.event.user.SemanticTableSelectionEvent; import com.windowtester.recorder.event.user.SemanticTreeItemSelectionEvent; import com.windowtester.recorder.event.user.SemanticWidgetClosedEvent; import com.windowtester.recorder.event.user.SemanticWidgetSelectionEvent; import com.windowtester.recorder.event.user.TreeEventType; import com.windowtester.runtime.IAdaptable; import com.windowtester.runtime.WT; import com.windowtester.runtime.WidgetLocator; import com.windowtester.runtime.locator.ILocator; import com.windowtester.runtime.locator.XYLocator; import com.windowtester.runtime.swing.SwingWidgetLocator; import com.windowtester.runtime.swing.condition.WindowDisposedCondition; import com.windowtester.runtime.swing.condition.WindowShowingCondition; import com.windowtester.runtime.swing.locator.JTextComponentLocator; import com.windowtester.runtime.swt.condition.shell.ShellDisposedCondition; import com.windowtester.runtime.swt.condition.shell.ShellShowingCondition; import com.windowtester.runtime.swt.internal.locator.IModifiable; import com.windowtester.runtime.swt.internal.locator.VirtualItemLocator; import com.windowtester.runtime.swt.internal.util.TextUtils; import com.windowtester.runtime.swt.locator.ColumnLocator; import com.windowtester.runtime.swt.locator.FilteredTreeLocator; import com.windowtester.runtime.swt.locator.LabeledLocator; import com.windowtester.runtime.swt.locator.SWTWidgetLocator; import com.windowtester.runtime.swt.locator.TableItemLocator; import com.windowtester.runtime.swt.locator.TreeItemLocator; import com.windowtester.runtime.swt.locator.eclipse.PullDownMenuItemLocator; public class NewAPICodeBlockBuilder implements ICodeBlockBuilder { private static final String NEW_LINE = TestCaseGenerator.NEW_LINE; private final ITestCaseBuilder _builder; public NewAPICodeBlockBuilder(ITestCaseBuilder builder) { _builder = builder; } public CodeBlock build(SemanticListSelectionEvent listSelection) { return selectBlock(listSelection); } public CodeBlock build(SemanticComboSelectionEvent comboSelection) { return selectBlock(comboSelection); } public CodeBlock buildButtonSelect(SemanticWidgetSelectionEvent event) { return buildSelect(event); } public CodeBlock buildFocus(SemanticFocusEvent event) { return notHandled("focus"); } public CodeBlock buildFocusChange(IWidgetIdentifier newTarget) { return notHandled("focusChange"); } public CodeBlock buildKeyEntry(String ctrl, String key) { addImport(WT.class); //if it's a legacy key, convert it: ctrl = fixLegacyKey(ctrl); StringBuffer sb = new StringBuffer(); sb.append(getInstanceName()).append(".keyClick(").append(ctrl).append(", \'"). append(key).append("\');").append(NEW_LINE); return new CodeBlock(sb.toString()); } public CodeBlock buildKeyEntry(String key) { StringBuffer sb = new StringBuffer(); addImport(WT.class); key = fixLegacyKey(key); sb.append(getInstanceName()).append('.').append("keyClick(").append(key).append(");").append(NEW_LINE); return new CodeBlock(sb.toString()); } public CodeBlock buildMenuSelect(SemanticMenuSelectionEvent event) { addImports(event); if (isContextClick(event)) return contextMenuSelectBlock(event); //fix tabs that have been interpreted into spaces String path = event.getPathString(); if (path != null) event.setPath(escapeTabs(TextUtils.fixTabs(path))); return selectBlock(event); } private CodeBlock contextMenuSelectBlock(SemanticMenuSelectionEvent event) { StringBuffer sb = new StringBuffer(); sb.append(getInstanceName()).append('.').append("contextClick("); String block = toJavaString(event); if (block.length() == 0) return new CodeBlock("//WARNING: unsupported widget context selection ignored - " + event + NEW_LINE); sb.append(block); sb.append(", \"").append(escapeTabs(event.getPathString())).append("\");").append(NEW_LINE); return new CodeBlock(sb.toString()); } private boolean isContextClick(SemanticMenuSelectionEvent event) { return event.getButton() == MouseConfig.SECONDARY_BUTTON; } public CodeBlock buildMethodInvocation(String method) { StringBuffer sb = new StringBuffer(); sb.append(method).append("();").append(NEW_LINE); return new CodeBlock(sb.toString()); } public CodeBlock buildMove(SemanticMoveEvent event) { return notHandled("move"); } public CodeBlock buildMoveTo(IUISemanticEvent event) { return notHandled("moveTo"); } public CodeBlock buildResize(SemanticResizeEvent event) { return notHandled("resize"); } public CodeBlock buildSelect(SemanticWidgetSelectionEvent event) { addImports(event); return selectBlock(event); } public CodeBlock buildDragTo(IUISemanticEvent event) { addImports(event); String block = toJavaString(event); StringBuffer sb = new StringBuffer(); sb.append(getInstanceName()).append(".dragTo(").append(block).append(");").append(NEW_LINE); return new CodeBlock(sb.toString()); } public CodeBlock buildAssertion(ILocator locator, PropertyMapping property) { addImportsForLocator(locator); Reflector reflector = Reflector.forObject(locator); String propertyKey = property.getKey(); Class<?>[] argTypes = (!property.isBoolean() && propertyKey.startsWith("has")) ? new Class<?>[]{String.class} : null; if (!reflector.supports(propertyKey, argTypes)) return notHandled("assertion of property: " + property.toString() + "(unsupported)"); String assertion = toJavaString(locator) + "." + propertyKey + "("; //boolean case if (propertyKey.startsWith("is") || property.isBoolean()) { if (property.getValue().equals("false")) assertion += "false"; } else { //String case assertion += '"' + property.getValue() + '"'; } assertion += ")"; return new CodeBlock(getInstanceName() + ".assertThat(" + assertion + ");" + NEW_LINE); } private CodeBlock selectBlock(IUISemanticEvent event) { addImports(event); optionallyAddSWTModifierInfoIfNecessary(event); String block = toJavaString(event); if (block.length() == 0) return new CodeBlock("//WARNING: unsupported widget selection ignored - " + event + NEW_LINE); /* * Optionally handle XYLocator and ColumnLocator wrappering */ block = optionallyWrapBlockInColumnLocator(block, event); block = optionallyWrapBlockInXYLocator(block, event); StringBuffer sb = new StringBuffer(); sb.append(getInstanceName()).append(".click("); int clicks = event.getClicks(); if (event instanceof IMaskable){ IMaskable maskedEvent = (IMaskable)event; //masks require click count always, but otherwise only if > 1 if (maskedEvent.getMask() != null || clicks > 1){ if (clicks == 0) //unset clicks defaults to 1 clicks = 1; sb.append(clicks).append(", "); } } else if (clicks > 1) sb.append(clicks).append(", "); sb.append(block); //append shift modifiers (e.g., WT.SHIFT) optionallyHandleClickMods(sb, event); //close block sb.append(");").append(NEW_LINE); return new CodeBlock(sb); } protected String toJavaString(IUISemanticEvent event) { return LocatorJavaStringFactory.toJavaString(event); } protected String toJavaString(ILocator locator) { return LocatorJavaStringFactory.toJavaString(locator); } public CodeBlock buildShellClosing(SemanticShellClosingEvent event) { if (isSWT(event)) return buildSWTShellClosing(event); //TODO[!pq}: this is not right... close and dispose are not distinguished... //Keerti: confirm for Swing? addImport(ShellDisposedCondition.class); //handled above -- this will add a superfluous generic widgetlocator import //addImports(event); /* * Hijacking and replicating buildShellDisposed(..) */ StringBuffer sb = new StringBuffer(); sb .append("//TODO: this is really generated by the close (close and dispose are not differentiated)"); sb.append(NEW_LINE); sb.append(getInstanceName()).append(".wait("); sb.append(getSystemBuilder(event).shellDisposedCondition( event.getName())); sb.append(");").append(NEW_LINE); return new CodeBlock(sb); } /* (non-Javadoc) * @see com.windowtester.codegen.generator.ICodeBlockBuilder#buildWidgetClosing(com.windowtester.recorder.event.user.SemanticWidgetClosedEvent) */ public CodeBlock buildWidgetClosing(SemanticWidgetClosedEvent event) { addImports(event); String locatorString = LocatorJavaStringFactory.toJavaString(event); StringBuffer sb = new StringBuffer(); // sb.append(getInstanceName()).append(".close(").append(locatorString).append(");").append(NEW_LINE); sb.append(getInstanceName()).append(".ensureThat(").append(locatorString).append(".isClosed());").append(NEW_LINE); return new CodeBlock(sb); } private CodeBlock buildSWTShellClosing(SemanticShellClosingEvent event) { addImports(event); String locatorString = LocatorJavaStringFactory.toJavaString(event); StringBuffer sb = new StringBuffer(); // sb.append(getInstanceName()).append(".close(").append(locatorString).append(");").append(NEW_LINE); sb.append(getInstanceName()).append(".ensureThat(").append(locatorString).append(".isClosed());").append(NEW_LINE); return new CodeBlock(sb); } public CodeBlock buildTextEntry(String string) { string = CodeGenSnippetBuilder.handleEscapes(string); StringBuffer sb = new StringBuffer(); sb.append(getInstanceName()).append('.').append("enterText(\"") .append(string).append("\");").append(NEW_LINE); return new CodeBlock(sb); } public CodeBlock buildTableSelect(SemanticTableSelectionEvent tableSelection) { addImport(java.awt.Point.class); addImports(tableSelection); //optionallyAddSWTModifierInfoIfNecessary(tableSelection); StringBuffer sb = new StringBuffer(); // check for context click String cmd = "click"; String menuPath = tableSelection.getContextMenuSelectionPath(); if (tableSelection.getButton() == 3 && menuPath != null) cmd = "contextClick"; sb.append(getInstanceName()).append('.').append(cmd).append("("); // check if mods, then append click count if (tableSelection.getMask() != null) { String clickString = (tableSelection.getClicks() == 1) ? "1, " : "2, "; sb.append(clickString); } sb.append(LocatorJavaStringFactory.toJavaString(tableSelection.getHierarchyInfo())); if (tableSelection.getButton() == 3) { if (menuPath != null) sb.append(", \"").append(escapeTabs(menuPath)).append("\""); } //check for modifiers optionallyHandleClickMods(sb, tableSelection); //close block sb.append(");").append(NEW_LINE); return new CodeBlock(sb.toString()); //return selectBlock(tableSelection); } public CodeBlock buildTreeSelect(SemanticTreeItemSelectionEvent event) { addImports(event); optionallyAddSWTModifierInfoIfNecessary(event); StringBuffer sb = new StringBuffer(); TreeEventType type = event.getType(); if (type == TreeEventType.SINGLE_CLICK || type == TreeEventType.DOUBLE_CLICK) { String cmd = "click"; boolean isContext = event.getButton() == 3; //context clicks (override clicks/double-clicks) if (isContext) cmd = "contextClick"; sb.append(getInstanceName()).append('.').append(cmd).append("("); optionallyAppendTreeClickCount(sb, event); sb.append(LocatorJavaStringFactory.toJavaString(event.getHierarchyInfo())); if (event.getButton() == 3) { String menuPath = event.getContextMenuSelectionPath(); if (menuPath != null) sb.append(", \"").append(escapeTabs(menuPath)).append("\""); } //check for modifiers if (!isContext) optionallyHandleClickMods(sb, event); //close block sb.append(");").append(NEW_LINE); } return new CodeBlock(sb.toString()); } public CodeBlock buildWaitForShellDisposed(SemanticShellDisposedEvent event) { if (isSwing(event)) { addImport(WindowDisposedCondition.class); } else addImport(ShellDisposedCondition.class); StringBuffer sb = new StringBuffer(); sb.append(getInstanceName()).append(".wait("); sb.append(getSystemBuilder(event).shellDisposedCondition(event.getName())); sb.append(");").append(NEW_LINE); return new CodeBlock(sb); } public CodeBlock buildWaitForShellShowing(SemanticShellShowingEvent event) { if (isSwing(event)) { addImport(WindowShowingCondition.class); } else addImport(ShellShowingCondition.class); StringBuffer sb = new StringBuffer(); sb.append(getInstanceName()).append(".wait("); sb.append(getSystemBuilder(event).shellShowCondition(event.getName())); sb.append(");").append(NEW_LINE); return new CodeBlock(sb); } ////////////////////////////////////////////////////////////////////////// // // Key Events // ////////////////////////////////////////////////////////////////////////// /* (non-Javadoc) * @see com.windowtester.codegen.generator.ICodeBlockBuilder#getKeyEventImport() */ public ImportUnit getKeyEventImport() { //kludge to handle Swing case if (getBuilder() instanceof SwingTestCaseBuilder) { return new ImportUnit(KeyEvent.class.getName()); } return new ImportUnit(WT.class.getName()); //this returns SWT! //return _builder.getKeyEventImport(); } ////////////////////////////////////////////////////////////////////////// // // Builder Utility Helpers // ////////////////////////////////////////////////////////////////////////// private String getInstanceName() { return getBuilder().getUIContextInstanceName(); } private ITestCaseBuilder getBuilder() { return _builder; } //////////////////////////////////////////////////////////////////////////////////////// // // Formatting // //////////////////////////////////////////////////////////////////////////////////////// private static String escapeTabs(String str) { return str.replaceAll("\t", "\\\\t"); } //////////////////////////////////////////////////////////////////////////////////////// // // Imports // //////////////////////////////////////////////////////////////////////////////////////// //add prerequisite imports private void addImports(IUISemanticEvent event) { Object locator = event.getHierarchyInfo(); addImportsForLocator(locator); } private void addImportsForLocator(Object locator) { if (locator instanceof ISelfDescribingLocator) { ((ISelfDescribingLocator)locator).addImports(getBuilder()); return; } if (locator instanceof IAdaptable) { ICodegenParticipant cp = (ICodegenParticipant) ((IAdaptable)locator).getAdapter(ICodegenParticipant.class); if (cp != null) { cp.describeTo(new DefaultCodeGenerator() { public ICodeGenerator addImport(String importString) { NewAPICodeBlockBuilder.this.addImport(importString); return this; } public ICodeGenerator append(String body) { return this; } }); return; } } if (locator instanceof IdentifierAdapter) locator = ((IdentifierAdapter)locator).getLocator(); boolean isTreeItemLocatorCase = locator instanceof TreeItemLocator; while (locator != null) { //tree items ignore parents if they are generic tree locators that don't themselves have parents if (isTreeItemLocatorCase && locator.getClass().equals(SWTWidgetLocator.class) || locator.getClass().equals(FilteredTreeLocator.class)) { SWTWidgetLocator parent = (SWTWidgetLocator)locator; if (parent.getParentInfo() != null) addImport(parent.getClass()); } else { addImport(locator.getClass()); } //icky cast... if (locator instanceof WidgetLocator) { /* * First we need to unpack control locators in the virtual locator case * TODO: might there be more than one? */ // kp: added support for Swing widgetlocators if (locator instanceof SwingWidgetLocator) addImports((SwingWidgetLocator)locator); if (locator instanceof VirtualItemLocator) addImports(((VirtualItemLocator)locator).getControlLocator()); //repeat kludge! -- rub: we need to pull target class out of label-wrappered locators if (locator.getClass() == LabeledLocator.class) addImport(((LabeledLocator)locator).getTargetClassName()); //SWTWidgetLocators need their target classes handled as well if (locator.getClass() == SWTWidgetLocator.class) { String clsName = ((SWTWidgetLocator)locator).getTargetClassName(); //(Implicit) trees should not get added in the treeitem case //(unless there's a parent to the tree locator) if (!isTreeItemLocatorCase || !clsName.equals("org.eclipse.swt.widgets.Tree") || ((SWTWidgetLocator)locator).getParentInfo() != null) addImport(((SWTWidgetLocator)locator).getTargetClassName()); } //then move on to the next locator //in case of a pulldown, this is the control: if (locator instanceof PullDownMenuItemLocator) { locator = ((PullDownMenuItemLocator)locator).getControlLocator(); } else { locator = ((WidgetLocator)locator).getParentInfo(); } } else { locator = null; //just short-circuit... } } } //unpack and add preqs private void addImports(SWTWidgetLocator locator) { if (locator == null) return; //no-op Class<?> cls = locator.getClass(); addImport(cls); //this is a kludge! -- rub: we need to pull target class out of label-wrappered locators if (cls == LabeledLocator.class) //addImport(((LabeledLocator)locator).getTargetClass()); addImport(((LabeledLocator)locator).getTargetClassName()); } private void addImports(SwingWidgetLocator locator){ if (locator == null) return; //no-op // changed getTargetClass() to getTargetClassName() Class<?> cls = locator.getClass(); addImport(cls); if (cls == JTextComponentLocator.class) addImport(((JTextComponentLocator)locator).getTargetClassName()); if (cls == SwingWidgetLocator.class) if (!LocatorUtil.isInternalSwingClass(locator.getTargetClassName())) addImport(locator.getTargetClassName()); } private void addImport(Class<?> cls) { addImport(new ImportUnit(cls.getName())); } private void addImport(ImportUnit imprt) { getBuilder().addImport(imprt); } private void addImport(String clsName){ addImport(new ImportUnit(clsName)); } //////////////////////////////////////////////////////////////////////////////////////// // // Swing/SWT System Accessors // //////////////////////////////////////////////////////////////////////////////////////// private boolean isSwing(IUISemanticEvent event) { return !isSWT(event); } private boolean isSWT(IUISemanticEvent event) { //first we can quickly test for the simple case if (event.getItemClass().startsWith("org.eclipse.swt")) return true; //else look a little further IWidgetIdentifier locator = event.getHierarchyInfo(); // return locator instanceof com.windowtester.swt.WidgetLocator || // locator instanceof SWTWidgetLocator; return locator instanceof SWTWidgetLocator; } IWidgetSystemCodeBlockBuilder getSystemBuilder(IUISemanticEvent event) { return isSwing(event) ? SwingCodeBlockBuilder.getInstance() : SWTCodeBlockBuilder.getInstance(); } //////////////////////////////////////////////////////////////////////////////////////// // // Legacy handling Helpers // //////////////////////////////////////////////////////////////////////////////////////// //convert legacy to new key constant (e.g., SWT.ALT -> WT.ALT) private String fixLegacyKey(String keyConstant) { //notice it does trim as a side effect but this is safe keyConstant = keyConstant.trim(); if (keyConstant.startsWith("SWT")) return keyConstant.substring(1); return keyConstant; } //////////////////////////////////////////////////////////////////////////////////////// // // Optional appends // //////////////////////////////////////////////////////////////////////////////////////// //test for modifiers and append if necessary private void optionallyHandleClickMods(StringBuffer sb, IUISemanticEvent event) { if (!(event instanceof IMaskable)) return; //no-op IMaskable maskedEvent = (IMaskable)event; if (isSWT(event)){ if (event.getHierarchyInfo() instanceof TableItemLocator) tableSelectionAppendSWTMaskAndAddImports(sb, maskedEvent); else optionallyAppendSWTMaskAndAddImports(sb, maskedEvent); } else optionallyAppendSwingMask(sb, maskedEvent); } private void optionallyAppendSwingMask(StringBuffer sb, IMaskable maskedEvent) { String mod = "InputEvent."; String mask = maskedEvent.getMask(); if (mask == null) return; //nothing to do List<String> convertedMasks = new ArrayList<String>(); StringTokenizer strtok = new StringTokenizer(mask, "|"); while (strtok.hasMoreTokens()) { String m = strtok.nextToken().trim(); convertedMasks.add(mod.concat(m)); } //bail if there's nothing to do if (convertedMasks.isEmpty()) return; //add a leading comma ", " unless the last char is a '(' or a ',' String currentBlockString = sb.toString().trim(); if (!(currentBlockString.endsWith("(") || currentBlockString.endsWith(","))) sb.append(", "); //now build the tokens back up for (Iterator<String> iter = convertedMasks.iterator(); iter.hasNext(); ) { sb.append(iter.next()); if (iter.hasNext()) sb.append(" | "); } addImport(InputEvent.class); } //some locators do not have their modifier info set at recording time //the info is in the vent and needs to get migrated to the locator to simplify codegen private void optionallyAddSWTModifierInfoIfNecessary(IUISemanticEvent event) { IWidgetIdentifier locator = event.getHierarchyInfo(); if (!(locator instanceof IModifiable)) return; //nothing to do if (!(event instanceof ICheckable)) return; //nothing to do IModifiable modifiable = (IModifiable)locator; ICheckable checkable = (ICheckable)event; if (checkable.getChecked()) { modifiable.setSelectionModifiers(modifiable.getSelectionModifiers() | WT.CHECK); addImport(WT.class); } } private void optionallyAppendTreeClickCount(StringBuffer sb, SemanticTreeItemSelectionEvent event) { if (event.isContext()) return; TreeEventType type = event.getType(); //TODO: triple+ clicks if (type == TreeEventType.DOUBLE_CLICK) { sb.append("2, "); return; } //modified clicks require count as well if (event.getMask() != null) { String clickString = (type == TreeEventType.DOUBLE_CLICK) ? "2, " : "1, "; sb.append(clickString); } } private void optionallyAppendSWTMaskAndAddImports(StringBuffer sb, IMaskable maskedEvent) { String mask = maskedEvent.getMask(); if (mask == null) return; //nothing to do List<String> convertedMasks = new ArrayList<String>(); StringTokenizer strtok = new StringTokenizer(mask, "|"); while (strtok.hasMoreTokens()) { String m = strtok.nextToken().trim(); //buttons are ignored (SWT.BUTTON1) -- CHECKS too if (m.startsWith("SWT") && !m.startsWith("SWT.BUTTON") && !m.equals("SWT.CHECK")) { addImport(WT.class); convertedMasks.add(m.substring(1)); } } appendSWTMask(sb, convertedMasks); } private void tableSelectionAppendSWTMaskAndAddImports(StringBuffer sb, IMaskable maskedEvent) { String mask = maskedEvent.getMask(); if (mask == null) return; //nothing to do List<String> convertedMasks = new ArrayList<String>(); StringTokenizer strtok = new StringTokenizer(mask, "|"); while (strtok.hasMoreTokens()) { String m = strtok.nextToken().trim(); if (m.startsWith("SWT") && !m.startsWith("SWT.BUTTON")) { addImport(WT.class); convertedMasks.add(m.substring(1)); } } appendSWTMask(sb, convertedMasks); } private void appendSWTMask(StringBuffer sb, List<String> convertedMasks) { //bail if there's nothing to do if (convertedMasks.isEmpty()) return; //add a leading comma ", " unless the last char is a '(' or a ',' String currentBlockString = sb.toString().trim(); if (!(currentBlockString.endsWith("(") || currentBlockString.endsWith(","))) sb.append(", "); //now build the tokens back up for (Iterator<String> iter = convertedMasks.iterator(); iter.hasNext(); ) { sb.append(iter.next()); if (iter.hasNext()) sb.append(" | "); } } private String optionallyWrapBlockInColumnLocator(String block, IUISemanticEvent event) { if (event.getIndex() != -1 && event.getHierarchyInfo() instanceof TableItemLocator) { addImport(ColumnLocator.class); return wrapInColumnLocator(block, event); } return block; } private String optionallyWrapBlockInXYLocator(String block, IUISemanticEvent event) { if (requiresXY(event)) { addImport(XYLocator.class); return wrapInXYLocator(block, event); } return block; } private boolean requiresXY(IUISemanticEvent event) { //check for overriding hint IIdentifierHintProvider hint = (IIdentifierHintProvider) Adapter.adapt(event.getHierarchyInfo(), IIdentifierHintProvider.class); if (hint != null) return hint.requiresXY(); return event.requiresLocationInfo(); } private String wrapInXYLocator(String block, IUISemanticEvent event) { StringBuffer sb = new StringBuffer(); sb.append("new XYLocator(").append(block).append(", ").append(event.getX()).append(", ").append(event.getY()).append(")"); return sb.toString(); } private String wrapInColumnLocator(String block, IUISemanticEvent event) { StringBuffer sb = new StringBuffer(); sb.append("new ColumnLocator(").append(event.getIndex()).append(", ").append(block).append(")"); return sb.toString(); } //////////////////////////////////////////////////////////////////////////////////////// // // Debugging // //////////////////////////////////////////////////////////////////////////////////////// private CodeBlock notHandled(String type) { return new CodeBlock("//event type: [" + type + "] not handled" + NEW_LINE); } }