diff --git a/README.md b/README.md index e971be6..971d026 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ private StringProperty name; public StringProperty getName() { return name; } -public void setName( StringProperty name ) { + +public void setName(StringProperty name) { this.name = name; } ``` @@ -24,11 +25,11 @@ public final String getName() { return name.get(); } -public final void setName( String value ) { +public final void setName(String value) { name.set(value); } -public final StringProperty nameProperty() { +public StringProperty nameProperty() { return name; } ``` @@ -38,19 +39,46 @@ which will create the following methods: ```java private StringProperty nameProperty; + public final String getName() { return nameProperty.get(); } -public final void setName( String value ) { +public final void setName(String value) { nameProperty.set(value); } -public final StringProperty nameProperty() { +public StringProperty nameProperty() { return nameProperty; } ``` +Read-only properties and read-only wrapper types are also supported: + +```java +private ReadOnlyStringProperty identifier; + +public final String getIdentifier() { + return identifier.get(); +} + +public ReadOnlyStringProperty identifierProperty() { + return identifier; +} +``` + +```java +private ReadOnlyStringWrapper identifier; + +public final String getIdentifier() { + return identifier.get(); +} + +public ReadOnlyStringProperty identifierProperty() { + return identifier.getReadOnlyProperty(); +} +``` + # Usage @@ -71,12 +99,35 @@ Methods for supported property types will automatically be generated. * FloatProperty * IntegerProperty * LongProperty - - - -### Unsupported Property Types * ListProperty * MapProperty * ObjectProperty * SetProperty + + +### Supported Read-only Property Types +* ReadOnlyStringProperty +* ReadOnlyBooleanProperty +* ReadOnlyDoubleProperty +* ReadOnlyFloatProperty +* ReadOnlyIntegerProperty +* ReadOnlyLongProperty +* ReadOnlyListProperty +* ReadOnlyMapProperty +* ReadOnlyObjectProperty +* ReadOnlySetProperty + + + +### Supported Read-only Wrapper Types +* ReadOnlyStringWrapper +* ReadOnlyBooleanWrapper +* ReadOnlyDoubleWrapper +* ReadOnlyFloatWrapper +* ReadOnlyIntegerWrapper +* ReadOnlyLongWrapper +* ReadOnlyListWrapper +* ReadOnlyMapWrapper +* ReadOnlyObjectWrapper +* ReadOnlySetWrapper diff --git a/nb-configuration.xml b/nb-configuration.xml deleted file mode 100644 index a65c451..0000000 --- a/nb-configuration.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - JDK_1.8 - - diff --git a/pom.xml b/pom.xml index be46058..12db3d5 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ Rob Terpilowski MIT License LICENSE - mykeystore + mykeystore myself @@ -61,47 +61,52 @@ org.netbeans.api org-netbeans-api-annotations-common - RELEASE802 + RELEASE81 org.netbeans.api org-netbeans-modules-editor-lib2 - RELEASE802 + RELEASE81 org.netbeans.api org-netbeans-modules-editor-mimelookup - RELEASE802 + RELEASE81 org.netbeans.api org-openide-util-lookup - RELEASE802 + RELEASE81 org.netbeans.api org-netbeans-libs-javacapi - RELEASE802 + RELEASE81 org.netbeans.api org-netbeans-modules-java-source - RELEASE802 + RELEASE81 org.netbeans.api org-openide-util - RELEASE802 + RELEASE81 org.netbeans.api org-netbeans-modules-editor-lib - RELEASE802 + RELEASE81 org.netbeans.api org-netbeans-libs-javafx - RELEASE802 + RELEASE81 + + + org.netbeans.api + org-netbeans-modules-java-source-base + RELEASE81 diff --git a/src/main/java/com/lynden/netbeans/javafx/CodeGeneratorCancellableTask.java b/src/main/java/com/lynden/netbeans/javafx/CodeGeneratorCancellableTask.java index e3922e1..65723b7 100644 --- a/src/main/java/com/lynden/netbeans/javafx/CodeGeneratorCancellableTask.java +++ b/src/main/java/com/lynden/netbeans/javafx/CodeGeneratorCancellableTask.java @@ -1,36 +1,34 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Lynden, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package com.lynden.netbeans.javafx; -/** -The MIT License (MIT) - -Copyright (c) 2015 Lynden, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -**/ - -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; import java.io.IOException; import javax.swing.text.JTextComponent; import org.netbeans.api.java.source.CancellableTask; import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.TreeUtilities; import org.netbeans.api.java.source.WorkingCopy; /** @@ -38,6 +36,7 @@ of this software and associated documentation files (the "Software"), to deal * @author Francesco Illuminati */ abstract class CodeGeneratorCancellableTask implements CancellableTask { + private final JTextComponent textComponent; public CodeGeneratorCancellableTask(JTextComponent textComponent) { @@ -51,17 +50,16 @@ public void run(WorkingCopy workingCopy) throws IOException { generate(workingCopy); } - public abstract void generateCode(WorkingCopy workingCopy, TreePath path, - int position); - private void generate(WorkingCopy wc) throws IOException { - final int caretOffset = textComponent.getCaretPosition(); - TreePath path = wc.getTreeUtilities().pathFor(caretOffset); - path = TreeHelper.getParentElementOfKind(Tree.Kind.CLASS, path); - int idx = TreeHelper.findClassMemberIndex(wc,(ClassTree) path.getLeaf(), caretOffset); - generateCode(wc, path, idx); + TreeUtilities treeUtils = wc.getTreeUtilities(); + + int caretPosition = textComponent.getCaretPosition(); + TreePath treePathAtCaret = treeUtils.pathFor(caretPosition); + generateCode(wc, treePathAtCaret, caretPosition); } + protected abstract void generateCode(WorkingCopy workingCopy, TreePath treePathAtCaret, int caretPosition); + @Override public void cancel() { } diff --git a/src/main/java/com/lynden/netbeans/javafx/JavaFxBeanHelper.java b/src/main/java/com/lynden/netbeans/javafx/JavaFxBeanHelper.java index ce67324..ccd9d6c 100644 --- a/src/main/java/com/lynden/netbeans/javafx/JavaFxBeanHelper.java +++ b/src/main/java/com/lynden/netbeans/javafx/JavaFxBeanHelper.java @@ -1,4 +1,4 @@ -/** +/* * The MIT License (MIT) * * Copyright (c) 2015 Lynden, Inc. @@ -20,19 +20,22 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. -* */ package com.lynden.netbeans.javafx; import com.sun.source.tree.ClassTree; -import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodTree; import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; +import com.sun.source.util.Trees; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; import java.util.List; -import javafx.beans.property.*; +import java.util.Set; +import java.util.stream.Collectors; import javafx.embed.swing.JFXPanel; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; @@ -46,6 +49,7 @@ import org.netbeans.api.java.source.JavaSource; import org.netbeans.api.java.source.ModificationResult; import org.netbeans.api.java.source.TreeMaker; +import org.netbeans.api.java.source.TreeUtilities; import org.netbeans.api.java.source.WorkingCopy; import org.netbeans.spi.editor.codegen.CodeGenerator; import org.netbeans.spi.editor.codegen.CodeGeneratorContextProvider; @@ -54,20 +58,46 @@ public class JavaFxBeanHelper implements CodeGenerator { + private static final Set SUPPORTED_CLASSES = new HashSet<>(); + + static { + SUPPORTED_CLASSES.add("javafx.beans.property.IntegerProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.LongProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.FloatProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.DoubleProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.BooleanProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.StringProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ListProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.SetProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.MapProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ObjectProperty"); + + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyIntegerProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyLongProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyFloatProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyDoubleProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyBooleanProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyStringProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyListProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlySetProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyMapProperty"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyObjectProperty"); + + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyIntegerWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyLongWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyFloatWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyDoubleWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyBooleanWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyStringWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyListWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlySetWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyMapWrapper"); + SUPPORTED_CLASSES.add("javafx.beans.property.ReadOnlyObjectWrapper"); + } + protected JTextComponent textComponent; //this is needed to initialize the JavaFx Toolkit protected JFXPanel panel = new JFXPanel(); - protected List fields; - - public JavaFxBeanHelper textComponent(final JTextComponent value) { - this.textComponent = value; - return this; - } - - public JavaFxBeanHelper fields(final List value) { - this.fields = value; - return this; - } /** * @@ -76,12 +106,6 @@ public JavaFxBeanHelper fields(final List value) { */ private JavaFxBeanHelper(Lookup context) { // Good practice is not to save Lookup outside ctor textComponent = context.lookup(JTextComponent.class); - CompilationController controller = context.lookup(CompilationController.class); - try { - fields = getFields(context, controller); - } catch (CodeGeneratorException ex) { - Exceptions.printStackTrace(ex); - } } @MimeRegistration(mimeType = "text/x-java", position = 250, service = CodeGenerator.Factory.class) @@ -89,7 +113,20 @@ public static class Factory implements CodeGenerator.Factory { @Override public List create(Lookup context) { - return Collections.singletonList(new JavaFxBeanHelper(context)); + CompilationController controller = context.lookup(CompilationController.class); + TreePath path = context.lookup(TreePath.class); + + TreeUtilities treeUtils = controller.getTreeUtilities(); + + TreePath classTreePath = treeUtils.getPathElementOfKind(EnumSet.of(Tree.Kind.CLASS, Tree.Kind.ENUM), path); + + /* Are we in a class and does the class have supported property + * fields? */ + if ((classTreePath != null) && (!getFields(controller, classTreePath).isEmpty())) { + return Collections.singletonList(new JavaFxBeanHelper(context)); + } else { + return Collections.emptyList(); + } } } @@ -112,8 +149,8 @@ public void invoke() { CancellableTask task = new CodeGeneratorCancellableTask(textComponent) { @Override - public void generateCode(WorkingCopy workingCopy, TreePath path, int position) { - JavaFxBeanHelper.this.generateCode(workingCopy, path, position, JavaFxBeanHelper.this.fields); + protected void generateCode(WorkingCopy workingCopy, TreePath treePathAtCaret, int caretPosition) { + JavaFxBeanHelper.this.generateCode(workingCopy, treePathAtCaret, caretPosition); } }; @@ -126,89 +163,60 @@ public void generateCode(WorkingCopy workingCopy, TreePath path, int position) { } - protected void generateCode(WorkingCopy wc, TreePath path, int position, List fields) { + protected void generateCode(WorkingCopy wc, TreePath treePathAtCaret, int caretPosition) { + TreeUtilities treeUtils = wc.getTreeUtilities(); - TypeElement typeClassElement = (TypeElement) wc.getTrees().getElement(path); - if (typeClassElement != null) { - int index = position; + TreePath classTreePath = treeUtils.getPathElementOfKind(EnumSet.of(Tree.Kind.CLASS, Tree.Kind.ENUM), treePathAtCaret); + if (classTreePath != null) { - TreeMaker make = wc.getTreeMaker(); - ClassTree classTree = (ClassTree) path.getLeaf(); - List members = new ArrayList<>(classTree.getMembers()); - String className = typeClassElement.toString(); + int classMemberIndexAtCaret = TreeHelper.findClassMemberIndex(wc, (ClassTree) classTreePath.getLeaf(), caretPosition); - PropertyMethodBuilder propertyMethodBuilder = new PropertyMethodBuilder(make, members, fields, className); + generateCodeInClass(wc, classTreePath, classMemberIndexAtCaret); + } + } - index = propertyMethodBuilder.removeExistingPropMethods(index); + protected void generateCodeInClass(WorkingCopy wc, TreePath classTreePath, int classMemberIndexAtCaret) { - propertyMethodBuilder.addPropMethods(index); + List fields = getFields(wc, classTreePath); - ClassTree newClassTree = make.Class(classTree.getModifiers(), - classTree.getSimpleName(), - classTree.getTypeParameters(), - classTree.getExtendsClause(), - (List) classTree.getImplementsClause(), - members); + TreeMaker make = wc.getTreeMaker(); + ClassTree classTree = (ClassTree) classTreePath.getLeaf(); + List members = new ArrayList<>(classTree.getMembers()); - wc.rewrite(classTree, newClassTree); - } - } + PropertyMethodBuilder propertyMethodBuilder = new PropertyMethodBuilder(make, fields); - private List getFields(Lookup context, CompilationController controller) throws CodeGeneratorException { - try { - List elementList = new ArrayList<>(); - TreePath treePath = context.lookup(TreePath.class); - TreePath path = TreeHelper.getParentElementOfKind(Tree.Kind.CLASS, treePath); - TypeElement typeElement = (TypeElement) controller.getTrees().getElement(path); + List createdMethods = propertyMethodBuilder.createPropMethods(); - if (!typeElement.getKind().isClass()) { - throw new CodeGeneratorException("typeElement " + typeElement.getKind().name() + " is not a class, cannot generate code."); - } + /* Filtering out methods that might clash with the pre-existing ones. */ + createdMethods.removeIf((MethodTree createdMethod) -> { + return TreeHelper.hasMethodWithSameName(members, createdMethod); + }); - Elements elements = controller.getElements(); - List temp = ElementFilter.fieldsIn(elements.getAllMembers(typeElement)); - - for (VariableElement e : temp) { - try { - Class memberClass = Class.forName(getClassName(e.asType().toString())); - if (Property.class.isAssignableFrom(memberClass) && - !ListProperty.class.isAssignableFrom(memberClass) && - !MapProperty.class.isAssignableFrom(memberClass) && - !ObjectProperty.class.isAssignableFrom(memberClass) && - !SetProperty.class.isAssignableFrom(memberClass) ) { - - elementList.add(e); - } - } catch (Exception ex) { - Exceptions.printStackTrace(ex); - } - } - return elementList; - } catch (NullPointerException ex) { - throw new CodeGeneratorException(ex); - } - } - - - protected String getClassName( String fullName ) { - if( !fullName.contains("<") ) { - return fullName; - } else { - return fullName.substring( 0, fullName.indexOf("<") ); - } + members.addAll(classMemberIndexAtCaret, createdMethods); + + ClassTree newClassTree = make.Class( + classTree.getModifiers(), + classTree.getSimpleName(), + classTree.getTypeParameters(), + classTree.getExtendsClause(), + classTree.getImplementsClause(), + members); + + wc.rewrite(classTree, newClassTree); } - private static class CodeGeneratorException extends Exception { + private static List getFields(CompilationController controller, TreePath classTreePath) { + Trees trees = controller.getTrees(); + Elements elements = controller.getElements(); - private static final long serialVersionUID = 1L; + TypeElement typeElement = (TypeElement) trees.getElement(classTreePath); - public CodeGeneratorException(String message) { - super(message); - } + List allFields = ElementFilter.fieldsIn(elements.getAllMembers(typeElement)); - public CodeGeneratorException(Throwable cause) { - super(cause); - } - } + List supportedFields = allFields.stream().filter((VariableElement var) -> { + return SUPPORTED_CLASSES.contains(TypeHelper.getClassName(var.asType().toString())); + }).collect(Collectors.toList()); + return supportedFields; + } } diff --git a/src/main/java/com/lynden/netbeans/javafx/PackageHelper.java b/src/main/java/com/lynden/netbeans/javafx/PackageHelper.java deleted file mode 100644 index 566e9fe..0000000 --- a/src/main/java/com/lynden/netbeans/javafx/PackageHelper.java +++ /dev/null @@ -1,80 +0,0 @@ -/** -The MIT License (MIT) - -Copyright (c) 2015 Lynden, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -**/ - -package com.lynden.netbeans.javafx; - -import java.util.ArrayList; -import java.util.List; - -/** - * Manipulates strings containing types. - * - */ -class PackageHelper { - - /** Removes packages from class names (it manages generics too). - * i.e. - * {@code java.lang.String -> String} - * and - * {@code java.util.List -> List}. - */ - static String removePackagesFromGenericsType(String fullName) { - final List list = new ArrayList<>(); - int idx = 0, counter = 0; - for (char c : fullName.toCharArray()) { - switch (c) { - case ',': - case '<': - case '>': - list.add(fullName.substring(idx, counter)); - list.add(String.valueOf(c)); - idx = counter + 1; - break; - } - counter++; - } - if (list.isEmpty()) { - return removePackageFromType(fullName); - } - StringBuilder buf = new StringBuilder(); - for (String s : list) { - if ("<>,".contains(s)) { - buf.append(s); - } else { - buf.append(removePackageFromType(s)); - } - } - return buf.toString(); - } - - /** Removes the package from a single class name (don't manage generics). */ - static String removePackageFromType(String fullname) { - int lastIndexOfPoint = fullname.lastIndexOf('.'); - if (lastIndexOfPoint == -1) { - return fullname; - } - return fullname.substring(lastIndexOfPoint + 1, fullname.length()); - } - -} diff --git a/src/main/java/com/lynden/netbeans/javafx/PropertyMethodBuilder.java b/src/main/java/com/lynden/netbeans/javafx/PropertyMethodBuilder.java index 1826d61..e93f54b 100644 --- a/src/main/java/com/lynden/netbeans/javafx/PropertyMethodBuilder.java +++ b/src/main/java/com/lynden/netbeans/javafx/PropertyMethodBuilder.java @@ -1,31 +1,33 @@ -/** -The MIT License (MIT) - -Copyright (c) 2015 Lynden, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -**/ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Lynden, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package com.lynden.netbeans.javafx; -import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.BlockTree; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.MethodTree; +import com.sun.source.tree.ModifiersTree; +import com.sun.source.tree.StatementTree; import com.sun.source.tree.Tree; import com.sun.source.tree.TypeParameterTree; import com.sun.source.tree.VariableTree; @@ -34,11 +36,10 @@ of this software and associated documentation files (the "Software"), to deal import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; -import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; import javax.lang.model.element.VariableElement; import org.netbeans.api.java.source.TreeMaker; @@ -47,256 +48,282 @@ of this software and associated documentation files (the "Software"), to deal * */ public class PropertyMethodBuilder { - + private static final String PROPERTY = "Property"; // NOI18N - private static final Map PRIMITIVES_MAP; + + private static final Map VALUE_TYPES = new HashMap<>(); + private static final Map GENERIC_VALUE_TYPES = new HashMap<>(); + private static final Set VALUE_TYPE_AS_PARAM = new HashSet<>(); + + private static final Set WRITABLE_PROPERTIES = new HashSet<>(); + private static final Map WRAPPED_READ_ONLY_TYPES = new HashMap<>(); static { - PRIMITIVES_MAP = new HashMap<>(); - PRIMITIVES_MAP.put("Integer", "int"); - PRIMITIVES_MAP.put("Float", "float"); - PRIMITIVES_MAP.put("Double", "double"); - PRIMITIVES_MAP.put("Boolean", "boolean"); - PRIMITIVES_MAP.put("Long", "long"); - } - private static String replaceWithPrimitive(String typeName) { - return PRIMITIVES_MAP.getOrDefault(typeName, typeName); + /* Type of the value can be found in map. */ + VALUE_TYPES.put("javafx.beans.property.IntegerProperty", "int"); + VALUE_TYPES.put("javafx.beans.property.LongProperty", "long"); + VALUE_TYPES.put("javafx.beans.property.FloatProperty", "float"); + VALUE_TYPES.put("javafx.beans.property.DoubleProperty", "double"); + VALUE_TYPES.put("javafx.beans.property.BooleanProperty", "boolean"); + VALUE_TYPES.put("javafx.beans.property.StringProperty", "java.lang.String"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyIntegerProperty", "int"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyLongProperty", "long"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyFloatProperty", "float"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyDoubleProperty", "double"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyBooleanProperty", "boolean"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyStringProperty", "java.lang.String"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyIntegerWrapper", "int"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyLongWrapper", "long"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyFloatWrapper", "float"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyDoubleWrapper", "double"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyBooleanWrapper", "boolean"); + VALUE_TYPES.put("javafx.beans.property.ReadOnlyStringWrapper", "java.lang.String"); + + /* Type of the value can be found in map, but it requires the same type + * parameters as the property type. */ + GENERIC_VALUE_TYPES.put("javafx.beans.property.ListProperty", "javafx.collections.ObservableList"); + GENERIC_VALUE_TYPES.put("javafx.beans.property.SetProperty", "javafx.collections.ObservableSet"); + GENERIC_VALUE_TYPES.put("javafx.beans.property.MapProperty", "javafx.collections.ObservableMap"); + GENERIC_VALUE_TYPES.put("javafx.beans.property.ReadOnlyListProperty", "javafx.collections.ObservableList"); + GENERIC_VALUE_TYPES.put("javafx.beans.property.ReadOnlySetProperty", "javafx.collections.ObservableSet"); + GENERIC_VALUE_TYPES.put("javafx.beans.property.ReadOnlyMapProperty", "javafx.collections.ObservableMap"); + GENERIC_VALUE_TYPES.put("javafx.beans.property.ReadOnlyListWrapper", "javafx.collections.ObservableList"); + GENERIC_VALUE_TYPES.put("javafx.beans.property.ReadOnlySetWrapper", "javafx.collections.ObservableSet"); + GENERIC_VALUE_TYPES.put("javafx.beans.property.ReadOnlyMapWrapper", "javafx.collections.ObservableMap"); + + /* Type of the value is given as a type parameter of the property type. */ + VALUE_TYPE_AS_PARAM.add("javafx.beans.property.ObjectProperty"); + VALUE_TYPE_AS_PARAM.add("javafx.beans.property.ReadOnlyObjectProperty"); + VALUE_TYPE_AS_PARAM.add("javafx.beans.property.ReadOnlyObjectWrapper"); + + + /* These property types are writable. */ + WRITABLE_PROPERTIES.add("javafx.beans.property.IntegerProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.LongProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.FloatProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.DoubleProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.BooleanProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.StringProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.ListProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.SetProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.MapProperty"); + WRITABLE_PROPERTIES.add("javafx.beans.property.ObjectProperty"); + + /* Read-only wrapper types and their respective wrapped types. These may + * or may not be generic. If they are, the type parameters are the same. */ + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyIntegerWrapper", "javafx.beans.property.ReadOnlyIntegerProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyLongWrapper", "javafx.beans.property.ReadOnlyLongProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyFloatWrapper", "javafx.beans.property.ReadOnlyFloatProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyDoubleWrapper", "javafx.beans.property.ReadOnlyDoubleProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyBooleanWrapper", "javafx.beans.property.ReadOnlyBooleanProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyStringWrapper", "javafx.beans.property.ReadOnlyStringProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyListWrapper", "javafx.beans.property.ReadOnlyListProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlySetWrapper", "javafx.beans.property.ReadOnlySetProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyMapWrapper", "javafx.beans.property.ReadOnlyMapProperty"); + WRAPPED_READ_ONLY_TYPES.put("javafx.beans.property.ReadOnlyObjectWrapper", "javafx.beans.property.ReadOnlyObjectProperty"); } - private final TreeMaker make; - private final List members; - private final List elements; - private final String className; + private static String getValueType(String typeName) { - + String className = TypeHelper.getClassName(typeName); + String typeParams = TypeHelper.getTypeParameters(typeName); - public PropertyMethodBuilder(TreeMaker make, - List members, - List elements, - String className) { - this.make = make; - this.members = members; - this.elements = elements; - this.className = className; - } + if (VALUE_TYPES.containsKey(className)) { + return VALUE_TYPES.get(className); + + } else if (GENERIC_VALUE_TYPES.containsKey(className)) { + return GENERIC_VALUE_TYPES.get(className) + '<' + typeParams + '>'; - int removeExistingPropMethods(int index) { - int counter = 0; - if( elements == null ) { - return 0; + } else if (VALUE_TYPE_AS_PARAM.contains(className)) { + return typeParams; + + } else { + return "java.lang.Object"; } - for (Iterator treeIt = members.iterator(); treeIt.hasNext();) { - Tree member = treeIt.next(); - - if (member.getKind().equals(Tree.Kind.METHOD)) { - MethodTree mt = (MethodTree) member; - for (Element element : elements) { - if( mt.getName().contentEquals(getGetterName(element.getSimpleName().toString()) ) || - mt.getName().contentEquals(getGetterName(element.getSimpleName().toString(), "is") ) || - - mt.getName().contentEquals(getSetterName(element.getSimpleName().toString()) ) || - mt.getName().contentEquals(getPropertyMethodName(element.getSimpleName().toString()))) { - - treeIt.remove(); - if (index > counter) { - index--; - } - break; - } - } - } - counter++; + } + + private static boolean isWritableType(String typeName) { + return WRITABLE_PROPERTIES.contains(TypeHelper.getClassName(typeName)); + } + + private static boolean isWrapperType(String typeName) { + return WRAPPED_READ_ONLY_TYPES.containsKey(TypeHelper.getClassName(typeName)); + } + + private static String getWrappedReadOnlyType(String typeName) { + + String className = TypeHelper.getClassName(typeName); + String typeParams = TypeHelper.getTypeParameters(typeName); + + if (typeParams == null) { + return WRAPPED_READ_ONLY_TYPES.get(className); + } else { + return WRAPPED_READ_ONLY_TYPES.get(className) + '<' + typeParams + '>'; } - return index; } - void addPropMethods(int index) { + private final TreeMaker make; + private final List fields; + + public PropertyMethodBuilder(TreeMaker make, List fields) { + this.make = make; + this.fields = fields; + } + + List createPropMethods() { - if( elements == null ) { - return; + if (fields == null) { + return Collections.emptyList(); } - - int position = index - 1; - for (VariableElement element : elements) { - position = Math.min(position + 1, members.size()); - members.add(position, createSetMethod(element)); - position = Math.min(position + 1, members.size()); - members.add(position, createGetMethod(element)); - position = Math.min(position + 1, members.size()); - members.add(position, createPropertyMethod(element)); + List createdMethods = new ArrayList<>(); + for (VariableElement field : fields) { + + createdMethods.add(createGetMethod(field)); + + /* Only create set method if property is writable */ + if (isWritableType(field.asType().toString())) { + createdMethods.add(createSetMethod(field)); + } + + createdMethods.add(createPropertyMethod(field)); } + return createdMethods; } - protected MethodTree createGetMethod(VariableElement element) { - Set modifiers = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL); - List annotations = new ArrayList<>(); - String typeName = replaceWithPrimitive(toStringWithoutPackages(element)); - VariableTree parameter = make.Variable(make.Modifiers(new HashSet(), Collections.emptyList()), "value", make.Identifier(typeName), - null); + protected MethodTree createGetMethod(VariableElement field) { + ModifiersTree modifiers = make.Modifiers(EnumSet.of(Modifier.PUBLIC, Modifier.FINAL)); + + String returnTypeName = getValueType(field.asType().toString()); + Tree returnType = make.Type(returnTypeName); - ExpressionTree returnType = make.QualIdent(parameter.getType().toString()); + String getterPrefix = ("boolean".equals(returnTypeName)) ? "is" : "get"; + String name = getGetMethodName(field.getSimpleName().toString(), getterPrefix); - final String bodyText = createPropGetterMethodBody(element); + List typeParameters = Collections.emptyList(); - String setterPrefix = ("boolean".equals(typeName)) ? "is" : "get"; + List parameters = Collections.emptyList(); - MethodTree method = make.Method( - make.Modifiers(modifiers, annotations), - getGetterName(element.getSimpleName().toString(), setterPrefix), - returnType, - Collections.emptyList(), - //Collections.singletonList(parameter), - Collections.emptyList(), - Collections.emptyList(), - bodyText, - null); + List throwsList = Collections.emptyList(); - return method; + BlockTree body = createGetMethodBody(field); + ExpressionTree defaultValue = null; + + + return make.Method(modifiers, name, returnType, typeParameters, parameters, throwsList, body, defaultValue); } - protected MethodTree createPropertyMethod(VariableElement element) { - Set modifiers = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL); - List annotations = new ArrayList<>(); - VariableTree parameter = make.Variable(make.Modifiers(new HashSet(), Collections.emptyList()), "value", make.Identifier(toStringWithoutPackages(element)), - null); + protected MethodTree createSetMethod(VariableElement field) { + ModifiersTree modifiers = make.Modifiers(EnumSet.of(Modifier.PUBLIC, Modifier.FINAL)); + + Tree returnType = make.Type("void"); + + String name = getSetMethodName(field.getSimpleName().toString()); - ExpressionTree returnType = make.QualIdent(parameter.getType().toString() + PROPERTY); + List typeParameters = Collections.emptyList(); - final String bodyText = createPropertyMethodBody(element); + String parameterTypeName = getValueType(field.asType().toString()); + String parameterName = "value"; + VariableTree parameter = make.Variable(make.Modifiers(Collections.emptySet()), parameterName, make.Type(parameterTypeName), null); + List parameters = Collections.singletonList(parameter); - MethodTree method = make.Method( - make.Modifiers(modifiers, annotations), - getPropertyMethodName(element.getSimpleName().toString()), - returnType, - Collections.emptyList(), - //Collections.singletonList(parameter), - Collections.emptyList(), - Collections.emptyList(), - bodyText, - null); + List throwsList = Collections.emptyList(); - return method; + BlockTree body = createSetMethodBody(field, parameterName); + ExpressionTree defaultValue = null; + + + return make.Method(modifiers, name, returnType, typeParameters, parameters, throwsList, body, defaultValue); } - protected MethodTree createSetMethod(VariableElement element) { - Set modifiers = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL); - List annotations = new ArrayList<>(); - String typeName = replaceWithPrimitive(toStringWithoutPackages(element)); - VariableTree parameter = make.Variable(make.Modifiers(new HashSet(), Collections.emptyList()), "value", make.Identifier(typeName), - null); + protected MethodTree createPropertyMethod(VariableElement field) { + ModifiersTree modifiers = make.Modifiers(EnumSet.of(Modifier.PUBLIC)); - ExpressionTree returnType = make.QualIdent("void"); + String fieldTypeName = field.asType().toString(); + boolean isReadOnlyWrapper = isWrapperType(fieldTypeName); - final String bodyText = createPropSetterMethodBody(element); + Tree returnType = make.Type(isReadOnlyWrapper ? getWrappedReadOnlyType(fieldTypeName) : fieldTypeName); - MethodTree method = make.Method( - make.Modifiers(modifiers, annotations), - getSetterName(element.getSimpleName().toString()), - returnType, - Collections.emptyList(), - //Collections.singletonList(parameter), - Collections.singletonList(parameter), - Collections.emptyList(), - bodyText, - null); + String name = getPropertyMethodName(field.getSimpleName().toString()); - return method; + List typeParameters = Collections.emptyList(); - } + List parameters = Collections.emptyList(); - protected String createPropertyMethodBody(Element element) { - StringBuilder sb = new StringBuilder(); - sb.append("{\n") - .append("return ") - .append(element.getSimpleName()) - .append(";\n}"); - return sb.toString(); + List throwsList = Collections.emptyList(); + + BlockTree body = createPropertyMethodBody(field, isReadOnlyWrapper); + + ExpressionTree defaultValue = null; + + + return make.Method(modifiers, name, returnType, typeParameters, parameters, throwsList, body, defaultValue); } - protected String createPropGetterMethodBody(Element element) { - StringBuilder sb = new StringBuilder(); - sb.append("{\n") - .append("return ") - .append(element.getSimpleName()) - .append(".get();\n}"); - return sb.toString(); + protected BlockTree createGetMethodBody(VariableElement field) { + /* return field.get(); */ + ExpressionTree method = make.MemberSelect(make.Identifier(field), "get"); + StatementTree statement = make.Return(make.MethodInvocation(Collections.emptyList(), method, Collections.emptyList())); + + return make.Block(Collections.singletonList(statement), false); } - protected String createPropSetterMethodBody(Element element) { - StringBuilder sb = new StringBuilder(); - sb.append("{\n") - .append(element.getSimpleName()) - .append(".set(value);\n}"); - return sb.toString(); + protected BlockTree createSetMethodBody(VariableElement field, String parameterName) { + /* field.set(parameterName); */ + ExpressionTree method = make.MemberSelect(make.Identifier(field), "set"); + ExpressionTree parameter = make.Identifier(parameterName); + StatementTree statement = make.ExpressionStatement(make.MethodInvocation(Collections.emptyList(), method, Collections.singletonList(parameter))); + + return make.Block(Collections.singletonList(statement), false); } - void addFields() { - for (VariableElement element : elements) { - VariableTree field - = make.Variable(make.Modifiers( - EnumSet.of(Modifier.PRIVATE), - Collections.emptyList()), - element.getSimpleName().toString(), - make.Identifier(toStringWithoutPackages(element)), - null); - - members.add(field); + protected BlockTree createPropertyMethodBody(VariableElement field, boolean isReadOnlyWrapper) { + StatementTree statement; + if (isReadOnlyWrapper) { + /* return field.getReadOnlyProperty(); */ + ExpressionTree method = make.MemberSelect(make.Identifier(field), "getReadOnlyProperty"); + statement = make.Return(make.MethodInvocation(Collections.emptyList(), method, Collections.emptyList())); + } else { + /* return field; */ + statement = make.Return(make.Identifier(field)); } + + return make.Block(Collections.singletonList(statement), false); } - private String getPropertyMethodName(String fieldName) { - final StringBuilder sb = new StringBuilder(); - sb.append(this.prepareFieldNameForMethodName(fieldName, Boolean.FALSE)); - sb.append(PROPERTY); - - return sb.toString(); + private static String getGetMethodName(String fieldName) { + return getGetMethodName(fieldName, "get"); } - private String getSetterName(String fieldName) { - final StringBuilder sb = new StringBuilder(); - sb.append("set"); - sb.append(this.prepareFieldNameForMethodName(fieldName)); - - return sb.toString(); + private static String getGetMethodName(String fieldName, String prefix) { + return prefix + prepareFieldNameForMethodName(fieldName); } - private String getGetterName(String fieldName) { - return getGetterName(fieldName, "get"); + private static String getSetMethodName(String fieldName) { + return "set" + prepareFieldNameForMethodName(fieldName); } - private String getGetterName(String fieldName, String prefix) { - final StringBuilder sb = new StringBuilder(); - sb.append(prefix); - sb.append(this.prepareFieldNameForMethodName(fieldName)); - - return sb.toString(); + private static String getPropertyMethodName(String fieldName) { + return prepareFieldNameForMethodName(fieldName, false) + PROPERTY; } - - private String prepareFieldNameForMethodName(String fieldName, boolean firstCharToUpperCase) { + + private static String prepareFieldNameForMethodName(String fieldName, boolean firstCharToUpperCase) { if (firstCharToUpperCase) { - fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); + fieldName = fieldName.substring(0, 1).toUpperCase(Locale.ROOT) + fieldName.substring(1); } - + if (fieldName.endsWith(PROPERTY)) { fieldName = fieldName.substring(0, fieldName.length() - PROPERTY.length()); } - + return fieldName; } - - private String prepareFieldNameForMethodName(String fieldName) { - return this.prepareFieldNameForMethodName(fieldName, Boolean.TRUE); - } - - private static String toStringWithoutPackages(VariableElement element) { - String fullProp = PackageHelper.removePackagesFromGenericsType(element.asType().toString()); - return fullProp.substring(0, fullProp.indexOf(("Prop"))); + private static String prepareFieldNameForMethodName(String fieldName) { + return prepareFieldNameForMethodName(fieldName, true); } - } diff --git a/src/main/java/com/lynden/netbeans/javafx/TreeHelper.java b/src/main/java/com/lynden/netbeans/javafx/TreeHelper.java index dbaecb4..0d252e9 100644 --- a/src/main/java/com/lynden/netbeans/javafx/TreeHelper.java +++ b/src/main/java/com/lynden/netbeans/javafx/TreeHelper.java @@ -1,34 +1,34 @@ -/** -The MIT License (MIT) - -Copyright (c) 2015 Lynden, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -**/ - +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Lynden, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package com.lynden.netbeans.javafx; import com.sun.source.tree.ClassTree; +import com.sun.source.tree.MethodTree; import com.sun.source.tree.Tree; import com.sun.source.util.SourcePositions; -import com.sun.source.util.TreePath; import java.io.IOException; +import java.util.Collection; import javax.swing.text.Document; import org.netbeans.api.java.source.WorkingCopy; import org.netbeans.editor.GuardedDocument; @@ -37,25 +37,6 @@ of this software and associated documentation files (the "Software"), to deal * */ class TreeHelper { - /** - * Search up the hierarchy of elements for one of the given kind. - * - * @param kind the element's kind to search for - * @param path the starting element - * @return {@code null} if no element was found. - */ - static TreePath getParentElementOfKind(Tree.Kind kind, TreePath path) { - if (path != null) { - TreePath tpath = path; - while (tpath != null) { - if (kind == tpath.getLeaf().getKind()) { - return tpath; - } - tpath = tpath.getParentPath(); - } - } - return null; - } /** * Find the index of the current class member. @@ -100,4 +81,17 @@ static int findClassMemberIndex(WorkingCopy wc, return index; } + /** + * Checks if the given collection of {@code members} contains a method with + * the same name as the given {@code method}. + * + * @param members + * @param method + * @return true if the collection contains a method with the same name + */ + static boolean hasMethodWithSameName(Collection members, MethodTree method) { + return members.stream().anyMatch((Tree member) -> { + return member.getKind().equals(Tree.Kind.METHOD) && ((MethodTree) member).getName().contentEquals(method.getName()); + }); + } } diff --git a/src/main/java/com/lynden/netbeans/javafx/TypeHelper.java b/src/main/java/com/lynden/netbeans/javafx/TypeHelper.java new file mode 100644 index 0000000..3dd43d2 --- /dev/null +++ b/src/main/java/com/lynden/netbeans/javafx/TypeHelper.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Lynden, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lynden.netbeans.javafx; + +/** + * Manipulates strings containing types. + * + */ +class TypeHelper { + + /** + * Returns only the class name part of a type name without type parameters. + * {@code "java.util.Map" -> "java.util.Map"} + * + * @param fullName + * @return class name + */ + static String getClassName(String fullName) { + if (!fullName.contains("<")) { + return fullName; + } else { + return fullName.substring(0, fullName.indexOf('<')); + } + } + + /** + * Returns only the type parameters part of a type name. Type params are in + * the same form as in the original type. If there were no type parameters, + * null is returned. + * {@code "java.util.Map" -> "java.lang.String, java.lang.String"} + * + * @param fullName + * @return type parameters + */ + static String getTypeParameters(String fullName) { + if (!fullName.contains("<")) { + return null; + } else { + return fullName.substring(fullName.indexOf('<') + 1, fullName.lastIndexOf('>')); + } + } +} diff --git a/src/main/resources/com/lynden/netbeans/javafx/Bundle.properties b/src/main/resources/com/lynden/netbeans/javafx/Bundle.properties index 311c424..8b4629e 100644 --- a/src/main/resources/com/lynden/netbeans/javafx/Bundle.properties +++ b/src/main/resources/com/lynden/netbeans/javafx/Bundle.properties @@ -2,5 +2,5 @@ OpenIDE-Module-Name=JavaFx Property Getter & Setter Generator OpenIDE-Module-Short-Description=Automatically generates getter and setter methods for JavaFx Properties in a POJO. OpenIDE-Module-Long-Description=Automatically generates getter and setter methods for JavaFx Properties in a POJO. -OpenIDE-Module-Display-Category=JavaFx +OpenIDE-Module-Display-Category=JavaFX 2 #Tue Sep 29 14:37:09 PDT 2015