| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * 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.intellij.uiDesigner.wizard; |
| |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.editor.Document; |
| import com.intellij.openapi.fileEditor.FileDocumentManager; |
| import com.intellij.openapi.fileEditor.FileEditorManager; |
| import com.intellij.openapi.fileEditor.OpenFileDescriptor; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.module.ModuleUtil; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.ProjectFileIndex; |
| import com.intellij.openapi.roots.ProjectRootManager; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.*; |
| import com.intellij.psi.codeStyle.CodeStyleManager; |
| import com.intellij.psi.codeStyle.JavaCodeStyleManager; |
| import com.intellij.psi.codeStyle.VariableKind; |
| import com.intellij.psi.util.PropertyUtil; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import com.intellij.refactoring.util.CommonRefactoringUtil; |
| import com.intellij.uiDesigner.FormEditingUtil; |
| import com.intellij.uiDesigner.PsiPropertiesProvider; |
| import com.intellij.uiDesigner.UIDesignerBundle; |
| import com.intellij.uiDesigner.compiler.AlienFormFileException; |
| import com.intellij.uiDesigner.compiler.Utils; |
| import com.intellij.uiDesigner.lw.LwComponent; |
| import com.intellij.uiDesigner.lw.LwRootContainer; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.IncorrectOperationException; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import javax.swing.text.JTextComponent; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| |
| /** |
| * @author Anton Katilin |
| * @author Vladimir Kondratyev |
| */ |
| public final class Generator { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.wizard.Generator"); |
| |
| private Generator() { |
| } |
| |
| /** |
| * @param rootContainer output parameter; should be LwRootContainer[1] |
| */ |
| public static FormProperty[] exposeForm(final Project project, final VirtualFile formFile, final LwRootContainer[] rootContainer) throws MyException{ |
| final Module module = ModuleUtil.findModuleForFile(formFile, project); |
| LOG.assertTrue(module != null); |
| |
| final PsiPropertiesProvider propertiesProvider = new PsiPropertiesProvider(module); |
| |
| final Document doc = FileDocumentManager.getInstance().getDocument(formFile); |
| final LwRootContainer _rootContainer; |
| try { |
| _rootContainer = Utils.getRootContainer(doc.getText(), propertiesProvider); |
| } |
| catch (AlienFormFileException e) { |
| throw new MyException(e.getMessage()); |
| } |
| catch (Exception e) { |
| throw new MyException(UIDesignerBundle.message("error.cannot.process.form.file", e)); |
| } |
| |
| rootContainer[0] = _rootContainer; |
| |
| final String classToBind = _rootContainer.getClassToBind(); |
| if (classToBind == null) { |
| throw new MyException(UIDesignerBundle.message("error.form.is.not.bound.to.a.class")); |
| } |
| |
| final PsiClass boundClass = FormEditingUtil.findClassToBind(module, classToBind); |
| if(boundClass == null){ |
| throw new MyException(UIDesignerBundle.message("error.bound.class.does.not.exist", classToBind)); |
| } |
| |
| final ArrayList<FormProperty> result = new ArrayList<FormProperty>(); |
| final MyException[] exception = new MyException[1]; |
| |
| FormEditingUtil.iterate( |
| _rootContainer, |
| new FormEditingUtil.ComponentVisitor<LwComponent>() { |
| public boolean visit(final LwComponent component) { |
| final String binding = component.getBinding(); |
| if (binding == null) { |
| return true; |
| } |
| |
| final PsiField[] fields = boundClass.getFields(); |
| PsiField field = null; |
| for(int i = fields.length - 1; i >=0 ; i--){ |
| if(binding.equals(fields[i].getName())){ |
| field = fields[i]; |
| break; |
| } |
| } |
| if(field == null){ |
| exception[0] = new MyException(UIDesignerBundle.message("error.field.not.found.in.class", binding, classToBind)); |
| return false; |
| } |
| |
| final PsiClass fieldClass = getClassByType(field.getType()); |
| if (fieldClass == null) { |
| exception[0] = new MyException(UIDesignerBundle.message("error.invalid.binding.field.type", binding, classToBind)); |
| return false; |
| } |
| |
| if (instanceOf(fieldClass, JTextComponent.class.getName())) { |
| result.add(new FormProperty(component, "getText", "setText", String.class.getName())); |
| } |
| else if (instanceOf(fieldClass, JCheckBox.class.getName())) { |
| result.add(new FormProperty(component, "isSelected", "setSelected", boolean.class.getName())); |
| } |
| |
| return true; |
| } |
| } |
| ); |
| |
| if (exception[0] != null) { |
| throw exception[0]; |
| } |
| |
| return result.toArray(new FormProperty[result.size()]); |
| } |
| |
| private static PsiClass getClassByType(final PsiType type) { |
| if (!(type instanceof PsiClassType)) { |
| return null; |
| } |
| return ((PsiClassType)type).resolve(); |
| } |
| |
| private static boolean instanceOf(final PsiClass jComponentClass, final String baseClassName) { |
| for (PsiClass c = jComponentClass; c != null; c = c.getSuperClass()){ |
| if (baseClassName.equals(c.getQualifiedName())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Should be invoked in command and write action |
| */ |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| public static void generateDataBindingMethods(final WizardData data) throws MyException { |
| if (data.myBindToNewBean) { |
| data.myBeanClass = createBeanClass(data); |
| } |
| else { |
| if (!CommonRefactoringUtil.checkReadOnlyStatus(data.myBeanClass.getProject(), data.myBeanClass)) { |
| return; |
| } |
| } |
| |
| final HashMap<String, String> binding2beanGetter = new HashMap<String, String>(); |
| final HashMap<String, String> binding2beanSetter = new HashMap<String, String>(); |
| |
| final FormProperty2BeanProperty[] bindings = data.myBindings; |
| for (final FormProperty2BeanProperty form2bean : bindings) { |
| if (form2bean == null || form2bean.myBeanProperty == null) { |
| continue; |
| } |
| |
| // check that bean contains the property, and if not, try to add the property to the bean |
| { |
| final String setterName = PropertyUtil.suggestSetterName(form2bean.myBeanProperty.myName); |
| final PsiMethod[] methodsByName = data.myBeanClass.findMethodsByName(setterName, true); |
| if (methodsByName.length < 1) { |
| // bean does not contain this property |
| // try to add... |
| |
| LOG.assertTrue(!data.myBindToNewBean); // just generated bean class should contain all necessary properties |
| |
| if (!data.myBeanClass.isWritable()) { |
| throw new MyException("Cannot add property to non writable class " + data.myBeanClass.getQualifiedName()); |
| } |
| |
| final StringBuffer membersBuffer = new StringBuffer(); |
| final StringBuffer methodsBuffer = new StringBuffer(); |
| |
| final Project project = data.myBeanClass.getProject(); |
| final CodeStyleManager formatter = CodeStyleManager.getInstance(project); |
| final JavaCodeStyleManager styler = JavaCodeStyleManager.getInstance(project); |
| |
| generateProperty(styler, form2bean.myBeanProperty.myName, form2bean.myBeanProperty.myType, membersBuffer, |
| methodsBuffer); |
| |
| final PsiClass fakeClass; |
| try { |
| fakeClass = JavaPsiFacade.getInstance(data.myBeanClass.getProject()).getElementFactory() |
| .createClassFromText(membersBuffer.toString() + methodsBuffer.toString(), null); |
| |
| final PsiField[] fields = fakeClass.getFields(); |
| { |
| final PsiElement result = data.myBeanClass.add(fields[0]); |
| styler.shortenClassReferences(result); |
| formatter.reformat(result); |
| } |
| |
| final PsiMethod[] methods = fakeClass.getMethods(); |
| { |
| final PsiElement result = data.myBeanClass.add(methods[0]); |
| styler.shortenClassReferences(result); |
| formatter.reformat(result); |
| } |
| { |
| final PsiElement result = data.myBeanClass.add(methods[1]); |
| styler.shortenClassReferences(result); |
| formatter.reformat(result); |
| } |
| } |
| catch (IncorrectOperationException e) { |
| throw new MyException(e.getMessage()); |
| } |
| } |
| } |
| |
| final PsiMethod propertySetter = PropertyUtil.findPropertySetter(data.myBeanClass, form2bean.myBeanProperty.myName, false, true); |
| final PsiMethod propertyGetter = PropertyUtil.findPropertyGetter(data.myBeanClass, form2bean.myBeanProperty.myName, false, true); |
| |
| if (propertyGetter == null) { |
| // todo |
| continue; |
| } |
| if (propertySetter == null) { |
| // todo |
| continue; |
| } |
| |
| final String binding = form2bean.myFormProperty.getLwComponent().getBinding(); |
| binding2beanGetter.put(binding, propertyGetter.getName()); |
| binding2beanSetter.put(binding, propertySetter.getName()); |
| } |
| |
| final String dataBeanClassName = data.myBeanClass.getQualifiedName(); |
| |
| final LwRootContainer[] rootContainer = new LwRootContainer[1]; |
| final FormProperty[] formProperties = exposeForm(data.myProject, data.myFormFile, rootContainer); |
| |
| final StringBuffer getDataBody = new StringBuffer(); |
| final StringBuffer setDataBody = new StringBuffer(); |
| final StringBuffer isModifiedBody = new StringBuffer(); |
| |
| // iterate exposed formproperties |
| |
| for (final FormProperty formProperty : formProperties) { |
| final String binding = formProperty.getLwComponent().getBinding(); |
| if (!binding2beanGetter.containsKey(binding)) { |
| continue; |
| } |
| |
| getDataBody.append("data."); |
| getDataBody.append(binding2beanSetter.get(binding)); |
| getDataBody.append("("); |
| getDataBody.append(binding); |
| getDataBody.append("."); |
| getDataBody.append(formProperty.getComponentPropertyGetterName()); |
| getDataBody.append("());\n"); |
| |
| setDataBody.append(binding); |
| setDataBody.append("."); |
| setDataBody.append(formProperty.getComponentPropertySetterName()); |
| setDataBody.append("(data."); |
| setDataBody.append(binding2beanGetter.get(binding)); |
| setDataBody.append("());\n"); |
| |
| final String propertyClassName = formProperty.getComponentPropertyClassName(); |
| if ("boolean".equals(propertyClassName)) { |
| isModifiedBody.append("if ("); |
| // |
| isModifiedBody.append(binding); |
| isModifiedBody.append("."); |
| isModifiedBody.append(formProperty.getComponentPropertyGetterName()); |
| isModifiedBody.append("()"); |
| // |
| isModifiedBody.append("!= "); |
| // |
| isModifiedBody.append("data."); |
| isModifiedBody.append(binding2beanGetter.get(binding)); |
| isModifiedBody.append("()"); |
| // |
| isModifiedBody.append(") return true;\n"); |
| } |
| else { |
| isModifiedBody.append("if ("); |
| // |
| isModifiedBody.append(binding); |
| isModifiedBody.append("."); |
| isModifiedBody.append(formProperty.getComponentPropertyGetterName()); |
| isModifiedBody.append("()"); |
| // |
| isModifiedBody.append("!= null ? "); |
| // |
| isModifiedBody.append("!"); |
| // |
| isModifiedBody.append(binding); |
| isModifiedBody.append("."); |
| isModifiedBody.append(formProperty.getComponentPropertyGetterName()); |
| isModifiedBody.append("()"); |
| // |
| isModifiedBody.append(".equals("); |
| // |
| isModifiedBody.append("data."); |
| isModifiedBody.append(binding2beanGetter.get(binding)); |
| isModifiedBody.append("()"); |
| isModifiedBody.append(") : "); |
| // |
| isModifiedBody.append("data."); |
| isModifiedBody.append(binding2beanGetter.get(binding)); |
| isModifiedBody.append("()"); |
| isModifiedBody.append("!= null"); |
| // |
| isModifiedBody.append(") return true;\n"); |
| } |
| } |
| isModifiedBody.append("return false;\n"); |
| |
| final String textOfMethods = |
| "public void setData(" + dataBeanClassName + " data){\n" + |
| setDataBody.toString() + |
| "}\n" + |
| "\n" + |
| "public void getData(" + dataBeanClassName + " data){\n" + |
| getDataBody.toString() + |
| "}\n" + |
| "\n" + |
| "public boolean isModified(" + dataBeanClassName + " data){\n" + |
| isModifiedBody.toString() + |
| "}\n"; |
| |
| // put them to the bound class |
| |
| final Module module = ModuleUtil.findModuleForFile(data.myFormFile, data.myProject); |
| LOG.assertTrue(module != null); |
| final PsiClass boundClass = FormEditingUtil.findClassToBind(module, rootContainer[0].getClassToBind()); |
| LOG.assertTrue(boundClass != null); |
| |
| if (!CommonRefactoringUtil.checkReadOnlyStatus(module.getProject(), boundClass)) { |
| return; |
| } |
| |
| // todo: check that this method does not exist yet |
| |
| final PsiClass fakeClass; |
| try { |
| fakeClass = JavaPsiFacade.getInstance(data.myProject).getElementFactory().createClassFromText(textOfMethods, null); |
| |
| final PsiMethod methodSetData = fakeClass.getMethods()[0]; |
| final PsiMethod methodGetData = fakeClass.getMethods()[1]; |
| final PsiMethod methodIsModified = fakeClass.getMethods()[2]; |
| |
| final PsiMethod existing1 = boundClass.findMethodBySignature(methodSetData, false); |
| final PsiMethod existing2 = boundClass.findMethodBySignature(methodGetData, false); |
| final PsiMethod existing3 = boundClass.findMethodBySignature(methodIsModified, false); |
| |
| // warning already shown |
| if (existing1 != null) { |
| existing1.delete(); |
| } |
| if (existing2 != null) { |
| existing2.delete(); |
| } |
| if (existing3 != null) { |
| existing3.delete(); |
| } |
| |
| final CodeStyleManager formatter = CodeStyleManager.getInstance(module.getProject()); |
| final JavaCodeStyleManager styler = JavaCodeStyleManager.getInstance(module.getProject()); |
| |
| final PsiElement setData = boundClass.add(methodSetData); |
| styler.shortenClassReferences(setData); |
| formatter.reformat(setData); |
| |
| final PsiElement getData = boundClass.add(methodGetData); |
| styler.shortenClassReferences(getData); |
| formatter.reformat(getData); |
| |
| if (data.myGenerateIsModified) { |
| final PsiElement isModified = boundClass.add(methodIsModified); |
| styler.shortenClassReferences(isModified); |
| formatter.reformat(isModified); |
| } |
| |
| final OpenFileDescriptor descriptor = new OpenFileDescriptor(setData.getProject(), setData.getContainingFile().getVirtualFile(), setData.getTextOffset()); |
| FileEditorManager.getInstance(data.myProject).openTextEditor(descriptor, true); |
| } |
| catch (IncorrectOperationException e) { |
| throw new MyException(e.getMessage()); |
| } |
| } |
| |
| @NotNull |
| private static PsiClass createBeanClass(final WizardData wizardData) throws MyException { |
| final PsiManager psiManager = PsiManager.getInstance(wizardData.myProject); |
| |
| final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(wizardData.myProject); |
| final ProjectFileIndex fileIndex = projectRootManager.getFileIndex(); |
| final VirtualFile sourceRoot = fileIndex.getSourceRootForFile(wizardData.myFormFile); |
| if (sourceRoot == null) { |
| throw new MyException(UIDesignerBundle.message("error.form.file.is.not.in.source.root")); |
| } |
| |
| final PsiDirectory rootDirectory = psiManager.findDirectory(sourceRoot); |
| LOG.assertTrue(rootDirectory != null); |
| |
| final PsiPackage aPackage = JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(wizardData.myPackageName); |
| if (aPackage == null) { |
| throw new MyException(UIDesignerBundle.message("error.package.does.not.exist", wizardData.myPackageName)); |
| } |
| |
| PsiDirectory targetDir = null; |
| |
| final PsiDirectory[] directories = aPackage.getDirectories(); |
| for (final PsiDirectory psiDirectory : directories) { |
| if (PsiTreeUtil.isAncestor(rootDirectory, psiDirectory, false)) { |
| targetDir = psiDirectory; |
| break; |
| } |
| } |
| |
| if (targetDir == null) { |
| // todo |
| throw new MyException(UIDesignerBundle.message("error.cannot.find.package", wizardData.myPackageName)); |
| } |
| |
| //noinspection HardCodedStringLiteral |
| final String body = |
| "public class " + wizardData.myShortClassName + "{\n" + |
| "public " + wizardData.myShortClassName + "(){}\n" + |
| "}"; |
| |
| try { |
| PsiFile sourceFile = |
| PsiFileFactory.getInstance(psiManager.getProject()).createFileFromText(wizardData.myShortClassName + ".java", body); |
| sourceFile = (PsiFile)targetDir.add(sourceFile); |
| |
| final PsiClass beanClass = ((PsiJavaFile)sourceFile).getClasses()[0]; |
| |
| final ArrayList<String> properties = new ArrayList<String>(); |
| final HashMap<String, String> property2fqClassName = new HashMap<String, String>(); |
| |
| final FormProperty2BeanProperty[] bindings = wizardData.myBindings; |
| for (final FormProperty2BeanProperty binding : bindings) { |
| if (binding == null || binding.myBeanProperty == null) { |
| continue; |
| } |
| |
| properties.add(binding.myBeanProperty.myName); |
| |
| // todo: handle "casts" ? |
| |
| final String propertyClassName = binding.myFormProperty.getComponentPropertyClassName(); |
| |
| property2fqClassName.put(binding.myBeanProperty.myName, propertyClassName); |
| } |
| |
| generateBean(beanClass, ArrayUtil.toStringArray(properties), property2fqClassName); |
| |
| return beanClass; |
| } |
| catch (IncorrectOperationException e) { |
| throw new MyException(e.getMessage()); |
| } |
| } |
| |
| // todo: inline |
| private static void generateBean( |
| final PsiClass aClass, |
| final String[] properties, |
| final HashMap<String, String> property2fqClassName |
| ) throws MyException { |
| final StringBuffer membersBuffer = new StringBuffer(); |
| final StringBuffer methodsBuffer = new StringBuffer(); |
| |
| final CodeStyleManager formatter = CodeStyleManager.getInstance(aClass.getProject()); |
| final JavaCodeStyleManager styler = JavaCodeStyleManager.getInstance(aClass.getProject()); |
| |
| for (final String property : properties) { |
| LOG.assertTrue(property != null); |
| final String type = property2fqClassName.get(property); |
| LOG.assertTrue(type != null); |
| |
| generateProperty(styler, property, type, membersBuffer, methodsBuffer); |
| } |
| |
| final PsiClass fakeClass; |
| try { |
| fakeClass = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createClassFromText( |
| membersBuffer.toString() + methodsBuffer.toString(), |
| null |
| ); |
| |
| final PsiField[] fields = fakeClass.getFields(); |
| for (final PsiField field : fields) { |
| aClass.add(field); |
| } |
| |
| final PsiMethod[] methods = fakeClass.getMethods(); |
| for (final PsiMethod method : methods) { |
| aClass.add(method); |
| } |
| |
| styler.shortenClassReferences(aClass); |
| formatter.reformat(aClass); |
| } |
| catch (IncorrectOperationException e) { |
| throw new MyException(e.getMessage()); |
| } |
| } |
| |
| private static void generateProperty(final JavaCodeStyleManager codeStyleManager, |
| final String property, |
| final String type, |
| @NonNls final StringBuffer membersBuffer, @NonNls final StringBuffer methodsBuffer) { |
| final String field = codeStyleManager.suggestVariableName(VariableKind.FIELD, property, null, null).names[0]; |
| |
| membersBuffer.append("private "); |
| membersBuffer.append(type); |
| membersBuffer.append(" "); |
| membersBuffer.append(field); |
| membersBuffer.append(";\n"); |
| |
| // getter |
| methodsBuffer.append("public "); |
| methodsBuffer.append(type); |
| methodsBuffer.append(" "); |
| methodsBuffer.append(suggestGetterName(property, type)); |
| methodsBuffer.append("(){\n"); |
| methodsBuffer.append("return "); |
| methodsBuffer.append(field); |
| methodsBuffer.append(";}\n"); |
| |
| // setter |
| final String parameterName = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, property, null, null).names[0]; |
| methodsBuffer.append("public void "); |
| methodsBuffer.append(PropertyUtil.suggestSetterName(property)); |
| methodsBuffer.append("(final "); |
| methodsBuffer.append(type); |
| methodsBuffer.append(" "); |
| methodsBuffer.append(parameterName); |
| methodsBuffer.append("){\n"); |
| if (parameterName.equals(field)) { |
| methodsBuffer.append("this."); |
| } |
| methodsBuffer.append(field); |
| methodsBuffer.append("="); |
| methodsBuffer.append(parameterName); |
| methodsBuffer.append(";}\n"); |
| } |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| private static String suggestGetterName(final String propertyName, final String propertyType) { |
| final StringBuffer name = new StringBuffer(StringUtil.capitalize(propertyName)); |
| if ("boolean".equals(propertyType)) { |
| name.insert(0, "is"); |
| } |
| else { |
| name.insert(0, "get"); |
| } |
| return name.toString(); |
| } |
| |
| public static void prepareWizardData(final WizardData data, PsiClass boundClass) throws MyException { |
| |
| final PsiMethod[] allGetDataMethods = boundClass.findMethodsByName("getData", false); |
| final PsiMethod[] allSetDataMethods = boundClass.findMethodsByName("setData", false); |
| |
| PsiMethod setDataMethod = null; |
| PsiClass beanClass = null; |
| |
| // find get/set pair and bean class |
| outer: for (int i = 0; i < allGetDataMethods.length; i++) { |
| final PsiMethod _getMethod = allGetDataMethods[i]; |
| |
| if (_getMethod.getReturnType() != PsiType.VOID) { |
| continue; |
| } |
| |
| final PsiParameter[] _getMethodParameters = _getMethod.getParameterList().getParameters(); |
| if (_getMethodParameters.length != 1) { |
| continue; |
| } |
| |
| final PsiClass _getParameterClass = getClassByType(_getMethodParameters[0].getType()); |
| if (_getParameterClass == null) { |
| continue; |
| } |
| |
| for (final PsiMethod _setMethod : allSetDataMethods) { |
| if (_setMethod.getReturnType() != PsiType.VOID) { |
| continue; |
| } |
| |
| final PsiParameter[] _setMethodParameters = _setMethod.getParameterList().getParameters(); |
| if (_setMethodParameters.length != 1) { |
| continue; |
| } |
| |
| final PsiClass _setParameterClass = getClassByType(_setMethodParameters[0].getType()); |
| if (_setParameterClass != _getParameterClass) { |
| continue; |
| } |
| |
| // pair found !!! |
| |
| setDataMethod = _setMethod; |
| beanClass = _getParameterClass; |
| break outer; |
| } |
| } |
| |
| if (beanClass == null) { |
| // nothing found |
| return; |
| } |
| |
| data.myBindToNewBean = false; |
| data.myBeanClass = beanClass; |
| |
| // parse setData() and try to associate fields with bean |
| { |
| final PsiCodeBlock body = setDataMethod.getBody(); |
| if (body == null) { |
| return; |
| } |
| |
| final PsiElement[] children = body.getChildren(); |
| for (PsiElement child : children) { |
| // Parses sequences like: a.foo(b.bar()); |
| final PsiField bindingField; |
| |
| if (!(child instanceof PsiExpressionStatement)) { |
| continue; |
| } |
| |
| final PsiExpression expression = ((PsiExpressionStatement)child).getExpression(); |
| if (!(expression instanceof PsiMethodCallExpression)) { |
| continue; |
| } |
| |
| final PsiMethodCallExpression callExpression = (PsiMethodCallExpression)expression; |
| |
| // find binding field ('a') |
| int index = -1; |
| { |
| final PsiElement psiElement = getObjectForWhichMethodWasCalled(callExpression); |
| if (!(psiElement instanceof PsiField)) { |
| continue; |
| } |
| |
| if (((PsiField)psiElement).getContainingClass() != boundClass) { |
| continue; |
| } |
| |
| bindingField = (PsiField)psiElement; |
| |
| // find binding for this field |
| final FormProperty2BeanProperty[] bindings = data.myBindings; |
| for (int j = 0; j < bindings.length; j++) { |
| final FormProperty2BeanProperty binding = bindings[j]; |
| if (bindingField.getName().equals(binding.myFormProperty.getLwComponent().getBinding())) { |
| index = j; |
| break; |
| } |
| } |
| } |
| |
| if (index == -1) { |
| continue; |
| } |
| |
| // find 'bar()' |
| { |
| final PsiReferenceParameterList parameterList = callExpression.getMethodExpression().getParameterList(); |
| if (parameterList == null) { |
| continue; |
| } |
| |
| final PsiExpressionList argumentList = callExpression.getArgumentList(); |
| if (argumentList == null) { |
| continue; |
| } |
| |
| final PsiExpression[] expressions = argumentList.getExpressions(); |
| if (expressions == null || expressions.length != 1) { |
| continue; |
| } |
| |
| if (!(expressions[0]instanceof PsiMethodCallExpression)) { |
| continue; |
| } |
| |
| final PsiMethodCallExpression callExpression2 = ((PsiMethodCallExpression)expressions[0]); |
| |
| // check that 'b' is parameter |
| final PsiElement psiElement = getObjectForWhichMethodWasCalled(callExpression2); |
| if (!(psiElement instanceof PsiParameter)) { |
| continue; |
| } |
| |
| final PsiMethod barMethod = ((PsiMethod)callExpression2.getMethodExpression().resolve()); |
| if (barMethod == null) { |
| continue; |
| } |
| |
| if (!PropertyUtil.isSimplePropertyGetter(barMethod)) { |
| continue; |
| } |
| |
| final String propertyName = PropertyUtil.getPropertyName(barMethod); |
| |
| // There are two possible types: boolean and java.lang.String |
| String typeName = barMethod.getReturnType().getCanonicalText(); |
| if(!"boolean".equals(typeName) && !"java.lang.String".equals(typeName)){ |
| continue; |
| } |
| |
| data.myBindings[index].myBeanProperty = new BeanProperty(propertyName, typeName); |
| } |
| } |
| } |
| } |
| |
| private static PsiElement getObjectForWhichMethodWasCalled(final PsiMethodCallExpression callExpression) { |
| final PsiExpression qualifierExpression = callExpression.getMethodExpression().getQualifierExpression(); |
| if (!(qualifierExpression instanceof PsiReferenceExpression)) { |
| return null; |
| } |
| return ((PsiReferenceExpression)qualifierExpression).resolve(); |
| } |
| |
| public static final class MyException extends Exception{ |
| public MyException(final String message) { |
| super(message); |
| } |
| } |
| } |