/*
* 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.codegenerators;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import com.motorola.studio.android.codeutils.i18n.CodeUtilsNLS;
import com.motorola.studio.android.generateviewbylayout.JavaViewBasedOnLayoutModifierConstants;
import com.motorola.studio.android.generateviewbylayout.model.CodeGeneratorDataBasedOnLayout;
import com.motorola.studio.android.generateviewbylayout.model.LayoutNode;
/**
* Responsible to add methods to deal with RadioButtons events
*/
public class RadioButtonCodeGenerator extends AbstractLayoutCodeGenerator
{
/**
* @param codeGeneratorData
* @param onCreateDeclaration
* @param typeDeclaration
*/
public RadioButtonCodeGenerator(CodeGeneratorDataBasedOnLayout codeGeneratorData,
MethodDeclaration onCreateDeclaration, TypeDeclaration typeDeclaration)
{
super(codeGeneratorData, onCreateDeclaration, typeDeclaration);
}
@Override
public void generateCode(IProgressMonitor monitor) throws JavaModelException
{
addSetOnClickListener(monitor);
addMethodToDeclareRadioButtonHandlerNotDeclaredOnLayoutXML(monitor);
}
/**
* Add method handlers for RadioButtons
*
* <br>
* GENERATED_CODE_FORMAT:
* <br>
* this.$GUI_ID.setOnClickListener(onClickHandler);
*/
@SuppressWarnings("unchecked")
private void addSetOnClickListener(IProgressMonitor monitor) throws JavaModelException
{
SubMonitor subMonitor = SubMonitor.convert(monitor);
subMonitor.beginTask(CodeUtilsNLS.JavaViewBasedOnLayoutModifier_AddingSetOnClickListener,
codeGeneratorData.getGuiItems().size());
/* ExpressionStatement
expression
MethodInvocation
arguments handler
methodName SimpleName(setOnClickListener)
optionalExpression SimpleName(button1)
*/
for (LayoutNode node : codeGeneratorData.getGuiItems())
{
if (node.shouldInsertCode()
&& node.getNodeType().equals(LayoutNode.LayoutNodeViewType.RadioButton.name()))
{
boolean containMethodDeclared =
checkIfInvokeMethodIsDeclared(node,
JavaViewBasedOnLayoutModifierConstants.SET_ON_CLICK_LISTENER);
if (!containMethodDeclared)
{
SimpleName method =
onCreateDeclaration.getAST().newSimpleName(
JavaViewBasedOnLayoutModifierConstants.SET_ON_CLICK_LISTENER);
SimpleName bId = onCreateDeclaration.getAST().newSimpleName(node.getNodeId());
FieldAccess fieldAccess = onCreateDeclaration.getAST().newFieldAccess();
fieldAccess.setExpression(onCreateDeclaration.getAST().newThisExpression());
fieldAccess.setName(bId);
SimpleName handler =
onCreateDeclaration
.getAST()
.newSimpleName(
JavaViewBasedOnLayoutModifierConstants.HANDLER_ONCLICK_LISTENER);
MethodInvocation mI = onCreateDeclaration.getAST().newMethodInvocation();
mI.arguments().add(handler);
mI.setName(method);
mI.setExpression(fieldAccess);
ExpressionStatement expr =
onCreateDeclaration.getAST().newExpressionStatement(mI);
if (!onCreateDeclaration.toString().contains(expr.toString()))
{
//avoid to duplicate statement
insertStatementsAtOnCreateDeclaration(expr, false);
}
}
}
subMonitor.worked(1);
}
}
/**
* Add method to declare button events handler (not declared on layout XML)
* @throws JavaModelException
*
* <br>
* GENERATED_CODE_FORMAT:
* <br>
* private View.OnClickListener onClickHandler = new View.OnClickListener() {
* <br>
* public void onClick(View target) {
* <br>
* if (target.getId() == $GUI_ID1) {
* <br>
* } else if (target.getId() == $GUI_ID2) {
* <br>
* }
* <br>
* }
* <br>
* };
*
*/
@SuppressWarnings(
{
"rawtypes", "unchecked"
})
private void addMethodToDeclareRadioButtonHandlerNotDeclaredOnLayoutXML(IProgressMonitor monitor)
throws JavaModelException
{
SubMonitor subMonitor = SubMonitor.convert(monitor);
//need to look at each GUI item and them create 1 method
subMonitor.beginTask(CodeUtilsNLS.JavaViewBasedOnLayoutModifier_AddingMethodToHandleButton,
codeGeneratorData.getGuiItems().size() + 1);
IfStatement ifStatement = null;
for (LayoutNode node : codeGeneratorData.getGuiItems())
{
if (node.getNodeType().equals(LayoutNode.LayoutNodeViewType.RadioButton.name())
&& node.shouldInsertCode())
{
if (typeDeclaration.bodyDeclarations() != null)
{
//check if field already declared
outer: for (Object bd : typeDeclaration.bodyDeclarations())
{
if (bd instanceof FieldDeclaration)
{
FieldDeclaration fd = (FieldDeclaration) bd;
if ((fd.fragments() != null))
{
String listenerType =
getListenerSimpleType(
JavaViewBasedOnLayoutModifierConstants.VIEW_CLASS,
JavaViewBasedOnLayoutModifierConstants.METHOD_ON_CLICK_LISTENER)
.toString();
for (Object fragment : fd.fragments())
{
if (fragment instanceof VariableDeclarationFragment)
{
VariableDeclarationFragment variableFragment =
(VariableDeclarationFragment) fragment;
if ((variableFragment.getName() != null)
&& variableFragment
.getName()
.toString()
.equals(JavaViewBasedOnLayoutModifierConstants.HANDLER_ONCLICK_LISTENER)
&& fd.getType().toString().equals(listenerType))
{
Expression expr = variableFragment.getInitializer();
if (expr instanceof ClassInstanceCreation)
{
ClassInstanceCreation classInstanceCreation =
(ClassInstanceCreation) expr;
AnonymousClassDeclaration anonymousClassDeclaration =
classInstanceCreation
.getAnonymousClassDeclaration();
for (Object bodyDeclaration : anonymousClassDeclaration
.bodyDeclarations())
{
if (bodyDeclaration instanceof MethodDeclaration)
{
MethodDeclaration methodDeclaration =
(MethodDeclaration) bodyDeclaration;
List statementsList =
methodDeclaration.getBody()
.statements();
for (Object statement : statementsList)
{
if (statement instanceof IfStatement)
{
if (statement
.toString()
.contains(
JavaViewBasedOnLayoutModifierConstants.VIEW_VARIABLE_NAME
+ "." //$NON-NLS-1$
+ JavaViewBasedOnLayoutModifierConstants.METHOD_NAME_GET_ID))
{
//found if statement
ifStatement =
(IfStatement) statement;
break outer;
}
}
}
if (ifStatement == null)
{
ifStatement =
typeDeclaration.getAST()
.newIfStatement();
statementsList.add(ifStatement);
}
}
}
}
}
}
}
}
}
}
}
if (ifStatement == null)
{
//create field with onClickListener class instance creation
//create method in the first time, after that, start to add new items in the same method
ifStatement = createOnClickListenerForRadioButtons(node);
}
else
{
//already have onClickListener field declared => append new item into the "else if" chain
addElseIfForEachRadioButtonId(ifStatement, node);
}
}
subMonitor.worked(1);
}
}
/**
* Creates field with an anonymous class declaration for radio buttons
*/
@SuppressWarnings("unchecked")
private IfStatement createOnClickListenerForRadioButtons(LayoutNode node)
{
IfStatement ifSt;
Modifier privateMod = typeDeclaration.getAST().newModifier(ModifierKeyword.PRIVATE_KEYWORD);
SimpleType listenerType =
getListenerSimpleType(JavaViewBasedOnLayoutModifierConstants.VIEW_CLASS,
JavaViewBasedOnLayoutModifierConstants.METHOD_ON_CLICK_LISTENER);
VariableDeclarationFragment variableFragment =
typeDeclaration.getAST().newVariableDeclarationFragment();
SimpleName varName =
variableFragment.getAST().newSimpleName(
JavaViewBasedOnLayoutModifierConstants.HANDLER_ONCLICK_LISTENER);
variableFragment.setName(varName);
FieldDeclaration declaration =
typeDeclaration.getAST().newFieldDeclaration(variableFragment);
declaration.modifiers().add(privateMod);
declaration.setType(listenerType);
ClassInstanceCreation classInstanceCreation =
typeDeclaration.getAST().newClassInstanceCreation();
SimpleType listenerType2 =
getListenerSimpleType(JavaViewBasedOnLayoutModifierConstants.VIEW_CLASS,
JavaViewBasedOnLayoutModifierConstants.METHOD_ON_CLICK_LISTENER);
classInstanceCreation.setType(listenerType2);
AnonymousClassDeclaration classDeclaration =
typeDeclaration.getAST().newAnonymousClassDeclaration();
MethodDeclaration methodDeclaration =
addMethodDeclaration(ModifierKeyword.PUBLIC_KEYWORD,
JavaViewBasedOnLayoutModifierConstants.METHOD_NAME_ON_CLICK,
PrimitiveType.VOID, JavaViewBasedOnLayoutModifierConstants.VIEW_CLASS,
JavaViewBasedOnLayoutModifierConstants.VIEW_VARIABLE_NAME);
Block block = typeDeclaration.getAST().newBlock();
ifSt = createElseIfForEachRadioButtonId(node);
block.statements().add(ifSt);
methodDeclaration.setBody(block);
classDeclaration.bodyDeclarations().add(methodDeclaration);
classInstanceCreation.setAnonymousClassDeclaration(classDeclaration);
variableFragment.setInitializer(classInstanceCreation);
typeDeclaration.bodyDeclarations().add(declaration);
return ifSt;
}
/**
* @return "else if" chain for each radio button id
*/
private IfStatement createElseIfForEachRadioButtonId(LayoutNode node)
{
IfStatement ifStatement = typeDeclaration.getAST().newIfStatement();
addElseIfForEachRadioButtonId(ifStatement, node);
return ifStatement;
}
/**
* Creates else if and else statements for each radio button
* @param ifSt If statement where the next "else if" will be appended
* @param node Layout node
*/
private void addElseIfForEachRadioButtonId(IfStatement ifSt, LayoutNode node)
{
if (node.getNodeType().equals(LayoutNode.LayoutNodeViewType.RadioButton.name())
&& node.shouldInsertCode())
{
MethodInvocation invocation = typeDeclaration.getAST().newMethodInvocation();
invocation
.setExpression(getVariableName(JavaViewBasedOnLayoutModifierConstants.VIEW_VARIABLE_NAME));
SimpleName getIdName =
typeDeclaration.getAST().newSimpleName(
JavaViewBasedOnLayoutModifierConstants.METHOD_NAME_GET_ID);
invocation.setName(getIdName);
SimpleName r =
typeDeclaration.getAST()
.newSimpleName(JavaViewBasedOnLayoutModifierConstants.R);
SimpleName id =
typeDeclaration.getAST().newSimpleName(
JavaViewBasedOnLayoutModifierConstants.ID);
QualifiedName rid = typeDeclaration.getAST().newQualifiedName(r, id);
SimpleName guiId = typeDeclaration.getAST().newSimpleName(node.getNodeId());
QualifiedName guiQN = typeDeclaration.getAST().newQualifiedName(rid, guiId);
createElseIfAndElseStatements(ifSt, invocation, guiQN);
}
}
}