/******************************************************************************* * 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 org.eclipse.core.runtime.Platform; import com.windowtester.codegen.util.LocatorUtil; 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.finder.ISearchScope; import com.windowtester.internal.runtime.locator.IdentifierAdapter; import com.windowtester.recorder.event.IUISemanticEvent; import com.windowtester.runtime.IAdaptable; import com.windowtester.runtime.WT; import com.windowtester.runtime.WidgetLocator; import com.windowtester.runtime.locator.IItemLocator; import com.windowtester.runtime.locator.ILocator; import com.windowtester.runtime.locator.IPathLocator; import com.windowtester.runtime.locator.IWidgetLocator; import com.windowtester.runtime.swing.SwingWidgetLocator; import com.windowtester.runtime.swing.locator.AbstractPathLocator; import com.windowtester.runtime.swing.locator.JTableItemLocator; import com.windowtester.runtime.swing.locator.JTextComponentLocator; import com.windowtester.runtime.swt.internal.locator.IControlRelativeLocator; import com.windowtester.runtime.swt.internal.locator.IModifiable; import com.windowtester.runtime.swt.internal.util.TextUtils; import com.windowtester.runtime.swt.locator.LabeledLocator; import com.windowtester.runtime.swt.locator.LabeledTextLocator; import com.windowtester.runtime.swt.locator.NamedWidgetLocator; import com.windowtester.runtime.swt.locator.SWTWidgetLocator; import com.windowtester.runtime.swt.locator.TreeItemLocator; import com.windowtester.runtime.swt.locator.eclipse.ActiveEditorLocator; import com.windowtester.runtime.swt.locator.eclipse.PerspectiveLocator; /** * Factory for generating Java Strings from locator instances. */ public class LocatorJavaStringFactory { //warning for use in testing ONLY! public static class TestOverride { private static ICodegenAdvisor testAdvisor; public static void setToStringDelegate(ICodegenAdvisor testAdvisor) { TestOverride.testAdvisor = testAdvisor; } public static boolean isSet() { return testAdvisor != null; } } public static String toJavaString(IUISemanticEvent event) { IWidgetIdentifier locator = event.getHierarchyInfo(); if (locator instanceof IdentifierAdapter) return toJavaString(((IdentifierAdapter)locator).getLocator()); // if (locator instanceof com.windowtester.swt.WidgetLocator) // return SWTLocatorJavaStringFactory.locatorToJavaString(event); return toJavaString(locator); } public static String toJavaString(ILocator locator) { ICodegenParticipant cp = adaptToCodegenParticipant(locator); if (cp != null ) { ICodeGenerator cg = new CodeGenDelegate(); cp.describeTo(cg); return cg.toString(); } if (locator instanceof SwingWidgetLocator) return wlToString((SwingWidgetLocator)locator); if (locator instanceof SWTWidgetLocator) return wlToString((SWTWidgetLocator)locator); return basicToString(locator); } //not accessible to subclasses to avoid possibility of circularity private static String basicToString(ILocator locator) { String contributed = delegateToString(locator); if (contributed != null) return contributed; StringBuffer sb = new StringBuffer(); appendCons(sb, locator); optionallyAppendPath(sb, locator); optionallyAppendScope(sb, locator); sb.append(")"); return sb.toString(); } protected static String delegateToString(ILocator locator) { if (TestOverride.isSet()) return TestOverride.testAdvisor.toJavaString(locator); if (!Platform.isRunning()) return null; return CodegenContributionManager.toJavaString(locator); } protected static void optionallyAppendScope(StringBuffer sb, ILocator locator) { IWidgetLocator scopeLocator = adaptToScopeLocator(locator); if (scopeLocator == null) return; if (scopeLocator instanceof ActiveEditorLocator) return; //this is the default find behavior sb.append(", "); sb.append(toJavaString(scopeLocator)); } protected static IWidgetLocator adaptToScopeLocator(ILocator locator) { if (!(locator instanceof IAdaptable)) return null; ISearchScope scope = (ISearchScope) ((IAdaptable)locator).getAdapter(ISearchScope.class); IWidgetLocator scopeLocator = adaptToLocator(scope); return scopeLocator; } protected static IWidgetLocator adaptToLocator(ISearchScope scope) { if (scope instanceof IWidgetLocator) return (IWidgetLocator)scope; if (!(scope instanceof IAdaptable)) return null; return (IWidgetLocator) ((IAdaptable)scope).getAdapter(IWidgetLocator.class); } protected static void optionallyAppendPath(StringBuffer sb, ILocator locator) { /* * perspective special case: */ if (locator instanceof PerspectiveLocator) { sb.append("\"").append(((PerspectiveLocator)locator).getPerspectiveId()).append("\""); return; } IItemLocator itemLocator = adaptToItemLocator(locator); if (itemLocator == null) return; String path = itemLocator.getPath(); sb.append("\"").append(path).append("\""); } protected static IItemLocator adaptToItemLocator(ILocator locator) { if (locator instanceof IItemLocator) { return (IItemLocator)locator; } if (locator instanceof IAdaptable) return (IItemLocator) ((IAdaptable)locator).getAdapter(IItemLocator.class); return null; } private static class CodeGenDelegate extends DefaultCodeGenerator { private StringBuffer sb = new StringBuffer(); public ICodeGenerator addImport(String importString) { //ignored here return this; } public ICodeGenerator append(String body) { sb.append(body); return this; } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return sb.toString(); } } public static String toJavaString(IWidgetIdentifier locator) { StringBuffer sb = new StringBuffer(); if (locator instanceof ISelfDescribingLocator) return ((ISelfDescribingLocator)locator).toJavaString(); ICodegenParticipant cp = adaptToCodegenParticipant(locator); if (cp != null ) { ICodeGenerator cg = new CodeGenDelegate(); cp.describeTo(cg); return cg.toString(); } if (locator instanceof SwingWidgetLocator) return wlToString((SwingWidgetLocator)locator); if (locator instanceof SWTWidgetLocator) return wlToString((SWTWidgetLocator)locator); return sb.toString(); } private static ICodegenParticipant adaptToCodegenParticipant(Object locator) { if (locator instanceof ICodegenParticipant) return (ICodegenParticipant) locator; if (locator instanceof IAdaptable) { return (ICodegenParticipant) ((IAdaptable)locator).getAdapter(ICodegenParticipant.class); } return null; } protected static String wlToString(SWTWidgetLocator locator) { StringBuffer sb = new StringBuffer(); appendCons(sb, locator); optionallyAppendModifiers(sb, locator); //"raw" widgetlocator case if (locator.getClass() == SWTWidgetLocator.class) { appendClass(sb, locator); } //label special case: labeled widget class PRECEDES label if (locator instanceof LabeledLocator && !(locator instanceof LabeledTextLocator)) { appendClass(sb, locator); } //path based locator case //TODO: make this an interface! if (locator instanceof IPathLocator) { appendPath(sb, (IPathLocator)locator); //default } else { appendLabel(sb, locator); } appendParentInfo(sb, locator); sb.append(")"); return sb.toString(); } protected static void appendCons(StringBuffer sb, ILocator locator) { String className = getClassName(locator.getClass()); sb.append("new "); sb.append(className); sb.append("("); } //check for modifiers like WT.CHECK protected static void optionallyAppendModifiers(StringBuffer sb, SWTWidgetLocator locator) { //checked case if (locator instanceof IModifiable) { int mods = ((IModifiable)locator).getSelectionModifiers(); if (isCheck(mods)) { appendCheck(sb); appendDelimeter(sb); } } } protected static void appendCheck(StringBuffer sb) { sb.append("WT.CHECK"); } protected static boolean isCheck(int mods) { return (mods & WT.CHECK) == WT.CHECK; } protected static void appendClass( StringBuffer sb, SWTWidgetLocator locator) { String targetClassName = locator.getTargetClassName(); if (targetClassName != null){ sb.append(getClassName(targetClassName)).append(".class"); } } protected static String wlToString(com.windowtester.runtime.WidgetLocator locator) { if (locator instanceof SWTWidgetLocator) return wlToString((SWTWidgetLocator)locator); if (locator instanceof SwingWidgetLocator) return wlToString((SwingWidgetLocator)locator); throw new IllegalArgumentException("unexpected type: " + locator.getClass()); } protected static String wlToString(SwingWidgetLocator locator) { StringBuffer sb = new StringBuffer(); String className = getClassName(locator.getClass()); sb.append("new "); sb.append(className); sb.append("("); //"raw" widgetlocator case if (locator.getClass() == SwingWidgetLocator.class) { String targetClassName = locator.getTargetClassName(); Boolean isInternal = LocatorUtil.isInternalSwingClass(targetClassName); if (targetClassName != null && !isInternal){ sb.append(getClassName(targetClassName)).append(".class"); } else if (isInternal){ sb.append("\""); sb.append(getClassName(targetClassName)).append("\""); } } //path based locator case //TODO: make this an interface! if (locator instanceof AbstractPathLocator) { appendPath(sb, (AbstractPathLocator)locator); //tables } else if (locator instanceof JTableItemLocator) { appendTableInfo(sb, (JTableItemLocator)locator); //text } else if (locator instanceof JTextComponentLocator){ appendTextComponentInfo(sb,locator); } else { appendLabel(sb, locator); } appendParentInfo(sb, locator); sb.append(")"); return sb.toString(); } protected static void appendTableInfo(StringBuffer sb, JTableItemLocator locator) { // appendLabel(sb, locator); sb.append("new Point(").append(locator.getRow()).append(',').append(locator.getColumn()).append(')'); } protected static void appendTextComponentInfo(StringBuffer sb,SwingWidgetLocator locator){ String targetClassName = locator.getTargetClassName(); // check for caret position int caret = ((JTextComponentLocator)locator).getCaretPosition(); if (caret != WidgetLocator.UNASSIGNED){ sb.append(caret); sb.append(","); } if (!(locator instanceof com.windowtester.runtime.swing.locator.LabeledTextLocator)) sb.append(getClassName(targetClassName)).append(".class"); appendLabel(sb,locator); } protected static void appendParentInfo(StringBuffer sb, SwingWidgetLocator locator) { com.windowtester.runtime.WidgetLocator parentInfo = locator.getParentInfo(); if (parentInfo != null) { int index = locator.getIndex(); if (index != SwingWidgetLocator.UNASSIGNED){ appendDelimeter(sb); sb.append(index); } appendDelimeter(sb); sb.append(wlToString(parentInfo)); } } protected static void appendParentInfo(StringBuffer sb, SWTWidgetLocator locator) { com.windowtester.runtime.WidgetLocator parentInfo = locator.getParentInfo(); //note, virtual items have virtual parents and we need to fetch those... if (locator instanceof IControlRelativeLocator) parentInfo = ((IControlRelativeLocator)locator).getControlLocator(); if (parentInfo != null && !specialCaseIgnoreParentLocator(locator)) { int index = locator.getIndex(); if (index != SWTWidgetLocator.UNASSIGNED){ appendDelimeter(sb); sb.append(index); } appendDelimeter(sb); sb.append(wlToString(parentInfo)); } } // protected static com.windowtester.runtime.WidgetLocator optionallyResynthesizeVirtualParents(SWTWidgetLocator locator, com.windowtester.runtime.WidgetLocator parentInfo) { // if (locator instanceof ComboItemLocator) { // if (parentInfo == null) { // parentInfo = locator.getParentInfo(); // if (parentInfo != null) // parentInfo = new SWTWidgetLocator(Combo.class, WidgetLocator.UNASSIGNED, (SWTWidgetLocator)parentInfo); // } // } // if (locator instanceof CComboItemLocator) { // if (parentInfo == null) { // parentInfo = locator.getParentInfo(); // if (parentInfo != null) // parentInfo = new SWTWidgetLocator(CCombo.class, WidgetLocator.UNASSIGNED, (SWTWidgetLocator)parentInfo); // } // } // return parentInfo; // } /** * This identifies special cases where parent hierarchy can be ignored (it's implicit). */ protected static boolean specialCaseIgnoreParentLocator(SWTWidgetLocator locator) { if (locator instanceof TreeItemLocator) { com.windowtester.runtime.WidgetLocator parentInfo = locator.getParentInfo(); //note: want to provision for named case, which should NOT be special cased if (parentInfo instanceof NamedWidgetLocator) return false; //return (parentInfo != null && parentInfo.getTargetClass() == Tree.class && !(parentInfo instanceof LabeledLocator) && parentInfo.getParentInfo() == null); //^--- is this scary enough?!? ;) [!pq: let's fix 2.0] return (parentInfo != null && parentInfo.getTargetClassName().equals("org.eclipse.swt.widgets.Tree") && !(parentInfo instanceof LabeledLocator) && parentInfo.getParentInfo() == null); } return false; } static void appendLabel(StringBuffer sb, IWidgetIdentifier locator) { String label = locator.getNameOrLabel(); if (label != null) { appendDelimeter(sb); sb.append("\"").append(escapeText(label)).append("\""); } } //append a comma if necessary protected static void appendDelimeter(StringBuffer sb) { String current = sb.toString().trim(); if (!current.endsWith("(") && !current.endsWith(",")) sb.append(", "); } protected static void appendPath(StringBuffer sb, IPathLocator pathLocator) { String path = pathLocator.getPath(); if (path != null) sb.append("\"").append(escapeTabs(escapeText(path))).append("\""); } protected static String escapeText(String text) { return TextUtils.escapeText(text); } protected static String escapeTabs(String str) { return str.replaceAll("\t", "\\\\t"); } static String getClassName(Class cls) { return getClassName(cls, false); } protected static String getClassName(Class cls, boolean qualify) { // get the simple name of the class int lastPeriod = cls.getName().lastIndexOf('.'); String simpleName = (lastPeriod >= 0) ? cls.getName().substring( lastPeriod + 1) : cls.getName(); // cls return (qualify) ? cls.getName() : simpleName; } protected static String getClassName(String str){ int lastPeriod = str.lastIndexOf('.'); String simpleName = (lastPeriod >= 0) ? str.substring( lastPeriod + 1) : str; return simpleName; } }