/* * Copyright (C) 2013 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.android.tools.idea.editors.navigation.macros; import com.android.navigation.*; import com.android.tools.idea.editors.navigation.Utilities; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; public class CodeGenerator { public final Module module; public final NavigationModel navigationModel; public CodeGenerator(NavigationModel navigationModel, Module module) { this.navigationModel = navigationModel; this.module = module; } /* Map<String, PsiElement> bindings = new HashMap<String, PsiElement>(); bindings.put("$menuItem", factory.createIdentifier("hello")); bindings.put("$f", factory.createIdentifier("goodbye")); bindings.put("$consume", factory.createExpressionFromText("true", body)); PsiElement newCode = Instantiation.instantiate(installMenuItemClick, bindings); */ private ActivityState getAssociatedActivityState(MenuState menuState) { for (Transition t : navigationModel.getTransitions()) { if (t.getDestination().getState() == menuState) { State state = t.getSource().getState(); if (state instanceof ActivityState) { return (ActivityState)state; } } } assert false; return null; } public void implementTransition(final Transition transition) { Project project = module.getProject(); JavaPsiFacade facade = JavaPsiFacade.getInstance(project); final PsiElementFactory factory = facade.getElementFactory(); final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); final Macros macros = Macros.getInstance(module.getProject()); State sourceState = transition.getSource().getState(); State destinationState = transition.getDestination().getState(); if (sourceState instanceof MenuState && destinationState instanceof ActivityState) { MenuState menuState = (MenuState)sourceState; final ActivityState newActivity = (ActivityState)destinationState; final ActivityState originatingActivity = getAssociatedActivityState(menuState); final PsiClass psiClass = Utilities.getPsiClass(module, originatingActivity.getClassName()); if (psiClass != null) { new WriteCommandAction<Void>(project, "Add navigation transition", psiClass.getContainingFile()) { @Override protected void run(Result<Void> result) { PsiMethod signature = factory.createMethodFromText("public boolean onPrepareOptionsMenu(Menu menu){ }", psiClass); PsiMethod method = psiClass.findMethodBySignature(signature, false); if (method == null) { method = factory.createMethodFromText( "@Override public boolean onPrepareOptionsMenu(Menu menu){boolean result=super.onPrepareOptionsMenu(menu);return result;}", psiClass); psiClass.add(method); method = psiClass.findMethodBySignature(signature, false); // the previously assigned method is not resolved somehow } String parameterName = method.getParameterList().getParameters()[0].getName(); PsiCodeBlock body = method.getBody(); PsiStatement[] statements = body.getStatements(); PsiStatement lastStatement = statements[statements.length - 1]; MultiMatch macro = macros.installMenuItemOnGetMenuItemAndLaunchActivityMacro; MultiMatch.Bindings<String> bindings = new MultiMatch.Bindings<String>(); bindings.put("$consume", "true"); bindings.put("$menuItem", "$menu", parameterName); bindings.put("$menuItem", "$id", "R.id." + transition.getSource().getViewName()); bindings.put("$f", "context", originatingActivity.getClassName() + ".this"); bindings.put("$f", "activityClass", newActivity.getClassName() + ".class"); String newCode = macro.instantiate(bindings); PsiStatement newStatement = factory.createStatementFromText(newCode + ";", body); body.addBefore(newStatement, lastStatement); codeStyleManager.reformat(method); } }.execute(); } } if (sourceState instanceof ActivityState && destinationState instanceof MenuState) { ActivityState activityState = (ActivityState)sourceState; final MenuState menuState = (MenuState)destinationState; final PsiClass psiClass = Utilities.getPsiClass(module, activityState.getClassName()); if (psiClass != null) { new WriteCommandAction<Void>(project, "Add navigation transition", psiClass.getContainingFile()) { @Override protected void run(Result<Void> result) { PsiMethod signature = factory.createMethodFromText("boolean onCreateOptionsMenu(Menu menu){}", psiClass); PsiMethod method = psiClass.findMethodBySignature(signature, false); if (method == null) { method = factory.createMethodFromText("@Override public boolean onCreateOptionsMenu(Menu menu) { return true;}", psiClass); psiClass.add(method); method = psiClass.findMethodBySignature(signature, false); // // the previously assigned method is not resolved somehow } String parameterName = method.getParameterList().getParameters()[0].getName(); PsiCodeBlock body = method.getBody(); PsiStatement[] statements = body.getStatements(); PsiStatement lastStatement = statements[statements.length - 1]; String newStatementText = "getMenuInflater().inflate(R.menu.$XmlResourceName, $parameterName);"; newStatementText = newStatementText.replace("$XmlResourceName", menuState.getXmlResourceName()); newStatementText = newStatementText.replace("$parameterName", parameterName); PsiStatement newStatement = factory.createStatementFromText(newStatementText, body); body.addBefore(newStatement, lastStatement); codeStyleManager.reformat(method); } }.execute(); } } if (sourceState instanceof ActivityState && destinationState instanceof ActivityState) { final ActivityState sourceActivityState = (ActivityState)sourceState; final ActivityState newActivity = (ActivityState)destinationState; final PsiClass psiClass = Utilities.getPsiClass(module, sourceActivityState.getClassName()); if (psiClass != null) { new WriteCommandAction<Void>(project, "Add navigation transition", psiClass.getContainingFile()) { @Override protected void run(Result<Void> result) { PsiMethod signature = factory.createMethodFromText("void onCreate(Bundle savedInstanceState){}", psiClass); PsiMethod method = psiClass.findMethodBySignature(signature, false); if (method == null) { method = factory.createMethodFromText("@Override " + "public void onCreate(Bundle savedInstanceState) {" + "super.onCreate(savedInstanceState);}", psiClass); psiClass.add(method); method = psiClass.findMethodBySignature(signature, false); // // the previously assigned method is not resolved somehow } PsiCodeBlock body = method.getBody(); PsiStatement[] statements = body.getStatements(); PsiStatement lastStatement = statements[statements.length - 1]; String newCode = "findViewById($id).setOnClickListener(new View.OnClickListener() { " + " @Override" + " public void onClick(View v) {" + " $context.startActivity(new Intent($context, $activityClass));" + " }" + "})"; newCode = newCode.replaceAll("\\$id", "R.id." + transition.getSource().getViewName()); // todo improve newCode = newCode.replaceAll("\\$context", sourceActivityState.getClassName() + ".this"); newCode = newCode.replaceAll("\\$activityClass", newActivity.getClassName() + ".class"); PsiStatement newStatement = factory.createStatementFromText(newCode + ";", body); body.addAfter(newStatement, lastStatement); codeStyleManager.reformat(method); } }.execute(); } } } }