| /* |
| * 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.compiler; |
| |
| import com.intellij.compiler.instrumentation.InstrumentationClassFinder; |
| import com.intellij.uiDesigner.core.SupportCode; |
| import com.intellij.uiDesigner.lw.LwComponent; |
| import com.intellij.uiDesigner.lw.LwIntrospectedProperty; |
| import com.intellij.uiDesigner.lw.StringDescriptor; |
| import org.jetbrains.org.objectweb.asm.Label; |
| import org.jetbrains.org.objectweb.asm.MethodVisitor; |
| import org.jetbrains.org.objectweb.asm.Opcodes; |
| import org.jetbrains.org.objectweb.asm.Type; |
| import org.jetbrains.org.objectweb.asm.commons.GeneratorAdapter; |
| import org.jetbrains.org.objectweb.asm.commons.Method; |
| |
| import javax.swing.*; |
| import java.io.IOException; |
| import java.util.HashSet; |
| import java.util.ResourceBundle; |
| import java.util.Set; |
| |
| /** |
| * @author yole |
| */ |
| public class StringPropertyCodeGenerator extends PropertyCodeGenerator implements Opcodes { |
| private static final Type myResourceBundleType = Type.getType(ResourceBundle.class); |
| private final Method myGetBundleMethod = Method.getMethod("java.util.ResourceBundle getBundle(java.lang.String)"); |
| private final Method myGetStringMethod = Method.getMethod("java.lang.String getString(java.lang.String)"); |
| private static final Method myLoadLabelTextMethod = new Method(AsmCodeGenerator.LOAD_LABEL_TEXT_METHOD, Type.VOID_TYPE, |
| new Type[] { Type.getType(JLabel.class), Type.getType(String.class) } ); |
| private static final Method myLoadButtonTextMethod = new Method(AsmCodeGenerator.LOAD_BUTTON_TEXT_METHOD, Type.VOID_TYPE, |
| new Type[] { Type.getType(AbstractButton.class), Type.getType(String.class) } ); |
| |
| private final Set myClassesRequiringLoadLabelText = new HashSet(); |
| private final Set myClassesRequiringLoadButtonText = new HashSet(); |
| private boolean myHaveSetDisplayedMnemonicIndex = false; |
| |
| public void generateClassStart(AsmCodeGenerator.FormClassVisitor visitor, final String name, final InstrumentationClassFinder classFinder) { |
| myClassesRequiringLoadLabelText.remove(name); |
| myClassesRequiringLoadButtonText.remove(name); |
| try { |
| InstrumentationClassFinder.PseudoClass pseudo = classFinder.loadClass(AbstractButton.class.getName()); |
| if (!pseudo.findMethods("getDisplayedMnemonicIndex").isEmpty()) { |
| myHaveSetDisplayedMnemonicIndex = true; |
| } |
| } |
| catch (Exception e) { |
| // ignore |
| } |
| } |
| |
| public boolean generateCustomSetValue(final LwComponent lwComponent, |
| final InstrumentationClassFinder.PseudoClass componentClass, |
| final LwIntrospectedProperty property, |
| final GeneratorAdapter generator, |
| final int componentLocal, |
| final String formClassName) throws IOException, ClassNotFoundException { |
| final InstrumentationClassFinder.PseudoClass abstractButtonClass = componentClass.getFinder().loadClass(AbstractButton.class.getName()); |
| final InstrumentationClassFinder.PseudoClass jLabelClass = componentClass.getFinder().loadClass(JLabel.class.getName()); |
| if ("text".equals(property.getName()) && |
| (abstractButtonClass.isAssignableFrom(componentClass) || jLabelClass.isAssignableFrom(componentClass))) { |
| final StringDescriptor propertyValue = (StringDescriptor)lwComponent.getPropertyValue(property); |
| if (propertyValue.getValue() != null) { |
| final SupportCode.TextWithMnemonic textWithMnemonic = SupportCode.parseText(propertyValue.getValue()); |
| if (textWithMnemonic.myMnemonicIndex >= 0) { |
| generator.loadLocal(componentLocal); |
| generator.push(textWithMnemonic.myText); |
| generator.invokeVirtual(Type.getType(componentClass.getDescriptor()), |
| new Method(property.getWriteMethodName(), |
| Type.VOID_TYPE, new Type[] { Type.getType(String.class) } )); |
| |
| String setMnemonicMethodName; |
| if (abstractButtonClass.isAssignableFrom(componentClass)) { |
| setMnemonicMethodName = "setMnemonic"; |
| } |
| else { |
| setMnemonicMethodName = "setDisplayedMnemonic"; |
| } |
| |
| generator.loadLocal(componentLocal); |
| generator.push(textWithMnemonic.getMnemonicChar()); |
| generator.invokeVirtual(Type.getType(componentClass.getDescriptor()), |
| new Method(setMnemonicMethodName, |
| Type.VOID_TYPE, new Type[] { Type.CHAR_TYPE } )); |
| |
| if (myHaveSetDisplayedMnemonicIndex) { |
| generator.loadLocal(componentLocal); |
| generator.push(textWithMnemonic.myMnemonicIndex); |
| generator.invokeVirtual(Type.getType(componentClass.getDescriptor()), |
| new Method("setDisplayedMnemonicIndex", |
| Type.VOID_TYPE, new Type[] { Type.INT_TYPE } )); |
| } |
| return true; |
| } |
| } |
| else { |
| Method method; |
| if (abstractButtonClass.isAssignableFrom(componentClass)) { |
| myClassesRequiringLoadButtonText.add(formClassName); |
| method = myLoadButtonTextMethod; |
| } |
| else { |
| myClassesRequiringLoadLabelText.add(formClassName); |
| method = myLoadLabelTextMethod; |
| } |
| |
| generator.loadThis(); |
| generator.loadLocal(componentLocal); |
| generator.push(propertyValue.getBundleName()); |
| generator.invokeStatic(myResourceBundleType, myGetBundleMethod); |
| generator.push(propertyValue.getKey()); |
| generator.invokeVirtual(myResourceBundleType, myGetStringMethod); |
| generator.invokeVirtual(Type.getType("L" + formClassName + ";"), method); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public void generatePushValue(final GeneratorAdapter generator, final Object value) { |
| StringDescriptor descriptor = (StringDescriptor) value; |
| if (descriptor == null) { |
| generator.push((String)null); |
| } |
| else if (descriptor.getValue() !=null) { |
| generator.push(descriptor.getValue()); |
| } |
| else { |
| generator.push(descriptor.getBundleName()); |
| generator.invokeStatic(myResourceBundleType, myGetBundleMethod); |
| generator.push(descriptor.getKey()); |
| generator.invokeVirtual(myResourceBundleType, myGetStringMethod); |
| } |
| } |
| |
| public void generateClassEnd(AsmCodeGenerator.FormClassVisitor visitor) { |
| if (myClassesRequiringLoadLabelText.contains(visitor.getClassName())) { |
| generateLoadTextMethod(visitor, AsmCodeGenerator.LOAD_LABEL_TEXT_METHOD, "javax/swing/JLabel", "setDisplayedMnemonic"); |
| myClassesRequiringLoadLabelText.remove(visitor.getClassName()); |
| } |
| if (myClassesRequiringLoadButtonText.contains(visitor.getClassName())) { |
| generateLoadTextMethod(visitor, AsmCodeGenerator.LOAD_BUTTON_TEXT_METHOD, "javax/swing/AbstractButton", "setMnemonic"); |
| myClassesRequiringLoadButtonText.remove(visitor.getClassName()); |
| } |
| } |
| |
| private void generateLoadTextMethod(final AsmCodeGenerator.FormClassVisitor visitor, final String methodName, final String componentClass, |
| final String setMnemonicMethodName) { |
| MethodVisitor mv = visitor.visitNewMethod(ACC_PRIVATE | ACC_SYNTHETIC, methodName, "(L" + componentClass + ";Ljava/lang/String;)V", null, null); |
| mv.visitCode(); |
| mv.visitTypeInsn(NEW, "java/lang/StringBuffer"); |
| mv.visitInsn(DUP); |
| mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V", false); |
| mv.visitVarInsn(ASTORE, 3); |
| mv.visitInsn(ICONST_0); |
| mv.visitVarInsn(ISTORE, 4); |
| mv.visitInsn(ICONST_0); |
| mv.visitVarInsn(ISTORE, 5); |
| mv.visitInsn(ICONST_M1); |
| mv.visitVarInsn(ISTORE, 6); |
| mv.visitInsn(ICONST_0); |
| mv.visitVarInsn(ISTORE, 7); |
| Label l0 = new Label(); |
| mv.visitLabel(l0); |
| mv.visitVarInsn(ILOAD, 7); |
| mv.visitVarInsn(ALOAD, 2); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "length", "()I", false); |
| Label l1 = new Label(); |
| mv.visitJumpInsn(IF_ICMPGE, l1); |
| mv.visitVarInsn(ALOAD, 2); |
| mv.visitVarInsn(ILOAD, 7); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); |
| mv.visitIntInsn(BIPUSH, 38); |
| Label l2 = new Label(); |
| mv.visitJumpInsn(IF_ICMPNE, l2); |
| mv.visitIincInsn(7, 1); |
| mv.visitVarInsn(ILOAD, 7); |
| mv.visitVarInsn(ALOAD, 2); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "length", "()I", false); |
| Label l3 = new Label(); |
| mv.visitJumpInsn(IF_ICMPNE, l3); |
| mv.visitJumpInsn(GOTO, l1); |
| mv.visitLabel(l3); |
| mv.visitVarInsn(ILOAD, 4); |
| mv.visitJumpInsn(IFNE, l2); |
| mv.visitVarInsn(ALOAD, 2); |
| mv.visitVarInsn(ILOAD, 7); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); |
| mv.visitIntInsn(BIPUSH, 38); |
| mv.visitJumpInsn(IF_ICMPEQ, l2); |
| mv.visitInsn(ICONST_1); |
| mv.visitVarInsn(ISTORE, 4); |
| mv.visitVarInsn(ALOAD, 2); |
| mv.visitVarInsn(ILOAD, 7); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); |
| mv.visitVarInsn(ISTORE, 5); |
| mv.visitVarInsn(ALOAD, 3); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "length", "()I", false); |
| mv.visitVarInsn(ISTORE, 6); |
| mv.visitLabel(l2); |
| mv.visitVarInsn(ALOAD, 3); |
| mv.visitVarInsn(ALOAD, 2); |
| mv.visitVarInsn(ILOAD, 7); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(C)Ljava/lang/StringBuffer;", false); |
| mv.visitInsn(POP); |
| mv.visitIincInsn(7, 1); |
| mv.visitJumpInsn(GOTO, l0); |
| mv.visitLabel(l1); |
| mv.visitVarInsn(ALOAD, 1); |
| mv.visitVarInsn(ALOAD, 3); |
| mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;", false); |
| mv.visitMethodInsn(INVOKEVIRTUAL, componentClass, "setText", "(Ljava/lang/String;)V", false); |
| mv.visitVarInsn(ILOAD, 4); |
| Label l4 = new Label(); |
| mv.visitJumpInsn(IFEQ, l4); |
| mv.visitVarInsn(ALOAD, 1); |
| mv.visitVarInsn(ILOAD, 5); |
| mv.visitMethodInsn(INVOKEVIRTUAL, componentClass, setMnemonicMethodName, "(C)V", false); |
| if (myHaveSetDisplayedMnemonicIndex) { |
| mv.visitVarInsn(ALOAD, 1); |
| mv.visitVarInsn(ILOAD, 6); |
| mv.visitMethodInsn(INVOKEVIRTUAL, componentClass, "setDisplayedMnemonicIndex", "(I)V", false); |
| } |
| mv.visitLabel(l4); |
| mv.visitInsn(RETURN); |
| mv.visitMaxs(3, 8); |
| mv.visitEnd(); |
| } |
| } |