blob: 953693ba68106df9144b4e08191896618830d31e [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.motorola.studio.android.generateviewbylayout;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import com.motorola.studio.android.generatecode.JDTUtils;
import com.motorola.studio.android.generateviewbylayout.model.CodeGeneratorDataBasedOnLayout;
/**
* Visitor responsible to search method invocations inside a method body
* and set the layout name associated with the activity / fragment
*/
public class MethodBodyVisitor extends ASTVisitor
{
/*
* Constants
*/
private static final String INFLATE = "inflate"; //$NON-NLS-1$
private static final String VIEW = "View"; //$NON-NLS-1$
private static final String ACTIVITY_METHOD_TO_SET_LAYOUT = "setContentView"; //$NON-NLS-1$
private static final String FRAGMENT_METHOD_TO_SET_LAYOUT = INFLATE;
private String layoutName;
/**
* If type is fragment, there may be an inflated view name.
* This will be used to call findViewById inside fragments
*/
private String inflatedViewName;
private CodeGeneratorDataBasedOnLayout.TYPE typeAssociatedToLayout;
private Set<String> declaredViewIds = new HashSet<String>();
public String getLayoutName()
{
return layoutName;
}
public void setLayoutName(String layoutName)
{
this.layoutName = layoutName;
}
/**
* Visits statements to find inflate method called on fragments
* to get the name of the view declared (this info will be used on findViewById,
* for fragments only)
*/
@Override
public boolean visit(VariableDeclarationStatement node)
{
if (node.getType().toString().equals(VIEW))
{
VariableDeclarationFragment frag =
(VariableDeclarationFragment) node.fragments().get(0);
if (frag.getInitializer() instanceof MethodInvocation)
{
MethodInvocation invoke = (MethodInvocation) frag.getInitializer();
String invokeName = invoke.getName().toString();
if (invoke.getExpression() instanceof SimpleName)
{
if ((invokeName != null) && invokeName.equals(INFLATE))
{
inflatedViewName = frag.getName().getFullyQualifiedName();
}
}
}
}
return super.visit(node);
}
/**
* Visit method invocations to find layout name set on activity/fragment
*/
@Override
public boolean visit(MethodInvocation node)
{
//Fill invoked method model.
MethodInvocation invoked = node;
IMethodBinding methodBinding = invoked.resolveMethodBinding();
if (methodBinding != null)
{
String methodSimpleName = methodBinding.getName();
//Retrieve parameter types and look for R constants used within method arguments
List<?> arguments = invoked.arguments();
for (Object argument : arguments)
{
Expression argumentExpression = (Expression) argument;
if (argumentExpression instanceof QualifiedName) /*Can be a constant access*/
{
QualifiedName qualifiedName = (QualifiedName) argumentExpression;
String layoutName = qualifiedName.getName().getIdentifier();
if (methodSimpleName != null)
{
if (methodSimpleName.equals(ACTIVITY_METHOD_TO_SET_LAYOUT))
{
typeAssociatedToLayout = CodeGeneratorDataBasedOnLayout.TYPE.ACTIVITY;
setLayoutName(layoutName);
}
else if (methodSimpleName.equals(FRAGMENT_METHOD_TO_SET_LAYOUT))
{
typeAssociatedToLayout = CodeGeneratorDataBasedOnLayout.TYPE.FRAGMENT;
setLayoutName(layoutName);
checkInflatedViewNameOnFields(node);
}
else if (methodSimpleName
.equals(JavaViewBasedOnLayoutModifierConstants.FIND_VIEW_BY_ID)
|| methodSimpleName
.equals(JavaViewBasedOnLayoutModifierConstants.FIND_FRAGMENT_BY_ID)) //$NON-NLS-1$
{
//findViewById
String viewId = qualifiedName.getName().toString();
getDeclaredViewIds().add(viewId);
}
}
}
}
}
return super.visit(node);
}
private void checkInflatedViewNameOnFields(MethodInvocation node)
{
//check if this method invocation is binded to an assignment
ASTNode nodeParent = node.getParent();
while ((nodeParent != null) && (inflatedViewName == null))
{
if (nodeParent instanceof Assignment)
{
Assignment assignment = (Assignment) nodeParent;
Expression lhs = assignment.getLeftHandSide();
ITypeBinding binding = lhs.resolveTypeBinding();
IJavaElement javaElement = binding.getJavaElement();
if ((javaElement != null) && (lhs instanceof SimpleName))
{
IType type = (IType) javaElement.getAdapter(IType.class);
if (type != null)
{
try
{
if (JDTUtils.isSubclass(type, "android.view.View"))
{
inflatedViewName = ((SimpleName) lhs).getFullyQualifiedName();
}
}
catch (JavaModelException e)
{
// do nothing
}
}
}
}
nodeParent = nodeParent.getParent();
}
}
/**
* @return the typeAssociatedToLayout
*/
public CodeGeneratorDataBasedOnLayout.TYPE getTypeAssociatedToLayout()
{
return typeAssociatedToLayout;
}
/**
* @return the inflatedViewName
*/
public String getInflatedViewName()
{
return inflatedViewName;
}
/**
* @param inflatedViewName the inflatedViewName to set
*/
public void setInflatedViewName(String inflatedViewName)
{
this.inflatedViewName = inflatedViewName;
}
/**
* @return the declaredLayoutIds
*/
public synchronized Set<String> getDeclaredViewIds()
{
return declaredViewIds;
}
}