javafx: Inspection of FXML attributes and tags which contain default values and there...
authorPavel Dolgov <pavel.dolgov@jetbrains.com>
Wed, 2 Mar 2016 16:59:27 +0000 (19:59 +0300)
committerPavel Dolgov <pavel.dolgov@jetbrains.com>
Wed, 2 Mar 2016 16:59:27 +0000 (19:59 +0300)
20 files changed:
plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/AbstractJavaFXQuickFixTest.java
plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxGenerateDefaultPropertyValuesScript.java [new file with mode: 0644]
plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxRedundantValueTest.java [new file with mode: 0644]
plugins/javaFX/resources/inspectionDescriptions/JavaFxRedundantPropertyValue.html [new file with mode: 0644]
plugins/javaFX/src/META-INF/common-javaFX-plugin.xml
plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection.java [new file with mode: 0644]
plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection8.txt [new file with mode: 0644]
plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/RemoveTagFix.java [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/attributeHighlighting.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/immediateAttribute.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/immediateAttribute_after.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/immediateTag.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/immediateTag_after.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/inheritedAttribute.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/inheritedAttribute_after.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/inheritedTag.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/inheritedTag_after.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/modifiedAttribute.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/modifiedTag.fxml [new file with mode: 0644]
plugins/javaFX/testData/inspections/redundantValue/tagHighlighting.fxml [new file with mode: 0644]

index feaaf1ec1336b011e516c0fb553da49ff50f2234..88a468abc7d494ba78fc0d8e7238614f200084f4 100644 (file)
@@ -16,6 +16,9 @@
 package org.jetbrains.plugins.javaFX.fxml;
 
 import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.testFramework.fixtures.CodeInsightTestUtil;
+
+import java.util.List;
 
 /**
  * User: anna
@@ -34,7 +37,8 @@ public abstract class AbstractJavaFXQuickFixTest extends AbstractJavaFXTestCase
 
   protected void checkQuickFixNotAvailable(String tagName) throws Exception {
     myFixture.configureByFiles(getTestName(true) + ".fxml");
-    final IntentionAction intention = myFixture.getAvailableIntention(getHint(tagName));
+    final List<IntentionAction> intentions = myFixture.getAvailableIntentions();
+    final IntentionAction intention = CodeInsightTestUtil.findIntentionByText(intentions, getHint(tagName));
     assertNull(intention);
   }
 }
diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxGenerateDefaultPropertyValuesScript.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxGenerateDefaultPropertyValuesScript.java
new file mode 100644 (file)
index 0000000..7a68e17
--- /dev/null
@@ -0,0 +1,533 @@
+package org.jetbrains.plugins.javaFX.fxml;
+
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.layout.StackPane;
+import javafx.stage.Stage;
+import org.jetbrains.annotations.NotNull;
+
+import java.beans.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * This is not a test, this is a config generator for JavaFxRedundantPropertyValueInspection
+ * <p>
+ * When launched without arguments it produces default values for JavaFX classes having default constructor and their superclasses, including some (but not all) abstract classes
+ * <p>
+ * When launched with <code>-fromSource</code> argument it attempts to extract default property values from the sources (JavaDoc and declarations),
+ * the results can be used for updating the contents of {@link #ourFromSource} map, which contains manually edited properties
+ *
+ * @author Pavel.Dolgov
+ */
+public class JavaFxGenerateDefaultPropertyValuesScript extends Application {
+  public static final String BINARIES_PATH = "/usr/lib/jvm/java-8-oracle/jre/lib/ext/jfxrt.jar";
+  public static final String SOURCE_PATH = "/usr/lib/jvm/java-8-oracle/javafx-src.zip";
+
+  public static void main(String[] args) {
+    if (args.length == 1 && "-fromSource".equals(args[0])) {
+      scanSource();
+    }
+    else {
+      launch(args);
+    }
+  }
+
+  @Override
+  public void start(Stage primaryStage) throws Exception {
+    Button b = new Button();
+    b.setText("Generate");
+    b.setOnAction(event -> generate());
+
+    StackPane pane = new StackPane();
+    pane.getChildren().add(b);
+    primaryStage.setScene(new Scene(pane, 300, 200));
+    primaryStage.show();
+
+    Platform.runLater(() -> {
+      generate();
+      primaryStage.close();
+    });
+  }
+
+  private static final Map<Class, Class> ourToBoxed = new HashMap<>();
+
+  static {
+    ourToBoxed.put(Boolean.TYPE, Boolean.class);
+    ourToBoxed.put(Character.TYPE, Character.class);
+    ourToBoxed.put(Byte.TYPE, Byte.class);
+    ourToBoxed.put(Short.TYPE, Short.class);
+    ourToBoxed.put(Integer.TYPE, Integer.class);
+    ourToBoxed.put(Long.TYPE, Long.class);
+    ourToBoxed.put(Float.TYPE, Float.class);
+    ourToBoxed.put(Double.TYPE, Double.class);
+  }
+
+  private static final Map<String, String> ourFromSource = new TreeMap<>();
+
+  static {
+    ourFromSource.put("javafx.concurrent.ScheduledService#maximumFailureCount", "Integer=2147483647");
+    ourFromSource.put("javafx.concurrent.ScheduledService#restartOnFailure", "Boolean=true");
+    ourFromSource.put("javafx.scene.Node#accessibleRole", "Enum=NODE");
+    ourFromSource.put("javafx.scene.Node#focusTraversable", "Boolean=false");
+    ourFromSource.put("javafx.scene.Node#nodeOrientation", "Enum=INHERIT");
+    ourFromSource.put("javafx.scene.Node#pickOnBounds", "Boolean=false");
+    ourFromSource.put("javafx.scene.SubScene#height", "Double=0.0");
+    ourFromSource.put("javafx.scene.SubScene#width", "Double=0.0");
+    ourFromSource.put("javafx.scene.chart.AreaChart#createSymbols", "Boolean=true");
+    ourFromSource.put("javafx.scene.chart.Axis#label", "String=");
+    ourFromSource.put("javafx.scene.chart.BarChart#barGap", "Double=4.0");
+    ourFromSource.put("javafx.scene.chart.BarChart#categoryGap", "Double=10.0");
+    ourFromSource.put("javafx.scene.chart.Chart#title", "String=");
+    ourFromSource.put("javafx.scene.chart.LineChart#axisSortingPolicy", "Enum=X_AXIS");
+    ourFromSource.put("javafx.scene.chart.LineChart#createSymbols", "Boolean=true");
+    ourFromSource.put("javafx.scene.chart.StackedAreaChart#createSymbols", "Boolean=true");
+    ourFromSource.put("javafx.scene.chart.StackedBarChart#categoryGap", "Double=10.0");
+    ourFromSource.put("javafx.scene.chart.XYChart#alternativeColumnFillVisible", "Boolean=false");
+    ourFromSource.put("javafx.scene.chart.XYChart#alternativeRowFillVisible", "Boolean=true");
+    ourFromSource.put("javafx.scene.chart.XYChart#horizontalGridLinesVisible", "Boolean=true");
+    ourFromSource.put("javafx.scene.chart.XYChart#horizontalZeroLineVisible", "Boolean=true");
+    ourFromSource.put("javafx.scene.chart.XYChart#verticalGridLinesVisible", "Boolean=true");
+    ourFromSource.put("javafx.scene.chart.XYChart#verticalZeroLineVisible", "Boolean=true");
+    ourFromSource.put("javafx.scene.control.ComboBoxBase#editable", "Boolean=false");
+    ourFromSource.put("javafx.scene.control.CustomMenuItem#hideOnClick", "Boolean=true");
+    ourFromSource.put("javafx.scene.control.Labeled#alignment", "Enum=CENTER_LEFT");
+    ourFromSource.put("javafx.scene.control.Labeled#mnemonicParsing", "Boolean=false");
+    ourFromSource.put("javafx.scene.control.SpinnerValueFactory#wrapAround", "Boolean=false");
+    ourFromSource.put("javafx.scene.control.TableSelectionModel#cellSelectionEnabled", "Boolean=false");
+    ourFromSource.put("javafx.scene.media.AudioClip#balance", "Double=0.0");
+    ourFromSource.put("javafx.scene.media.AudioClip#cycleCount", "Integer=1");
+    ourFromSource.put("javafx.scene.media.AudioClip#pan", "Double=0.0");
+    ourFromSource.put("javafx.scene.media.AudioClip#priority", "Integer=0");
+    ourFromSource.put("javafx.scene.media.AudioClip#rate", "Double=1.0");
+    ourFromSource.put("javafx.scene.media.AudioClip#volume", "Double=1.0");
+    ourFromSource.put("javafx.scene.media.AudioEqualizer#enabled", "Boolean=false");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#audioSpectrumInterval", "Double=0.1");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#audioSpectrumNumBands", "Integer=128");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#audioSpectrumThreshold", "Integer=-60");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#autoPlay", "Boolean=false");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#balance", "Double=0.0");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#cycleCount", "Integer=1");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#mute", "Boolean=false");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#rate", "Double=1.0");
+    ourFromSource.put("javafx.scene.media.MediaPlayer#volume", "Double=1.0");
+    ourFromSource.put("javafx.stage.PopupWindow#anchorLocation", "Enum=WINDOW_TOP_LEFT");
+    ourFromSource.put("javafx.stage.PopupWindow#autoHide", "Boolean=false");
+    ourFromSource.put("javafx.stage.PopupWindow#consumeAutoHidingEvents", "Boolean=true");
+  }
+
+  private static final Set<String> ourSkippedProperties = new HashSet<>(
+    Arrays.asList("javafx.scene.web.HTMLEditor#htmlText",
+                  "javafx.scene.web.WebEngine#userAgent",
+                  "javafx.scene.control.ButtonBar#buttonOrder"));
+
+  static class TypedValue {
+
+    private final String kind;
+    private final String value;
+
+    TypedValue(@NotNull String kind, @NotNull String value) {
+      this.kind = kind;
+      this.value = value;
+    }
+
+    public String getKind() {
+      return kind;
+    }
+
+    public String getValue() {
+      return value;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (!(o instanceof TypedValue)) return false;
+
+      TypedValue that = (TypedValue)o;
+      return kind.equals(that.kind) && value.equals(that.value);
+    }
+
+    @Override
+    public int hashCode() {
+      return kind.hashCode() ^ value.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return kind + ':' + value;
+    }
+  }
+
+  static class ContainedValue extends TypedValue {
+    private final String declaringClass;
+
+    public ContainedValue(@NotNull String kind, @NotNull String value, @NotNull String declaringClass) {
+      super(kind, value);
+      this.declaringClass = declaringClass;
+    }
+
+    public String getDeclaringClass() {
+      return declaringClass;
+    }
+  }
+
+  /**
+   * Attempt to instantiate JavaFX classes on the FX thread, obtain default property values from instantiated objects.
+   */
+  private static void generate() {
+    System.out.println("--- JavaFX default property values ---");
+
+    final Map<String, Map<String, ContainedValue>> containedProperties = new TreeMap<>();
+    final Map<String, Map<String, TypedValue>> declaredProperties = new TreeMap<>();
+    final Map<String, Map<String, Set<String>>> overriddenProperties = new TreeMap<>();
+    final Map<String, String> superClasses = new TreeMap<>();
+    try (final ZipInputStream zip = new ZipInputStream(new FileInputStream(new File(BINARIES_PATH)))) {
+      for (ZipEntry ze = zip.getNextEntry(); ze != null; ze = zip.getNextEntry()) {
+        final String entryName = ze.getName();
+        if (!ze.isDirectory() && entryName.endsWith(".class") && entryName.startsWith("javafx")) {
+          final String className = entryName.substring(0, entryName.lastIndexOf('.')).replace('/', '.');
+          Class<?> currentClass = Class.forName(className);
+          if (!Modifier.isPublic(currentClass.getModifiers()) && !Modifier.isProtected(currentClass.getModifiers())) continue;
+          if (currentClass.getName().startsWith("javafx.beans")) continue;
+          if (currentClass.getName().matches(".*\\$\\d+$")) continue;
+          BeanInfo info = Introspector.getBeanInfo(currentClass);
+          if (currentClass.getSuperclass() != null) {
+            superClasses.put(currentClass.getName(), currentClass.getSuperclass().getName());
+          }
+
+          Set<String> bindings = new TreeSet<>();
+          for (MethodDescriptor methodDesc : info.getMethodDescriptors()) {
+            if (methodDesc.getName().endsWith("Property") &&
+                !methodDesc.getMethod().getGenericReturnType().toString().contains("ReadOnly")) {
+              bindings.add(methodDesc.getName());
+            }
+          }
+
+          Object obj = null;
+          for (PropertyDescriptor desc : info.getPropertyDescriptors()) {
+            final String propName = desc.getName();
+            final String propQualifiedName = currentClass.getName() + "#" + propName;
+            if (ourSkippedProperties.contains(propQualifiedName)) continue;
+            final Method setter = desc.getWriteMethod();
+            final boolean hasBinding = bindings.contains(propName + "Property");
+            if (setter == null || !hasBinding) continue;
+            final Type type = setter.getGenericParameterTypes()[0];
+
+            if (type instanceof Class) {
+              final Class<?> paramCls = (Class)type;
+              final String kind = kind(paramCls);
+              if (kind != null) {
+                if (obj == null) {
+                  obj = instantiate(currentClass);
+                  if (obj == null) break;
+                }
+                final Object value;
+                final Method getter = desc.getReadMethod();
+                try {
+                  value = getter.invoke(obj);
+                }
+                catch (IllegalAccessException | InvocationTargetException e) {
+                  throw new RuntimeException("Can't invoke " + getter + " on " + currentClass, e);
+                }
+                if (value != null) {
+                  if (!value.equals(validate(paramCls, value))) {
+                    throw new RuntimeException("Invalid " + currentClass + "#" + propName + ":" + paramCls + "=" + value);
+                  }
+                  final Class<?> declaringClass = getter.getDeclaringClass();
+                  final ContainedValue newValue = new ContainedValue(kind, String.valueOf(value), declaringClass.getName());
+                  if (declaringClass.getName().startsWith("javafx")) {
+                    containedProperties
+                      .computeIfAbsent(currentClass.getName(), unused -> new TreeMap<>())
+                      .put(propName, newValue);
+                  }
+
+                  final Map<String, TypedValue> shareableProperties =
+                    declaredProperties.computeIfAbsent(declaringClass.getName(), unused -> new TreeMap<>());
+                  final TypedValue sharedValue = shareableProperties.get(propName);
+
+                  if (sharedValue == null) {
+                    shareableProperties.put(propName, newValue);
+                  }
+                  else if (!sharedValue.equals(newValue)) {
+                    final Set<String> multipleValues = overriddenProperties
+                      .computeIfAbsent(declaringClass.getName(), unused -> new TreeMap<>())
+                      .computeIfAbsent(propName, unused -> new TreeSet<>());
+                    multipleValues.add(sharedValue.getValue());
+                    multipleValues.add(newValue.getValue());
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    catch (IOException | ClassNotFoundException | IntrospectionException e) {
+      e.printStackTrace();
+    }
+
+    System.out.println("-------- Collected from sources ---------");
+    ourFromSource.forEach((k, v) -> System.out.println(k + ":" + v));
+
+    System.out.println("-------- Shared (not overridden) ---------");
+    declaredProperties.forEach(
+      (className, propertyMap) -> {
+        final Map<String, Set<String>> multipleValues = overriddenProperties.getOrDefault(className, Collections.emptyMap());
+        propertyMap.forEach((propName, typedValue) -> {
+          if (!multipleValues.containsKey(propName)) {
+            System.out.println(className + "#" + propName + ":" + typedValue.getKind() + "=" + typedValue.getValue());
+          }
+        });
+      });
+    System.out.println("-------- Overridden in subclass ---------");
+    final Map<String, Map<String, ContainedValue>> fromSource = new TreeMap<>();
+    ourFromSource.forEach((classAndPropName, kindAndValue) -> {
+      final int p1 = classAndPropName.indexOf('#');
+      if (p1 > 0 && p1 < classAndPropName.length()) {
+        final String className = classAndPropName.substring(0, p1);
+        final String propName = classAndPropName.substring(p1 + 1);
+        final int p3 = kindAndValue.indexOf('=');
+        if (p3 > 0 && p3 < kindAndValue.length()) {
+          final String kind = kindAndValue.substring(0, p3);
+          final String value = kindAndValue.substring(p3 + 1);
+          final Map<String, ContainedValue> propMap = fromSource.computeIfAbsent(className, unused -> new TreeMap<>());
+          if (!propMap.containsKey(propName)) {
+            final ContainedValue valueFromSource = new ContainedValue(kind, value, className);
+            propMap.put(propName, valueFromSource);
+          }
+        }
+      }
+    });
+    containedProperties.forEach(
+      (className, propertyMap) -> propertyMap.forEach(
+        (propName, propValue) -> {
+          final ContainedValue sourceValue = fromSource.getOrDefault(className, Collections.emptyMap()).get(propName);
+          if (sourceValue != null &&
+              sourceValue.equals(propValue)) {
+            return;
+          }
+          final Map<String, Set<String>> multipleValues = overriddenProperties.get(propValue.getDeclaringClass());
+          if (multipleValues != null && multipleValues.get(propName) != null) {
+            boolean sameValueInSuperClass = false;
+            for (String scName = superClasses.get(className); scName != null; scName = superClasses.get(scName)) {
+              final Map<String, ContainedValue> superPropMap = containedProperties.getOrDefault(scName, fromSource.get(scName));
+              if (superPropMap != null) {
+                ContainedValue superValue = superPropMap.get(propName);
+                if (superValue != null) {
+                  sameValueInSuperClass = superValue.equals(propValue);
+                  break;
+                }
+              }
+            }
+            if (!sameValueInSuperClass) {
+              System.out.println(className + "#" + propName + ":" + propValue.getKind() + "=" + propValue.getValue());
+            }
+          }
+        }));
+
+    System.out.println("-------- Overridden properties' values ---------");
+    overriddenProperties
+      .forEach((className, propertyValues) -> propertyValues.entrySet()
+        .forEach(e -> System.out.println("-- " + className + "#" + e.getKey() + e.getValue())));
+    System.out.println("-------- Skipped properties ---------");
+    ourSkippedProperties.forEach(propName -> System.out.println("-- " + propName));
+  }
+
+  private static String kind(Class aCls) {
+    String kind = null;
+    if (aCls.isPrimitive()) {
+      kind = ourToBoxed.get(aCls).getSimpleName();
+    }
+    else if (aCls.isEnum()) {
+      kind = "Enum";
+    }
+    else if (Number.class.isAssignableFrom(aCls) || Boolean.class.isAssignableFrom(aCls) || Character.class.isAssignableFrom(aCls)) {
+      kind = aCls.getSimpleName();
+    }
+    else if (CharSequence.class.isAssignableFrom(aCls)) {
+      kind = "String";
+    }
+    return kind;
+  }
+
+  private static Object validate(Class<?> aCls, Object val) {
+    try {
+      if (aCls.isPrimitive()) {
+        aCls = ourToBoxed.get(aCls);
+        Method valueOf = aCls.getDeclaredMethod("valueOf", String.class);
+        return valueOf.invoke(null, String.valueOf(val));
+      }
+      if (Number.class.isAssignableFrom(aCls) || Boolean.class.isAssignableFrom(aCls) || Character.class.isAssignableFrom(aCls)) {
+        Method valueOf = aCls.getDeclaredMethod("valueOf", String.class);
+        return valueOf.invoke(null, String.valueOf(val));
+      }
+      if (CharSequence.class.isAssignableFrom(aCls)) {
+        return val;
+      }
+      if (aCls.isEnum()) {
+        Method valueOf = aCls.getDeclaredMethod("valueOf", String.class);
+        return valueOf.invoke(null, String.valueOf(val));
+      }
+      throw new IllegalStateException("Cannot cast " + val + " to unsupported class " + aCls);
+    }
+    catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+      throw new IllegalStateException("Cannot cast " + val + " to " + aCls, e);
+    }
+  }
+
+  private static Object instantiate(Class<?> aClass) {
+    try {
+      if (Modifier.isAbstract(aClass.getModifiers())) return null;
+
+      final Constructor<?> constructor;
+      try {
+        constructor = aClass.getConstructor();
+      }
+      catch (NoSuchMethodException e) {
+        return null;
+      }
+      constructor.setAccessible(true);
+      return constructor.newInstance();
+    }
+    catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+      System.err.println("Not instantiated " + aClass + " " + e);
+      return null;
+    }
+  }
+
+  private static final Set<String> ourSourceClasses = new TreeSet<>();
+
+  static {
+    ourSourceClasses.add("javafx.animation.Animation");
+    ourSourceClasses.add("javafx.concurrent.ScheduledService");
+    ourSourceClasses.add("javafx.print.JobSettings");
+    ourSourceClasses.add("javafx.scene.Camera");
+    ourSourceClasses.add("javafx.scene.LightBase");
+    ourSourceClasses.add("javafx.scene.Node");
+    ourSourceClasses.add("javafx.scene.Scene");
+    ourSourceClasses.add("javafx.scene.SubScene");
+    ourSourceClasses.add("javafx.scene.canvas.GraphicsContext");
+    ourSourceClasses.add("javafx.scene.chart.AreaChart");
+    ourSourceClasses.add("javafx.scene.chart.Axis");
+    ourSourceClasses.add("javafx.scene.chart.BarChart");
+    ourSourceClasses.add("javafx.scene.chart.Chart");
+    ourSourceClasses.add("javafx.scene.chart.LineChart");
+    ourSourceClasses.add("javafx.scene.chart.PieChart");
+    ourSourceClasses.add("javafx.scene.chart.StackedAreaChart");
+    ourSourceClasses.add("javafx.scene.chart.StackedBarChart");
+    ourSourceClasses.add("javafx.scene.chart.ValueAxis");
+    ourSourceClasses.add("javafx.scene.chart.XYChart");
+    ourSourceClasses.add("javafx.scene.control.Alert");
+    ourSourceClasses.add("javafx.scene.control.ComboBoxBase");
+    ourSourceClasses.add("javafx.scene.control.Labeled");
+    ourSourceClasses.add("javafx.scene.control.MultipleSelectionModel");
+    ourSourceClasses.add("javafx.scene.control.SpinnerValueFactory");
+    ourSourceClasses.add("javafx.scene.control.SpinnerValueFactory");
+    ourSourceClasses.add("javafx.scene.control.SpinnerValueFactory");
+    ourSourceClasses.add("javafx.scene.control.TableColumnBase");
+    ourSourceClasses.add("javafx.scene.control.TableSelectionModel");
+    ourSourceClasses.add("javafx.scene.control.TextFormatter");
+    ourSourceClasses.add("javafx.scene.control.TextInputControl");
+    ourSourceClasses.add("javafx.scene.control.Toggle");
+    ourSourceClasses.add("javafx.scene.input.DragEvent");
+    ourSourceClasses.add("javafx.scene.input.Dragboard");
+    ourSourceClasses.add("javafx.scene.input.MouseEvent");
+    ourSourceClasses.add("javafx.scene.media.AudioClip");
+    ourSourceClasses.add("javafx.scene.media.AudioEqualizer");
+    ourSourceClasses.add("javafx.scene.media.MediaPlayer");
+    ourSourceClasses.add("javafx.scene.shape.PathElement");
+    ourSourceClasses.add("javafx.scene.shape.Shape");
+    ourSourceClasses.add("javafx.scene.shape.Shape3D");
+    ourSourceClasses.add("javafx.scene.web.WebHistory");
+    ourSourceClasses.add("javafx.stage.PopupWindow");
+    ourSourceClasses.add("javafx.stage.Window");
+  }
+
+  private static void scanSource() {
+
+    Pattern defaultValueJavaDoc = Pattern.compile("^.*\\*\\s*@defaultValue\\s*(.+)\\s*$");
+    Pattern fieldDecl = Pattern.compile("^.*\\s(\\w+)\\s*(=.*|;)\\s*$");
+    Pattern methodDecl = Pattern.compile("^.*\\s(\\w+)\\s*\\(\\).*$");
+    Pattern propertyDecl = Pattern.compile("^.*Property\\S*\\s+(\\w+)\\s*=\\s*(.+)[;{].*$");
+
+    Map<String, String> props = new TreeMap<>();
+    try (final ZipInputStream zip = new ZipInputStream(new FileInputStream(new File(SOURCE_PATH)))) {
+      byte[] buffer = new byte[1 << 16];
+      for (ZipEntry ze = zip.getNextEntry(); ze != null; ze = zip.getNextEntry()) {
+        final String eName = ze.getName();
+        if (!ze.isDirectory() && eName.endsWith(".java") && eName.startsWith("javafx")) {
+          String className = eName.substring(0, eName.lastIndexOf('.')).replace('/', '.');
+          if (ourSourceClasses.contains(className)) {
+            StringBuilder text = new StringBuilder();
+            int len;
+            while ((len = zip.read(buffer)) > 0) {
+              String str = new String(buffer, 0, len);
+              text.append(str);
+            }
+            String[] lines = text.toString().split("\n");
+            int state = 0;
+            String name = null;
+            String value = null;
+            for (String s : lines) {
+              Matcher m;
+              m = propertyDecl.matcher(s);
+              if (m.matches()) {
+                name = m.group(1);
+                value = m.group(2);
+                if (!"null".equals(value)) {
+                  props.put(className + "#" + name, value);
+                }
+              }
+              switch (state) {
+                case 0:
+                  m = defaultValueJavaDoc.matcher(s);
+                  if (m.matches()) {
+                    state = 1;
+                    value = m.group(1);
+                  }
+                  break;
+                case 1:
+                  if (s.contains("*/")) state = 2;
+                  break;
+                case 2:
+                  if (!s.trim().isEmpty()) {
+                    state = 0;
+                    m = fieldDecl.matcher(s);
+                    if (m.matches()) {
+                      name = m.group(1);
+                    }
+                    else {
+                      m = methodDecl.matcher(s);
+                      if (m.matches()) {
+                        name = m.group(1);
+                      }
+                    }
+                    if (name != null && value != null && !"null".equals(value)) {
+                      props.put(className + "#" + name, value);
+                    }
+                    name = value = null;
+                  }
+                  break;
+              }
+            }
+          }
+        }
+      }
+    }
+    catch (IOException e) {
+      System.err.println("Failed to read sources " + e);
+    }
+    System.out.println("--- Default values collected from JavaDoc and declarations. To be reviewed and manually edited ---");
+    props.forEach((n, v) -> System.out.println(n + "=" + v));
+  }
+}
diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxRedundantValueTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxRedundantValueTest.java
new file mode 100644 (file)
index 0000000..aab4ee8
--- /dev/null
@@ -0,0 +1,66 @@
+package org.jetbrains.plugins.javaFX.fxml;
+
+import com.intellij.openapi.application.PluginPathManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxRedundantPropertyValueInspection;
+
+/**
+ * @author Pavel.Dolgov
+ */
+public class JavaFxRedundantValueTest extends AbstractJavaFXQuickFixTest {
+  @Override
+  protected void enableInspections() {
+    myFixture.enableInspections(new JavaFxRedundantPropertyValueInspection());
+  }
+
+  public void testModifiedAttribute() throws Exception {
+    checkQuickFixNotAvailable("alignment");
+  }
+
+  public void testImmediateAttribute() throws Exception {
+    doLaunchQuickfixTest("alignment");
+  }
+
+  public void testInheritedAttribute() throws Exception {
+    doLaunchQuickfixTest("maxHeight");
+  }
+
+  public void testModifiedTag() throws Exception {
+    checkQuickFixNotAvailable("alignment");
+  }
+
+  public void testImmediateTag() throws Exception {
+    doLaunchQuickfixTest("alignment");
+  }
+
+  public void testInheritedTag() throws Exception {
+    doLaunchQuickfixTest("maxHeight");
+  }
+
+  public void testAttributeHighlighting() throws Exception {
+    doTestHighlighting();
+  }
+
+  public void testTagHighlighting() throws Exception {
+    doTestHighlighting();
+  }
+
+  private void doTestHighlighting() {
+    myFixture.configureByFiles(getTestName(true) + ".fxml");
+    myFixture.checkHighlighting();
+  }
+
+  @NotNull
+  @Override
+  protected String getTestDataPath() {
+    return PluginPathManager.getPluginHomePath("javaFX") + "/testData/inspections/redundantValue/";
+  }
+
+  @Override
+  protected String getHint(String tagName) {
+    if (getTestName(false).endsWith("Attribute")) {
+      return "Remove attribute " + tagName;
+    }
+    return "Remove tag '" + tagName + "'";
+  }
+}
diff --git a/plugins/javaFX/resources/inspectionDescriptions/JavaFxRedundantPropertyValue.html b/plugins/javaFX/resources/inspectionDescriptions/JavaFxRedundantPropertyValue.html
new file mode 100644 (file)
index 0000000..c03a132
--- /dev/null
@@ -0,0 +1,6 @@
+<html>
+<body>
+This inspection reports properties in .fxml files (both attributes and tags) having default values and therefore redundant.
+<!-- tooltip end -->
+</body>
+</html>
\ No newline at end of file
index 84ca5e512a1d8e32f7b20bedc941b5c087c6188f..ca16653de0a9ef3707e81623d5e864a2df73c25b 100644 (file)
@@ -22,6 +22,8 @@
                      enabledByDefault="true" level="WARNING" groupName="JavaFX"/>
     <localInspection language="XML" shortName="JavaFxUnusedImports" implementationClass="org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxUnusedImportsInspection"
                          enabledByDefault="true" level="WARNING" displayName="JavaFX unused imports" groupName="JavaFX"/>
+    <localInspection language="XML" shortName="JavaFxRedundantPropertyValue" implementationClass="org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxRedundantPropertyValueInspection"
+                         enabledByDefault="true" level="WARNING" displayName="JavaFX redundant property values" groupName="JavaFX"/>
 
     <applicationService serviceInterface="org.jetbrains.plugins.javaFX.JavaFxSettings" serviceImplementation="org.jetbrains.plugins.javaFX.JavaFxSettings"/>
     <applicationConfigurable groupId="language" displayName="JavaFX" id="preferences.JavaFX" instance="org.jetbrains.plugins.javaFX.JavaFxSettingsConfigurable"/>
diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection.java
new file mode 100644 (file)
index 0000000..fbd642f
--- /dev/null
@@ -0,0 +1,239 @@
+package org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections;
+
+import com.intellij.codeInsight.daemon.impl.analysis.RemoveAttributeIntentionFix;
+import com.intellij.codeInspection.*;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.CharsetToolkit;
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.xml.XmlAttribute;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.reference.SoftReference;
+import com.intellij.xml.XmlAttributeDescriptor;
+import com.intellij.xml.XmlElementDescriptor;
+import gnu.trove.THashMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
+import org.jetbrains.plugins.javaFX.fxml.JavaFxFileTypeFactory;
+import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxClassBackedElementDescriptor;
+import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxPropertyAttributeDescriptor;
+import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxPropertyElementDescriptor;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.ref.Reference;
+import java.net.URL;
+import java.util.LinkedHashSet;
+import java.util.Map;
+
+/**
+ * @author Pavel.Dolgov
+ */
+public class JavaFxRedundantPropertyValueInspection extends XmlSuppressableInspectionTool {
+  private static final Logger LOG = Logger.getInstance("#" + JavaFxRedundantPropertyValueInspection.class.getName());
+
+  private static Reference<Map<String, Map<String, Object>>> ourDefaultPropertyValues;
+
+  @NotNull
+  @Override
+  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
+    return new XmlElementVisitor() {
+      @Override
+      public void visitXmlFile(XmlFile file) {
+        if (!JavaFxFileTypeFactory.isFxml(file)) return;
+        super.visitXmlFile(file);
+      }
+
+      @Override
+      public void visitXmlAttribute(XmlAttribute attribute) {
+        super.visitXmlAttribute(attribute);
+        final XmlAttributeDescriptor descriptor = attribute.getDescriptor();
+        if (!(descriptor instanceof JavaFxPropertyAttributeDescriptor)) return;
+        final String attributeName = attribute.getName();
+        final String attributeValue = attribute.getValue();
+        if (attributeValue == null ||
+            attributeValue.startsWith("$") ||
+            attributeValue.startsWith("#") ||
+            attributeValue.startsWith("%") ||
+            FxmlConstants.FX_ID.equals(attributeName) ||
+            FxmlConstants.FX_CONTROLLER.equals(attributeName)) {
+          return;
+        }
+
+        final Object defaultValue = getDefaultValue(attributeName, attribute.getParent());
+        if (defaultValue == null) return;
+
+        if (isEqualValue(attributeValue, defaultValue)) {
+          holder.registerProblem(attribute, "Attribute is redundant because it contains default value",
+                                 ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+                                 new RemoveAttributeIntentionFix(attributeName, attribute));
+        }
+      }
+
+      @Override
+      public void visitXmlTag(XmlTag tag) {
+        super.visitXmlTag(tag);
+        final XmlElementDescriptor descriptor = tag.getDescriptor();
+        if (!(descriptor instanceof JavaFxPropertyElementDescriptor) &&
+            !(descriptor instanceof JavaFxClassBackedElementDescriptor)) {
+          return;
+        }
+        if (tag.getSubTags().length != 0) return;
+        final String tagText = tag.getValue().getText().trim();
+        if (tagText.startsWith("$") ||
+            tagText.startsWith("#") ||
+            tagText.startsWith("%")) {
+          return;
+        }
+
+        final Object defaultValue = getDefaultValue(tag.getName(), tag.getParentTag());
+        if (defaultValue == null) return;
+
+        if (isEqualValue(tagText, defaultValue)) {
+          holder.registerProblem(tag, "Tag is redundant because it contains default value",
+                                 ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+                                 new RemoveTagFix(tag.getName()));
+        }
+      }
+    };
+  }
+
+  @Nullable
+  private static Object getDefaultValue(@NotNull String propertyName, @Nullable XmlTag enclosingTag) {
+    if (enclosingTag != null) {
+      final XmlElementDescriptor descriptor = enclosingTag.getDescriptor();
+      if (descriptor != null) {
+        final PsiElement declaration = descriptor.getDeclaration();
+        if (declaration instanceof PsiClass) {
+          PsiClass containingClass = ((PsiClass)declaration);
+          {
+            final Object defaultValue = getDefaultPropertyValue(containingClass.getQualifiedName(), propertyName);
+            if (defaultValue != null) return defaultValue;
+          }
+          final LinkedHashSet<PsiClass> superClasses = InheritanceUtil.getSuperClasses(containingClass);
+          for (PsiClass superClass : superClasses) {
+            final Object defaultValue = getDefaultPropertyValue(superClass.getQualifiedName(), propertyName);
+            if (defaultValue != null) return defaultValue;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  private static boolean isEqualValue(@NotNull String attributeValue, @NotNull Object defaultValue) {
+    if (defaultValue instanceof String && defaultValue.equals(attributeValue)) return true;
+    if (defaultValue instanceof Boolean) return defaultValue == Boolean.valueOf(attributeValue);
+    if (defaultValue instanceof Double) {
+      try {
+        return Double.compare((Double)defaultValue, Double.valueOf(attributeValue)) == 0;
+      }
+      catch (NumberFormatException ignored) {
+        return false;
+      }
+    }
+    if (defaultValue instanceof Integer) {
+      try {
+        return Integer.compare((Integer)defaultValue, Integer.valueOf(attributeValue)) == 0;
+      }
+      catch (NumberFormatException ignored) {
+        return false;
+      }
+    }
+    return false;
+  }
+
+  private static Object getDefaultPropertyValue(String classQualifiedName, String propertyName) {
+    final Map<String, Object> values = getDefaultPropertyValues(classQualifiedName);
+    return values != null ? values.get(propertyName) : null;
+  }
+
+  /**
+   * Load property values config. The config is produced with the script JavaFxGenerateDefaultPropertyValuesScript (can be found in tests)
+   */
+  private static Map<String, Object> getDefaultPropertyValues(String classQualifiedName) {
+    if (ourDefaultPropertyValues == null) {
+      ourDefaultPropertyValues = loadDefaultPropertyValues(JavaFxRedundantPropertyValueInspection.class.getSimpleName() + "8.txt");
+    }
+    Map<String, Map<String, Object>> values = SoftReference.dereference(ourDefaultPropertyValues);
+    return values != null ? values.get(classQualifiedName) : null;
+  }
+
+  /**
+   * The file format is <code>ClassName#propertyName:type=value</code> per line, line with leading double dash (--) is commented out
+   */
+  private static Reference<Map<String, Map<String, Object>>> loadDefaultPropertyValues(String resourceName) {
+    final URL resource = JavaFxRedundantPropertyValueInspection.class.getResource(resourceName);
+    if (resource == null) {
+      LOG.warn("Resource not found: " + resourceName);
+      return null;
+    }
+
+    final Map<String, Map<String, Object>> result = new THashMap<>(200);
+    try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.openStream(), CharsetToolkit.UTF8_CHARSET))) {
+      for (String line : FileUtil.loadLines(reader)) {
+        if (line.isEmpty() || line.startsWith("--")) continue;
+        boolean lineParsed = false;
+        final int p1 = line.indexOf('#');
+        if (p1 > 0 && p1 < line.length()) {
+          final String className = line.substring(0, p1);
+          final int p2 = line.indexOf(':', p1);
+          if (p2 > p1 && p2 < line.length()) {
+            final String propertyName = line.substring(p1 + 1, p2);
+            final int p3 = line.indexOf('=', p2 + 1);
+            if (p3 > 0 && p3 < line.length()) {
+              final String type = line.substring(p2 + 1, p3);
+              final String text = line.substring(p3 + 1);
+              final Object value = parseValue(type, text);
+              if (value != null) {
+                lineParsed = true;
+                final Map<String, Object> properties = result.computeIfAbsent(className, ignored -> new THashMap<String, Object>());
+                if (properties.put(propertyName, value) != null) {
+                  LOG.warn("Duplicate default property value " + line);
+                }
+              }
+            }
+          }
+        }
+        if (!lineParsed) {
+          LOG.warn("Can't parse default property value " + line);
+        }
+      }
+    }
+    catch (IOException e) {
+      LOG.warn("Cannot read resource: " + resourceName, e);
+      return null;
+    }
+
+    return new SoftReference<Map<String, Map<String, Object>>>(result);
+  }
+
+  @Nullable
+  private static Object parseValue(String type, String text) {
+    try {
+      switch (type) {
+        case "Boolean":
+          return Boolean.valueOf(text);
+        case "Integer":
+          return Integer.valueOf(text);
+        case "Double":
+          return Double.valueOf(text);
+        case "String":
+        case "Enum":
+          return text;
+        default:
+          LOG.warn("Unsupported value type " + type + " for '" + text + "'");
+          return null;
+      }
+    }
+    catch (NumberFormatException ignored) {
+      LOG.warn("Invalid format of " + type + ": '" + text + "'");
+      return null;
+    }
+  }
+}
+
diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection8.txt b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection8.txt
new file mode 100644 (file)
index 0000000..5fae741
--- /dev/null
@@ -0,0 +1,677 @@
+--- JavaFX default property values ---
+-------- Collected from sources ---------
+javafx.concurrent.ScheduledService#maximumFailureCount:Integer=2147483647
+javafx.concurrent.ScheduledService#restartOnFailure:Boolean=true
+javafx.scene.Node#accessibleRole:Enum=NODE
+javafx.scene.Node#focusTraversable:Boolean=false
+javafx.scene.Node#nodeOrientation:Enum=INHERIT
+javafx.scene.Node#pickOnBounds:Boolean=false
+javafx.scene.SubScene#height:Double=0.0
+javafx.scene.SubScene#width:Double=0.0
+javafx.scene.chart.AreaChart#createSymbols:Boolean=true
+javafx.scene.chart.Axis#label:String=
+javafx.scene.chart.BarChart#barGap:Double=4.0
+javafx.scene.chart.BarChart#categoryGap:Double=10.0
+javafx.scene.chart.Chart#title:String=
+javafx.scene.chart.LineChart#axisSortingPolicy:Enum=X_AXIS
+javafx.scene.chart.LineChart#createSymbols:Boolean=true
+javafx.scene.chart.StackedAreaChart#createSymbols:Boolean=true
+javafx.scene.chart.StackedBarChart#categoryGap:Double=10.0
+javafx.scene.chart.XYChart#alternativeColumnFillVisible:Boolean=false
+javafx.scene.chart.XYChart#alternativeRowFillVisible:Boolean=true
+javafx.scene.chart.XYChart#horizontalGridLinesVisible:Boolean=true
+javafx.scene.chart.XYChart#horizontalZeroLineVisible:Boolean=true
+javafx.scene.chart.XYChart#verticalGridLinesVisible:Boolean=true
+javafx.scene.chart.XYChart#verticalZeroLineVisible:Boolean=true
+javafx.scene.control.ComboBoxBase#editable:Boolean=false
+javafx.scene.control.CustomMenuItem#hideOnClick:Boolean=true
+javafx.scene.control.Labeled#alignment:Enum=CENTER_LEFT
+javafx.scene.control.Labeled#mnemonicParsing:Boolean=false
+javafx.scene.control.SpinnerValueFactory#wrapAround:Boolean=false
+javafx.scene.control.TableSelectionModel#cellSelectionEnabled:Boolean=false
+javafx.scene.media.AudioClip#balance:Double=0.0
+javafx.scene.media.AudioClip#cycleCount:Integer=1
+javafx.scene.media.AudioClip#pan:Double=0.0
+javafx.scene.media.AudioClip#priority:Integer=0
+javafx.scene.media.AudioClip#rate:Double=1.0
+javafx.scene.media.AudioClip#volume:Double=1.0
+javafx.scene.media.AudioEqualizer#enabled:Boolean=false
+javafx.scene.media.MediaPlayer#audioSpectrumInterval:Double=0.1
+javafx.scene.media.MediaPlayer#audioSpectrumNumBands:Integer=128
+javafx.scene.media.MediaPlayer#audioSpectrumThreshold:Integer=-60
+javafx.scene.media.MediaPlayer#autoPlay:Boolean=false
+javafx.scene.media.MediaPlayer#balance:Double=0.0
+javafx.scene.media.MediaPlayer#cycleCount:Integer=1
+javafx.scene.media.MediaPlayer#mute:Boolean=false
+javafx.scene.media.MediaPlayer#rate:Double=1.0
+javafx.scene.media.MediaPlayer#volume:Double=1.0
+javafx.stage.PopupWindow#anchorLocation:Enum=WINDOW_TOP_LEFT
+javafx.stage.PopupWindow#autoHide:Boolean=false
+javafx.stage.PopupWindow#consumeAutoHidingEvents:Boolean=true
+-------- Shared (not overridden) ---------
+javafx.animation.Animation#autoReverse:Boolean=false
+javafx.animation.Animation#cycleCount:Integer=1
+javafx.animation.Animation#rate:Double=1.0
+javafx.animation.FadeTransition#byValue:Double=0.0
+javafx.animation.FadeTransition#fromValue:Double=NaN
+javafx.animation.FadeTransition#toValue:Double=NaN
+javafx.animation.PathTransition#orientation:Enum=NONE
+javafx.animation.RotateTransition#byAngle:Double=0.0
+javafx.animation.RotateTransition#fromAngle:Double=NaN
+javafx.animation.RotateTransition#toAngle:Double=NaN
+javafx.animation.ScaleTransition#byX:Double=0.0
+javafx.animation.ScaleTransition#byY:Double=0.0
+javafx.animation.ScaleTransition#byZ:Double=0.0
+javafx.animation.ScaleTransition#fromX:Double=NaN
+javafx.animation.ScaleTransition#fromY:Double=NaN
+javafx.animation.ScaleTransition#fromZ:Double=NaN
+javafx.animation.ScaleTransition#toX:Double=NaN
+javafx.animation.ScaleTransition#toY:Double=NaN
+javafx.animation.ScaleTransition#toZ:Double=NaN
+javafx.animation.TranslateTransition#byX:Double=0.0
+javafx.animation.TranslateTransition#byY:Double=0.0
+javafx.animation.TranslateTransition#byZ:Double=0.0
+javafx.animation.TranslateTransition#fromX:Double=NaN
+javafx.animation.TranslateTransition#fromY:Double=NaN
+javafx.animation.TranslateTransition#fromZ:Double=NaN
+javafx.animation.TranslateTransition#toX:Double=NaN
+javafx.animation.TranslateTransition#toY:Double=NaN
+javafx.animation.TranslateTransition#toZ:Double=NaN
+javafx.scene.Camera#farClip:Double=100.0
+javafx.scene.Camera#nearClip:Double=0.1
+javafx.scene.Group#autoSizeChildren:Boolean=true
+javafx.scene.LightBase#lightOn:Boolean=true
+javafx.scene.Node#cache:Boolean=false
+javafx.scene.Node#cacheHint:Enum=DEFAULT
+javafx.scene.Node#depthTest:Enum=INHERIT
+javafx.scene.Node#disable:Boolean=false
+javafx.scene.Node#layoutX:Double=0.0
+javafx.scene.Node#layoutY:Double=0.0
+javafx.scene.Node#managed:Boolean=true
+javafx.scene.Node#mouseTransparent:Boolean=false
+javafx.scene.Node#opacity:Double=1.0
+javafx.scene.Node#rotate:Double=0.0
+javafx.scene.Node#scaleX:Double=1.0
+javafx.scene.Node#scaleY:Double=1.0
+javafx.scene.Node#scaleZ:Double=1.0
+javafx.scene.Node#style:String=
+javafx.scene.Node#translateX:Double=0.0
+javafx.scene.Node#translateY:Double=0.0
+javafx.scene.Node#translateZ:Double=0.0
+javafx.scene.Node#visible:Boolean=true
+javafx.scene.PerspectiveCamera#fieldOfView:Double=30.0
+javafx.scene.PerspectiveCamera#verticalFieldOfView:Boolean=true
+javafx.scene.canvas.Canvas#height:Double=0.0
+javafx.scene.canvas.Canvas#width:Double=0.0
+javafx.scene.chart.Axis#animated:Boolean=true
+javafx.scene.chart.Axis#autoRanging:Boolean=true
+javafx.scene.chart.Axis#tickLabelGap:Double=3.0
+javafx.scene.chart.Axis#tickLabelRotation:Double=0.0
+javafx.scene.chart.Axis#tickLabelsVisible:Boolean=true
+javafx.scene.chart.Axis#tickLength:Double=8.0
+javafx.scene.chart.Axis#tickMarkVisible:Boolean=true
+javafx.scene.chart.Axis$TickMark#position:Double=0.0
+javafx.scene.chart.CategoryAxis#endMargin:Double=5.0
+javafx.scene.chart.CategoryAxis#gapStartAndEnd:Boolean=true
+javafx.scene.chart.CategoryAxis#startMargin:Double=5.0
+javafx.scene.chart.Chart#animated:Boolean=true
+javafx.scene.chart.Chart#legendSide:Enum=BOTTOM
+javafx.scene.chart.Chart#legendVisible:Boolean=true
+javafx.scene.chart.Chart#titleSide:Enum=TOP
+javafx.scene.chart.NumberAxis#forceZeroInRange:Boolean=true
+javafx.scene.chart.NumberAxis#tickUnit:Double=5.0
+javafx.scene.chart.PieChart#clockwise:Boolean=true
+javafx.scene.chart.PieChart#labelLineLength:Double=20.0
+javafx.scene.chart.PieChart#labelsVisible:Boolean=true
+javafx.scene.chart.PieChart#startAngle:Double=0.0
+javafx.scene.chart.ValueAxis#lowerBound:Double=0.0
+javafx.scene.chart.ValueAxis#minorTickCount:Integer=5
+javafx.scene.chart.ValueAxis#minorTickLength:Double=5.0
+javafx.scene.chart.ValueAxis#minorTickVisible:Boolean=true
+javafx.scene.chart.ValueAxis#upperBound:Double=100.0
+javafx.scene.control.Button#cancelButton:Boolean=false
+javafx.scene.control.Button#defaultButton:Boolean=false
+javafx.scene.control.ButtonBar#buttonMinWidth:Double=85.0
+javafx.scene.control.Cell#editable:Boolean=true
+javafx.scene.control.CheckBox#allowIndeterminate:Boolean=false
+javafx.scene.control.CheckBox#indeterminate:Boolean=false
+javafx.scene.control.CheckBox#selected:Boolean=false
+javafx.scene.control.CheckBoxTreeItem#independent:Boolean=false
+javafx.scene.control.CheckBoxTreeItem#indeterminate:Boolean=false
+javafx.scene.control.CheckBoxTreeItem#selected:Boolean=false
+javafx.scene.control.CheckMenuItem#selected:Boolean=false
+javafx.scene.control.ComboBox#visibleRowCount:Integer=10
+javafx.scene.control.ComboBoxBase#promptText:String=
+javafx.scene.control.ContextMenu#impl_showRelativeToWindow:Boolean=false
+javafx.scene.control.DatePicker#showWeekNumbers:Boolean=false
+javafx.scene.control.Dialog#headerText:String=Confirmation
+javafx.scene.control.Dialog#resizable:Boolean=false
+javafx.scene.control.Dialog#title:String=Confirmation
+javafx.scene.control.DialogPane#expanded:Boolean=false
+javafx.scene.control.Hyperlink#visited:Boolean=false
+javafx.scene.control.Labeled#contentDisplay:Enum=LEFT
+javafx.scene.control.Labeled#ellipsisString:String=...
+javafx.scene.control.Labeled#graphicTextGap:Double=4.0
+javafx.scene.control.Labeled#lineSpacing:Double=0.0
+javafx.scene.control.Labeled#text:String=
+javafx.scene.control.Labeled#textAlignment:Enum=LEFT
+javafx.scene.control.Labeled#textOverrun:Enum=ELLIPSIS
+javafx.scene.control.Labeled#underline:Boolean=false
+javafx.scene.control.Labeled#wrapText:Boolean=false
+javafx.scene.control.ListView#editable:Boolean=false
+javafx.scene.control.ListView#fixedCellSize:Double=-1.0
+javafx.scene.control.ListView#orientation:Enum=VERTICAL
+javafx.scene.control.MenuBar#useSystemMenuBar:Boolean=false
+javafx.scene.control.MenuButton#popupSide:Enum=BOTTOM
+javafx.scene.control.MenuItem#disable:Boolean=false
+javafx.scene.control.MenuItem#mnemonicParsing:Boolean=true
+javafx.scene.control.MenuItem#text:String=
+javafx.scene.control.MenuItem#visible:Boolean=true
+javafx.scene.control.Pagination#currentPageIndex:Integer=0
+javafx.scene.control.Pagination#maxPageIndicatorCount:Integer=10
+javafx.scene.control.Pagination#pageCount:Integer=2147483647
+javafx.scene.control.PopupControl#maxHeight:Double=-1.0
+javafx.scene.control.PopupControl#maxWidth:Double=-1.0
+javafx.scene.control.PopupControl#minHeight:Double=-1.0
+javafx.scene.control.PopupControl#minWidth:Double=-1.0
+javafx.scene.control.PopupControl#prefHeight:Double=-1.0
+javafx.scene.control.PopupControl#prefWidth:Double=-1.0
+javafx.scene.control.PopupControl#style:String=
+javafx.scene.control.ProgressIndicator#progress:Double=-1.0
+javafx.scene.control.RadioMenuItem#selected:Boolean=false
+javafx.scene.control.ScrollBar#blockIncrement:Double=10.0
+javafx.scene.control.ScrollBar#max:Double=100.0
+javafx.scene.control.ScrollBar#min:Double=0.0
+javafx.scene.control.ScrollBar#orientation:Enum=HORIZONTAL
+javafx.scene.control.ScrollBar#unitIncrement:Double=1.0
+javafx.scene.control.ScrollBar#value:Double=0.0
+javafx.scene.control.ScrollBar#visibleAmount:Double=15.0
+javafx.scene.control.ScrollPane#fitToHeight:Boolean=false
+javafx.scene.control.ScrollPane#fitToWidth:Boolean=false
+javafx.scene.control.ScrollPane#hbarPolicy:Enum=AS_NEEDED
+javafx.scene.control.ScrollPane#hmax:Double=1.0
+javafx.scene.control.ScrollPane#hmin:Double=0.0
+javafx.scene.control.ScrollPane#hvalue:Double=0.0
+javafx.scene.control.ScrollPane#minViewportHeight:Double=0.0
+javafx.scene.control.ScrollPane#minViewportWidth:Double=0.0
+javafx.scene.control.ScrollPane#pannable:Boolean=false
+javafx.scene.control.ScrollPane#prefViewportHeight:Double=0.0
+javafx.scene.control.ScrollPane#prefViewportWidth:Double=0.0
+javafx.scene.control.ScrollPane#vbarPolicy:Enum=AS_NEEDED
+javafx.scene.control.ScrollPane#vmax:Double=1.0
+javafx.scene.control.ScrollPane#vmin:Double=0.0
+javafx.scene.control.ScrollPane#vvalue:Double=0.0
+javafx.scene.control.Separator#halignment:Enum=CENTER
+javafx.scene.control.Separator#orientation:Enum=HORIZONTAL
+javafx.scene.control.Separator#valignment:Enum=CENTER
+javafx.scene.control.Slider#blockIncrement:Double=10.0
+javafx.scene.control.Slider#majorTickUnit:Double=25.0
+javafx.scene.control.Slider#max:Double=100.0
+javafx.scene.control.Slider#min:Double=0.0
+javafx.scene.control.Slider#minorTickCount:Integer=3
+javafx.scene.control.Slider#orientation:Enum=HORIZONTAL
+javafx.scene.control.Slider#showTickLabels:Boolean=false
+javafx.scene.control.Slider#showTickMarks:Boolean=false
+javafx.scene.control.Slider#snapToTicks:Boolean=false
+javafx.scene.control.Slider#value:Double=0.0
+javafx.scene.control.Slider#valueChanging:Boolean=false
+javafx.scene.control.Spinner#editable:Boolean=false
+javafx.scene.control.SplitPane#orientation:Enum=HORIZONTAL
+javafx.scene.control.SplitPane$Divider#position:Double=0.5
+javafx.scene.control.Tab#closable:Boolean=true
+javafx.scene.control.Tab#disable:Boolean=false
+javafx.scene.control.TabPane#rotateGraphic:Boolean=false
+javafx.scene.control.TabPane#side:Enum=TOP
+javafx.scene.control.TabPane#tabClosingPolicy:Enum=SELECTED_TAB
+javafx.scene.control.TabPane#tabMaxHeight:Double=1.7976931348623157E308
+javafx.scene.control.TabPane#tabMaxWidth:Double=1.7976931348623157E308
+javafx.scene.control.TabPane#tabMinHeight:Double=0.0
+javafx.scene.control.TabPane#tabMinWidth:Double=0.0
+javafx.scene.control.TableColumn#sortType:Enum=ASCENDING
+javafx.scene.control.TableColumnBase#editable:Boolean=true
+javafx.scene.control.TableColumnBase#maxWidth:Double=5000.0
+javafx.scene.control.TableColumnBase#minWidth:Double=10.0
+javafx.scene.control.TableColumnBase#prefWidth:Double=80.0
+javafx.scene.control.TableColumnBase#resizable:Boolean=true
+javafx.scene.control.TableColumnBase#sortable:Boolean=true
+javafx.scene.control.TableColumnBase#style:String=
+javafx.scene.control.TableColumnBase#text:String=
+javafx.scene.control.TableColumnBase#visible:Boolean=true
+javafx.scene.control.TableView#editable:Boolean=false
+javafx.scene.control.TableView#fixedCellSize:Double=-1.0
+javafx.scene.control.TableView#tableMenuButtonVisible:Boolean=false
+javafx.scene.control.TextArea#prefColumnCount:Integer=40
+javafx.scene.control.TextArea#prefRowCount:Integer=10
+javafx.scene.control.TextArea#scrollLeft:Double=0.0
+javafx.scene.control.TextArea#scrollTop:Double=0.0
+javafx.scene.control.TextArea#wrapText:Boolean=false
+javafx.scene.control.TextField#alignment:Enum=CENTER_LEFT
+javafx.scene.control.TextField#prefColumnCount:Integer=12
+javafx.scene.control.TextInputControl#editable:Boolean=true
+javafx.scene.control.TextInputControl#promptText:String=
+javafx.scene.control.TextInputControl#text:String=
+javafx.scene.control.TitledPane#animated:Boolean=true
+javafx.scene.control.TitledPane#collapsible:Boolean=true
+javafx.scene.control.TitledPane#expanded:Boolean=true
+javafx.scene.control.ToggleButton#selected:Boolean=false
+javafx.scene.control.ToolBar#orientation:Enum=HORIZONTAL
+javafx.scene.control.Tooltip#contentDisplay:Enum=LEFT
+javafx.scene.control.Tooltip#graphicTextGap:Double=4.0
+javafx.scene.control.Tooltip#text:String=
+javafx.scene.control.Tooltip#textAlignment:Enum=LEFT
+javafx.scene.control.Tooltip#textOverrun:Enum=ELLIPSIS
+javafx.scene.control.Tooltip#wrapText:Boolean=false
+javafx.scene.control.TreeItem#expanded:Boolean=false
+javafx.scene.control.TreeTableColumn#sortType:Enum=ASCENDING
+javafx.scene.control.TreeTableView#editable:Boolean=false
+javafx.scene.control.TreeTableView#fixedCellSize:Double=-1.0
+javafx.scene.control.TreeTableView#showRoot:Boolean=true
+javafx.scene.control.TreeTableView#sortMode:Enum=ALL_DESCENDANTS
+javafx.scene.control.TreeTableView#tableMenuButtonVisible:Boolean=false
+javafx.scene.control.TreeView#editable:Boolean=false
+javafx.scene.control.TreeView#fixedCellSize:Double=-1.0
+javafx.scene.control.TreeView#showRoot:Boolean=true
+javafx.scene.control.cell.ComboBoxListCell#comboBoxEditable:Boolean=false
+javafx.scene.control.cell.ComboBoxTableCell#comboBoxEditable:Boolean=false
+javafx.scene.control.cell.ComboBoxTreeCell#comboBoxEditable:Boolean=false
+javafx.scene.control.cell.ComboBoxTreeTableCell#comboBoxEditable:Boolean=false
+javafx.scene.effect.Blend#mode:Enum=SRC_OVER
+javafx.scene.effect.Blend#opacity:Double=1.0
+javafx.scene.effect.Bloom#threshold:Double=0.3
+javafx.scene.effect.BoxBlur#height:Double=5.0
+javafx.scene.effect.BoxBlur#iterations:Integer=1
+javafx.scene.effect.BoxBlur#width:Double=5.0
+javafx.scene.effect.ColorAdjust#brightness:Double=0.0
+javafx.scene.effect.ColorAdjust#contrast:Double=0.0
+javafx.scene.effect.ColorAdjust#hue:Double=0.0
+javafx.scene.effect.ColorAdjust#saturation:Double=0.0
+javafx.scene.effect.ColorInput#height:Double=0.0
+javafx.scene.effect.ColorInput#width:Double=0.0
+javafx.scene.effect.ColorInput#x:Double=0.0
+javafx.scene.effect.ColorInput#y:Double=0.0
+javafx.scene.effect.DisplacementMap#offsetX:Double=0.0
+javafx.scene.effect.DisplacementMap#offsetY:Double=0.0
+javafx.scene.effect.DisplacementMap#scaleX:Double=1.0
+javafx.scene.effect.DisplacementMap#scaleY:Double=1.0
+javafx.scene.effect.DisplacementMap#wrap:Boolean=false
+javafx.scene.effect.DropShadow#blurType:Enum=THREE_PASS_BOX
+javafx.scene.effect.DropShadow#height:Double=21.0
+javafx.scene.effect.DropShadow#offsetX:Double=0.0
+javafx.scene.effect.DropShadow#offsetY:Double=0.0
+javafx.scene.effect.DropShadow#radius:Double=10.0
+javafx.scene.effect.DropShadow#spread:Double=0.0
+javafx.scene.effect.DropShadow#width:Double=21.0
+javafx.scene.effect.FloatMap#height:Integer=1
+javafx.scene.effect.FloatMap#width:Integer=1
+javafx.scene.effect.GaussianBlur#radius:Double=10.0
+javafx.scene.effect.Glow#level:Double=0.3
+javafx.scene.effect.ImageInput#x:Double=0.0
+javafx.scene.effect.ImageInput#y:Double=0.0
+javafx.scene.effect.InnerShadow#blurType:Enum=THREE_PASS_BOX
+javafx.scene.effect.InnerShadow#choke:Double=0.0
+javafx.scene.effect.InnerShadow#height:Double=21.0
+javafx.scene.effect.InnerShadow#offsetX:Double=0.0
+javafx.scene.effect.InnerShadow#offsetY:Double=0.0
+javafx.scene.effect.InnerShadow#radius:Double=10.0
+javafx.scene.effect.InnerShadow#width:Double=21.0
+javafx.scene.effect.Light$Distant#azimuth:Double=45.0
+javafx.scene.effect.Light$Distant#elevation:Double=45.0
+javafx.scene.effect.Light$Point#x:Double=0.0
+javafx.scene.effect.Light$Point#y:Double=0.0
+javafx.scene.effect.Light$Point#z:Double=0.0
+javafx.scene.effect.Light$Spot#pointsAtX:Double=0.0
+javafx.scene.effect.Light$Spot#pointsAtY:Double=0.0
+javafx.scene.effect.Light$Spot#pointsAtZ:Double=0.0
+javafx.scene.effect.Light$Spot#specularExponent:Double=1.0
+javafx.scene.effect.Lighting#diffuseConstant:Double=1.0
+javafx.scene.effect.Lighting#specularConstant:Double=0.3
+javafx.scene.effect.Lighting#specularExponent:Double=20.0
+javafx.scene.effect.Lighting#surfaceScale:Double=1.5
+javafx.scene.effect.MotionBlur#angle:Double=0.0
+javafx.scene.effect.MotionBlur#radius:Double=10.0
+javafx.scene.effect.PerspectiveTransform#llx:Double=0.0
+javafx.scene.effect.PerspectiveTransform#lly:Double=0.0
+javafx.scene.effect.PerspectiveTransform#lrx:Double=0.0
+javafx.scene.effect.PerspectiveTransform#lry:Double=0.0
+javafx.scene.effect.PerspectiveTransform#ulx:Double=0.0
+javafx.scene.effect.PerspectiveTransform#uly:Double=0.0
+javafx.scene.effect.PerspectiveTransform#urx:Double=0.0
+javafx.scene.effect.PerspectiveTransform#ury:Double=0.0
+javafx.scene.effect.Reflection#bottomOpacity:Double=0.0
+javafx.scene.effect.Reflection#fraction:Double=0.75
+javafx.scene.effect.Reflection#topOffset:Double=0.0
+javafx.scene.effect.Reflection#topOpacity:Double=0.5
+javafx.scene.effect.SepiaTone#level:Double=1.0
+javafx.scene.effect.Shadow#blurType:Enum=THREE_PASS_BOX
+javafx.scene.effect.Shadow#height:Double=21.0
+javafx.scene.effect.Shadow#radius:Double=10.0
+javafx.scene.effect.Shadow#width:Double=21.0
+javafx.scene.image.ImageView#fitHeight:Double=0.0
+javafx.scene.image.ImageView#fitWidth:Double=0.0
+javafx.scene.image.ImageView#preserveRatio:Boolean=false
+javafx.scene.image.ImageView#smooth:Boolean=true
+javafx.scene.image.ImageView#x:Double=0.0
+javafx.scene.image.ImageView#y:Double=0.0
+javafx.scene.layout.ColumnConstraints#fillWidth:Boolean=true
+javafx.scene.layout.ColumnConstraints#maxWidth:Double=-1.0
+javafx.scene.layout.ColumnConstraints#minWidth:Double=-1.0
+javafx.scene.layout.ColumnConstraints#percentWidth:Double=-1.0
+javafx.scene.layout.ColumnConstraints#prefWidth:Double=-1.0
+javafx.scene.layout.FlowPane#alignment:Enum=TOP_LEFT
+javafx.scene.layout.FlowPane#columnHalignment:Enum=LEFT
+javafx.scene.layout.FlowPane#hgap:Double=0.0
+javafx.scene.layout.FlowPane#orientation:Enum=HORIZONTAL
+javafx.scene.layout.FlowPane#prefWrapLength:Double=400.0
+javafx.scene.layout.FlowPane#rowValignment:Enum=CENTER
+javafx.scene.layout.FlowPane#vgap:Double=0.0
+javafx.scene.layout.GridPane#alignment:Enum=TOP_LEFT
+javafx.scene.layout.GridPane#gridLinesVisible:Boolean=false
+javafx.scene.layout.GridPane#hgap:Double=0.0
+javafx.scene.layout.GridPane#vgap:Double=0.0
+javafx.scene.layout.HBox#alignment:Enum=TOP_LEFT
+javafx.scene.layout.HBox#fillHeight:Boolean=true
+javafx.scene.layout.HBox#spacing:Double=0.0
+javafx.scene.layout.Region#cacheShape:Boolean=true
+javafx.scene.layout.Region#centerShape:Boolean=true
+javafx.scene.layout.Region#maxHeight:Double=-1.0
+javafx.scene.layout.Region#maxWidth:Double=-1.0
+javafx.scene.layout.Region#minHeight:Double=-1.0
+javafx.scene.layout.Region#minWidth:Double=-1.0
+javafx.scene.layout.Region#prefHeight:Double=-1.0
+javafx.scene.layout.Region#prefWidth:Double=-1.0
+javafx.scene.layout.Region#scaleShape:Boolean=true
+javafx.scene.layout.Region#snapToPixel:Boolean=true
+javafx.scene.layout.RowConstraints#fillHeight:Boolean=true
+javafx.scene.layout.RowConstraints#maxHeight:Double=-1.0
+javafx.scene.layout.RowConstraints#minHeight:Double=-1.0
+javafx.scene.layout.RowConstraints#percentHeight:Double=-1.0
+javafx.scene.layout.RowConstraints#prefHeight:Double=-1.0
+javafx.scene.layout.StackPane#alignment:Enum=CENTER
+javafx.scene.layout.TilePane#alignment:Enum=TOP_LEFT
+javafx.scene.layout.TilePane#hgap:Double=0.0
+javafx.scene.layout.TilePane#orientation:Enum=HORIZONTAL
+javafx.scene.layout.TilePane#prefColumns:Integer=5
+javafx.scene.layout.TilePane#prefRows:Integer=5
+javafx.scene.layout.TilePane#prefTileHeight:Double=-1.0
+javafx.scene.layout.TilePane#prefTileWidth:Double=-1.0
+javafx.scene.layout.TilePane#tileAlignment:Enum=CENTER
+javafx.scene.layout.TilePane#vgap:Double=0.0
+javafx.scene.layout.VBox#alignment:Enum=TOP_LEFT
+javafx.scene.layout.VBox#fillWidth:Boolean=true
+javafx.scene.layout.VBox#spacing:Double=0.0
+javafx.scene.media.EqualizerBand#bandwidth:Double=0.0
+javafx.scene.media.EqualizerBand#centerFrequency:Double=0.0
+javafx.scene.media.EqualizerBand#gain:Double=0.0
+javafx.scene.media.MediaView#fitHeight:Double=0.0
+javafx.scene.media.MediaView#fitWidth:Double=0.0
+javafx.scene.media.MediaView#preserveRatio:Boolean=true
+javafx.scene.media.MediaView#smooth:Boolean=true
+javafx.scene.media.MediaView#x:Double=0.0
+javafx.scene.media.MediaView#y:Double=0.0
+javafx.scene.paint.PhongMaterial#specularPower:Double=32.0
+javafx.scene.shape.Arc#centerX:Double=0.0
+javafx.scene.shape.Arc#centerY:Double=0.0
+javafx.scene.shape.Arc#length:Double=0.0
+javafx.scene.shape.Arc#radiusX:Double=0.0
+javafx.scene.shape.Arc#radiusY:Double=0.0
+javafx.scene.shape.Arc#startAngle:Double=0.0
+javafx.scene.shape.Arc#type:Enum=OPEN
+javafx.scene.shape.ArcTo#XAxisRotation:Double=0.0
+javafx.scene.shape.ArcTo#largeArcFlag:Boolean=false
+javafx.scene.shape.ArcTo#radiusX:Double=0.0
+javafx.scene.shape.ArcTo#radiusY:Double=0.0
+javafx.scene.shape.ArcTo#sweepFlag:Boolean=false
+javafx.scene.shape.ArcTo#x:Double=0.0
+javafx.scene.shape.ArcTo#y:Double=0.0
+javafx.scene.shape.Box#depth:Double=2.0
+javafx.scene.shape.Box#height:Double=2.0
+javafx.scene.shape.Box#width:Double=2.0
+javafx.scene.shape.Circle#centerX:Double=0.0
+javafx.scene.shape.Circle#centerY:Double=0.0
+javafx.scene.shape.Circle#radius:Double=0.0
+javafx.scene.shape.CubicCurve#controlX1:Double=0.0
+javafx.scene.shape.CubicCurve#controlX2:Double=0.0
+javafx.scene.shape.CubicCurve#controlY1:Double=0.0
+javafx.scene.shape.CubicCurve#controlY2:Double=0.0
+javafx.scene.shape.CubicCurve#endX:Double=0.0
+javafx.scene.shape.CubicCurve#endY:Double=0.0
+javafx.scene.shape.CubicCurve#startX:Double=0.0
+javafx.scene.shape.CubicCurve#startY:Double=0.0
+javafx.scene.shape.CubicCurveTo#controlX1:Double=0.0
+javafx.scene.shape.CubicCurveTo#controlX2:Double=0.0
+javafx.scene.shape.CubicCurveTo#controlY1:Double=0.0
+javafx.scene.shape.CubicCurveTo#controlY2:Double=0.0
+javafx.scene.shape.CubicCurveTo#x:Double=0.0
+javafx.scene.shape.CubicCurveTo#y:Double=0.0
+javafx.scene.shape.Cylinder#height:Double=2.0
+javafx.scene.shape.Cylinder#radius:Double=1.0
+javafx.scene.shape.Ellipse#centerX:Double=0.0
+javafx.scene.shape.Ellipse#centerY:Double=0.0
+javafx.scene.shape.Ellipse#radiusX:Double=0.0
+javafx.scene.shape.Ellipse#radiusY:Double=0.0
+javafx.scene.shape.HLineTo#x:Double=0.0
+javafx.scene.shape.Line#endX:Double=0.0
+javafx.scene.shape.Line#endY:Double=0.0
+javafx.scene.shape.Line#startX:Double=0.0
+javafx.scene.shape.Line#startY:Double=0.0
+javafx.scene.shape.LineTo#x:Double=0.0
+javafx.scene.shape.LineTo#y:Double=0.0
+javafx.scene.shape.MoveTo#x:Double=0.0
+javafx.scene.shape.MoveTo#y:Double=0.0
+javafx.scene.shape.Path#fillRule:Enum=NON_ZERO
+javafx.scene.shape.PathElement#absolute:Boolean=true
+javafx.scene.shape.QuadCurve#controlX:Double=0.0
+javafx.scene.shape.QuadCurve#controlY:Double=0.0
+javafx.scene.shape.QuadCurve#endX:Double=0.0
+javafx.scene.shape.QuadCurve#endY:Double=0.0
+javafx.scene.shape.QuadCurve#startX:Double=0.0
+javafx.scene.shape.QuadCurve#startY:Double=0.0
+javafx.scene.shape.QuadCurveTo#controlX:Double=0.0
+javafx.scene.shape.QuadCurveTo#controlY:Double=0.0
+javafx.scene.shape.QuadCurveTo#x:Double=0.0
+javafx.scene.shape.QuadCurveTo#y:Double=0.0
+javafx.scene.shape.Rectangle#arcHeight:Double=0.0
+javafx.scene.shape.Rectangle#arcWidth:Double=0.0
+javafx.scene.shape.Rectangle#height:Double=0.0
+javafx.scene.shape.Rectangle#width:Double=0.0
+javafx.scene.shape.Rectangle#x:Double=0.0
+javafx.scene.shape.Rectangle#y:Double=0.0
+javafx.scene.shape.SVGPath#content:String=
+javafx.scene.shape.SVGPath#fillRule:Enum=NON_ZERO
+javafx.scene.shape.Shape#smooth:Boolean=true
+javafx.scene.shape.Shape#strokeDashOffset:Double=0.0
+javafx.scene.shape.Shape#strokeLineCap:Enum=SQUARE
+javafx.scene.shape.Shape#strokeLineJoin:Enum=MITER
+javafx.scene.shape.Shape#strokeMiterLimit:Double=10.0
+javafx.scene.shape.Shape#strokeType:Enum=CENTERED
+javafx.scene.shape.Shape#strokeWidth:Double=1.0
+javafx.scene.shape.Shape3D#cullFace:Enum=BACK
+javafx.scene.shape.Shape3D#drawMode:Enum=FILL
+javafx.scene.shape.Sphere#radius:Double=1.0
+javafx.scene.shape.VLineTo#y:Double=0.0
+javafx.scene.text.Text#boundsType:Enum=LOGICAL
+javafx.scene.text.Text#fontSmoothingType:Enum=GRAY
+javafx.scene.text.Text#impl_caretBias:Boolean=true
+javafx.scene.text.Text#impl_caretPosition:Integer=-1
+javafx.scene.text.Text#impl_selectionEnd:Integer=-1
+javafx.scene.text.Text#impl_selectionStart:Integer=-1
+javafx.scene.text.Text#lineSpacing:Double=0.0
+javafx.scene.text.Text#strikethrough:Boolean=false
+javafx.scene.text.Text#text:String=
+javafx.scene.text.Text#textAlignment:Enum=LEFT
+javafx.scene.text.Text#textOrigin:Enum=BASELINE
+javafx.scene.text.Text#underline:Boolean=false
+javafx.scene.text.Text#wrappingWidth:Double=0.0
+javafx.scene.text.Text#x:Double=0.0
+javafx.scene.text.Text#y:Double=0.0
+javafx.scene.text.TextFlow#lineSpacing:Double=0.0
+javafx.scene.text.TextFlow#textAlignment:Enum=LEFT
+javafx.scene.transform.Affine#mxx:Double=1.0
+javafx.scene.transform.Affine#mxy:Double=0.0
+javafx.scene.transform.Affine#mxz:Double=0.0
+javafx.scene.transform.Affine#myx:Double=0.0
+javafx.scene.transform.Affine#myy:Double=1.0
+javafx.scene.transform.Affine#myz:Double=0.0
+javafx.scene.transform.Affine#mzx:Double=0.0
+javafx.scene.transform.Affine#mzy:Double=0.0
+javafx.scene.transform.Affine#mzz:Double=1.0
+javafx.scene.transform.Affine#tx:Double=0.0
+javafx.scene.transform.Affine#ty:Double=0.0
+javafx.scene.transform.Affine#tz:Double=0.0
+javafx.scene.transform.Rotate#angle:Double=0.0
+javafx.scene.transform.Rotate#pivotX:Double=0.0
+javafx.scene.transform.Rotate#pivotY:Double=0.0
+javafx.scene.transform.Rotate#pivotZ:Double=0.0
+javafx.scene.transform.Scale#pivotX:Double=0.0
+javafx.scene.transform.Scale#pivotY:Double=0.0
+javafx.scene.transform.Scale#pivotZ:Double=0.0
+javafx.scene.transform.Scale#x:Double=1.0
+javafx.scene.transform.Scale#y:Double=1.0
+javafx.scene.transform.Scale#z:Double=1.0
+javafx.scene.transform.Shear#pivotX:Double=0.0
+javafx.scene.transform.Shear#pivotY:Double=0.0
+javafx.scene.transform.Shear#x:Double=0.0
+javafx.scene.transform.Shear#y:Double=0.0
+javafx.scene.transform.Translate#x:Double=0.0
+javafx.scene.transform.Translate#y:Double=0.0
+javafx.scene.transform.Translate#z:Double=0.0
+javafx.scene.web.WebEngine#javaScriptEnabled:Boolean=true
+javafx.scene.web.WebView#contextMenuEnabled:Boolean=true
+javafx.scene.web.WebView#fontScale:Double=1.0
+javafx.scene.web.WebView#fontSmoothingType:Enum=LCD
+javafx.scene.web.WebView#maxHeight:Double=1.7976931348623157E308
+javafx.scene.web.WebView#maxWidth:Double=1.7976931348623157E308
+javafx.scene.web.WebView#minHeight:Double=0.0
+javafx.scene.web.WebView#minWidth:Double=0.0
+javafx.scene.web.WebView#prefHeight:Double=600.0
+javafx.scene.web.WebView#prefWidth:Double=800.0
+javafx.scene.web.WebView#zoom:Double=1.0
+javafx.stage.PopupWindow#autoFix:Boolean=true
+javafx.stage.PopupWindow#hideOnEscape:Boolean=true
+javafx.stage.Stage#maxHeight:Double=1.7976931348623157E308
+javafx.stage.Stage#maxWidth:Double=1.7976931348623157E308
+javafx.stage.Stage#minHeight:Double=0.0
+javafx.stage.Stage#minWidth:Double=0.0
+javafx.stage.Stage#resizable:Boolean=true
+javafx.stage.Window#opacity:Double=1.0
+-------- Overridden in subclass ---------
+javafx.embed.swing.SwingNode#focusTraversable:Boolean=true
+javafx.scene.Group#accessibleRole:Enum=PARENT
+javafx.scene.canvas.Canvas#nodeOrientation:Enum=LEFT_TO_RIGHT
+javafx.scene.control.Button#accessibleRole:Enum=BUTTON
+javafx.scene.control.Button#focusTraversable:Boolean=true
+javafx.scene.control.Button#mnemonicParsing:Boolean=true
+javafx.scene.control.CheckBox#accessibleRole:Enum=CHECK_BOX
+javafx.scene.control.CheckBox#focusTraversable:Boolean=true
+javafx.scene.control.CheckBox#mnemonicParsing:Boolean=true
+javafx.scene.control.ChoiceBox#accessibleRole:Enum=COMBO_BOX
+javafx.scene.control.ChoiceBox#focusTraversable:Boolean=true
+javafx.scene.control.ColorPicker#focusTraversable:Boolean=true
+javafx.scene.control.ComboBox#accessibleRole:Enum=COMBO_BOX
+javafx.scene.control.ComboBox#focusTraversable:Boolean=true
+javafx.scene.control.ContextMenu#autoHide:Boolean=true
+javafx.scene.control.ContextMenu#consumeAutoHidingEvents:Boolean=false
+javafx.scene.control.DatePicker#accessibleRole:Enum=DATE_PICKER
+javafx.scene.control.DatePicker#editable:Boolean=true
+javafx.scene.control.DatePicker#focusTraversable:Boolean=true
+javafx.scene.control.Hyperlink#accessibleRole:Enum=HYPERLINK
+javafx.scene.control.Hyperlink#focusTraversable:Boolean=true
+javafx.scene.control.Label#accessibleRole:Enum=TEXT
+javafx.scene.control.ListCell#accessibleRole:Enum=LIST_ITEM
+javafx.scene.control.ListView#accessibleRole:Enum=LIST_VIEW
+javafx.scene.control.ListView#focusTraversable:Boolean=true
+javafx.scene.control.MenuBar#accessibleRole:Enum=MENU_BAR
+javafx.scene.control.MenuButton#accessibleRole:Enum=MENU_BUTTON
+javafx.scene.control.MenuButton#focusTraversable:Boolean=true
+javafx.scene.control.MenuButton#mnemonicParsing:Boolean=true
+javafx.scene.control.Pagination#accessibleRole:Enum=PAGINATION
+javafx.scene.control.Pagination#focusTraversable:Boolean=true
+javafx.scene.control.PasswordField#accessibleRole:Enum=PASSWORD_FIELD
+javafx.scene.control.PopupControl#anchorLocation:Enum=CONTENT_TOP_LEFT
+javafx.scene.control.ProgressIndicator#accessibleRole:Enum=PROGRESS_INDICATOR
+javafx.scene.control.RadioButton#accessibleRole:Enum=RADIO_BUTTON
+javafx.scene.control.RadioButton#alignment:Enum=CENTER_LEFT
+javafx.scene.control.ScrollBar#accessibleRole:Enum=SCROLL_BAR
+javafx.scene.control.ScrollPane#accessibleRole:Enum=SCROLL_PANE
+javafx.scene.control.SeparatorMenuItem#hideOnClick:Boolean=false
+javafx.scene.control.Slider#accessibleRole:Enum=SLIDER
+javafx.scene.control.Slider#focusTraversable:Boolean=true
+javafx.scene.control.Spinner#accessibleRole:Enum=SPINNER
+javafx.scene.control.Spinner#focusTraversable:Boolean=true
+javafx.scene.control.SplitMenuButton#accessibleRole:Enum=SPLIT_MENU_BUTTON
+javafx.scene.control.TabPane#accessibleRole:Enum=TAB_PANE
+javafx.scene.control.TabPane#focusTraversable:Boolean=true
+javafx.scene.control.TableCell#accessibleRole:Enum=TABLE_CELL
+javafx.scene.control.TableRow#accessibleRole:Enum=TABLE_ROW
+javafx.scene.control.TableView#accessibleRole:Enum=TABLE_VIEW
+javafx.scene.control.TableView#focusTraversable:Boolean=true
+javafx.scene.control.TextArea#accessibleRole:Enum=TEXT_AREA
+javafx.scene.control.TextArea#focusTraversable:Boolean=true
+javafx.scene.control.TextField#accessibleRole:Enum=TEXT_FIELD
+javafx.scene.control.TextField#focusTraversable:Boolean=true
+javafx.scene.control.TitledPane#accessibleRole:Enum=TITLED_PANE
+javafx.scene.control.TitledPane#focusTraversable:Boolean=true
+javafx.scene.control.ToggleButton#accessibleRole:Enum=TOGGLE_BUTTON
+javafx.scene.control.ToggleButton#alignment:Enum=CENTER
+javafx.scene.control.ToggleButton#focusTraversable:Boolean=true
+javafx.scene.control.ToggleButton#mnemonicParsing:Boolean=true
+javafx.scene.control.ToolBar#accessibleRole:Enum=TOOL_BAR
+javafx.scene.control.TreeCell#accessibleRole:Enum=TREE_ITEM
+javafx.scene.control.TreeTableCell#accessibleRole:Enum=TREE_TABLE_CELL
+javafx.scene.control.TreeTableRow#accessibleRole:Enum=TREE_TABLE_ROW
+javafx.scene.control.TreeTableView#accessibleRole:Enum=TREE_TABLE_VIEW
+javafx.scene.control.TreeTableView#focusTraversable:Boolean=true
+javafx.scene.control.TreeView#accessibleRole:Enum=TREE_VIEW
+javafx.scene.control.TreeView#focusTraversable:Boolean=true
+javafx.scene.control.cell.CheckBoxTreeCell#accessibleRole:Enum=TREE_ITEM
+javafx.scene.control.cell.CheckBoxTreeCell#alignment:Enum=CENTER_LEFT
+javafx.scene.control.cell.CheckBoxTreeCell#focusTraversable:Boolean=false
+javafx.scene.control.cell.CheckBoxTreeCell#mnemonicParsing:Boolean=false
+javafx.scene.control.cell.CheckBoxTreeCell#nodeOrientation:Enum=INHERIT
+javafx.scene.control.cell.CheckBoxTreeCell#pickOnBounds:Boolean=true
+javafx.scene.control.cell.ChoiceBoxTreeCell#accessibleRole:Enum=TREE_ITEM
+javafx.scene.control.cell.ChoiceBoxTreeCell#alignment:Enum=CENTER_LEFT
+javafx.scene.control.cell.ChoiceBoxTreeCell#focusTraversable:Boolean=false
+javafx.scene.control.cell.ChoiceBoxTreeCell#mnemonicParsing:Boolean=false
+javafx.scene.control.cell.ChoiceBoxTreeCell#nodeOrientation:Enum=INHERIT
+javafx.scene.control.cell.ChoiceBoxTreeCell#pickOnBounds:Boolean=true
+javafx.scene.control.cell.ComboBoxTreeCell#accessibleRole:Enum=TREE_ITEM
+javafx.scene.control.cell.ComboBoxTreeCell#alignment:Enum=CENTER_LEFT
+javafx.scene.control.cell.ComboBoxTreeCell#focusTraversable:Boolean=false
+javafx.scene.control.cell.ComboBoxTreeCell#mnemonicParsing:Boolean=false
+javafx.scene.control.cell.ComboBoxTreeCell#nodeOrientation:Enum=INHERIT
+javafx.scene.control.cell.ComboBoxTreeCell#pickOnBounds:Boolean=true
+javafx.scene.control.cell.TextFieldTreeCell#accessibleRole:Enum=TREE_ITEM
+javafx.scene.control.cell.TextFieldTreeCell#alignment:Enum=CENTER_LEFT
+javafx.scene.control.cell.TextFieldTreeCell#focusTraversable:Boolean=false
+javafx.scene.control.cell.TextFieldTreeCell#mnemonicParsing:Boolean=false
+javafx.scene.control.cell.TextFieldTreeCell#nodeOrientation:Enum=INHERIT
+javafx.scene.control.cell.TextFieldTreeCell#pickOnBounds:Boolean=true
+javafx.scene.image.ImageView#accessibleRole:Enum=IMAGE_VIEW
+javafx.scene.image.ImageView#nodeOrientation:Enum=LEFT_TO_RIGHT
+javafx.scene.layout.Region#accessibleRole:Enum=PARENT
+javafx.scene.layout.Region#pickOnBounds:Boolean=true
+javafx.scene.media.MediaView#nodeOrientation:Enum=LEFT_TO_RIGHT
+javafx.scene.text.Text#accessibleRole:Enum=TEXT
+javafx.scene.text.Text#pickOnBounds:Boolean=true
+javafx.scene.text.TextFlow#accessibleRole:Enum=TEXT
+javafx.scene.web.HTMLEditor#focusTraversable:Boolean=true
+javafx.scene.web.WebView#accessibleRole:Enum=PARENT
+javafx.scene.web.WebView#focusTraversable:Boolean=true
+javafx.scene.web.WebView#nodeOrientation:Enum=LEFT_TO_RIGHT
+-------- Overridden properties' values ---------
+-- javafx.scene.Node#accessibleRole[BUTTON, CHECK_BOX, COMBO_BOX, DATE_PICKER, HYPERLINK, IMAGE_VIEW, LIST_ITEM, LIST_VIEW, MENU_BAR, MENU_BUTTON, NODE, PAGINATION, PARENT, PASSWORD_FIELD, PROGRESS_INDICATOR, RADIO_BUTTON, SCROLL_BAR, SCROLL_PANE, SLIDER, SPINNER, SPLIT_MENU_BUTTON, TABLE_CELL, TABLE_ROW, TABLE_VIEW, TAB_PANE, TEXT, TEXT_AREA, TEXT_FIELD, TITLED_PANE, TOGGLE_BUTTON, TOOL_BAR, TREE_ITEM, TREE_TABLE_CELL, TREE_TABLE_ROW, TREE_TABLE_VIEW, TREE_VIEW]
+-- javafx.scene.Node#focusTraversable[false, true]
+-- javafx.scene.Node#nodeOrientation[INHERIT, LEFT_TO_RIGHT]
+-- javafx.scene.Node#pickOnBounds[false, true]
+-- javafx.scene.control.ComboBoxBase#editable[false, true]
+-- javafx.scene.control.CustomMenuItem#hideOnClick[false, true]
+-- javafx.scene.control.Labeled#alignment[CENTER, CENTER_LEFT]
+-- javafx.scene.control.Labeled#mnemonicParsing[false, true]
+-- javafx.stage.PopupWindow#anchorLocation[CONTENT_TOP_LEFT, WINDOW_TOP_LEFT]
+-- javafx.stage.PopupWindow#autoHide[false, true]
+-- javafx.stage.PopupWindow#consumeAutoHidingEvents[false, true]
+-------- Skipped properties ---------
+-- javafx.scene.web.WebEngine#userAgent
+-- javafx.scene.web.HTMLEditor#htmlText
+-- javafx.scene.control.ButtonBar#buttonOrder
diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/RemoveTagFix.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/RemoveTagFix.java
new file mode 100644 (file)
index 0000000..0e97afd
--- /dev/null
@@ -0,0 +1,61 @@
+package org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections;
+
+import com.intellij.codeInsight.FileModificationService;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleManager;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.xml.XmlTag;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.javaFX.fxml.JavaFxFileTypeFactory;
+
+/**
+ * @author Pavel.Dolgov
+ */
+public class RemoveTagFix implements LocalQuickFix {
+  private static final Logger LOG = Logger.getInstance("#" + RemoveTagFix.class.getName());
+
+  private final String myTagName;
+
+  public RemoveTagFix(String name) {
+    myTagName = name;
+  }
+
+  @Nls
+  @NotNull
+  @Override
+  public String getName() {
+    return "Remove tag '" + myTagName + "'";
+  }
+
+  @Nls
+  @NotNull
+  @Override
+  public String getFamilyName() {
+    return "Remove tag";
+  }
+
+  @Override
+  public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+    final PsiElement element = descriptor.getPsiElement();
+    if (element != null) {
+      final PsiFile containingFile = element.getContainingFile();
+      LOG.assertTrue(containingFile != null && JavaFxFileTypeFactory.isFxml(containingFile),
+                     containingFile == null ? "no containing file found" : "containing file: " + containingFile.getName());
+      final XmlTag xmlTag = PsiTreeUtil.getParentOfType(element, XmlTag.class, false);
+      if (xmlTag != null) {
+        final XmlTag parentTag = xmlTag.getParentTag();
+        if (!FileModificationService.getInstance().preparePsiElementsForWrite(element)) return;
+        xmlTag.delete();
+        if (parentTag != null) {
+          CodeStyleManager.getInstance(project).reformat(parentTag);
+        }
+      }
+    }
+  }
+}
diff --git a/plugins/javaFX/testData/inspections/redundantValue/attributeHighlighting.fxml b/plugins/javaFX/testData/inspections/redundantValue/attributeHighlighting.fxml
new file mode 100644 (file)
index 0000000..0b1bc41
--- /dev/null
@@ -0,0 +1,11 @@
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.control.Label?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          <warning descr="Attribute is redundant because it contains default value">maxHeight="-1"</warning>
+          maxWidth="500"
+          <warning descr="Attribute is redundant because it contains default value">vgap="0"</warning>
+          hgap="1"
+          <warning descr="Attribute is redundant because it contains default value">cache="false"</warning>
+          opacity="0.99">
+    <Label text="Hi" alignment="TOP_LEFT"/>
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/immediateAttribute.fxml b/plugins/javaFX/testData/inspections/redundantValue/immediateAttribute.fxml
new file mode 100644 (file)
index 0000000..d0590a9
--- /dev/null
@@ -0,0 +1,8 @@
+<?import javafx.scene.layout.GridPane?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          maxHeight="-1"
+          minHeight="-Infinity"
+          alignm<caret>ent="TOP_LEFT"
+          prefHeight="400.0"
+          prefWidth="600.0">
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/immediateAttribute_after.fxml b/plugins/javaFX/testData/inspections/redundantValue/immediateAttribute_after.fxml
new file mode 100644 (file)
index 0000000..d2064eb
--- /dev/null
@@ -0,0 +1,7 @@
+<?import javafx.scene.layout.GridPane?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          maxHeight="-1"
+          minHeight="-Infinity"
+          prefHeight="400.0"
+          prefWidth="600.0">
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/immediateTag.fxml b/plugins/javaFX/testData/inspections/redundantValue/immediateTag.fxml
new file mode 100644 (file)
index 0000000..05fce21
--- /dev/null
@@ -0,0 +1,12 @@
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.control.Label?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          maxHeight="-1"
+          minHeight="-Infinity"
+          prefHeight="400.0"
+          prefWidth="600.0">
+  <alignm<caret>ent>TOP_LEFT</alignment>
+  <Label text="Hi">
+    <alignment>TOP_LEFT</alignment>
+  </Label>
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/immediateTag_after.fxml b/plugins/javaFX/testData/inspections/redundantValue/immediateTag_after.fxml
new file mode 100644 (file)
index 0000000..da5fe05
--- /dev/null
@@ -0,0 +1,11 @@
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.control.Label?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          maxHeight="-1"
+          minHeight="-Infinity"
+          prefHeight="400.0"
+          prefWidth="600.0">
+    <Label text="Hi">
+        <alignment>TOP_LEFT</alignment>
+    </Label>
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/inheritedAttribute.fxml b/plugins/javaFX/testData/inspections/redundantValue/inheritedAttribute.fxml
new file mode 100644 (file)
index 0000000..6f07a3d
--- /dev/null
@@ -0,0 +1,9 @@
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.control.Label?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          maxHei<caret>ght="-1"
+          minHeight="-Infinity"
+          alignment="TOP_LEFT"
+          prefHeight="400.0"
+          prefWidth="600.0">
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/inheritedAttribute_after.fxml b/plugins/javaFX/testData/inspections/redundantValue/inheritedAttribute_after.fxml
new file mode 100644 (file)
index 0000000..39056fe
--- /dev/null
@@ -0,0 +1,8 @@
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.control.Label?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          minHeight="-Infinity"
+          alignment="TOP_LEFT"
+          prefHeight="400.0"
+          prefWidth="600.0">
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/inheritedTag.fxml b/plugins/javaFX/testData/inspections/redundantValue/inheritedTag.fxml
new file mode 100644 (file)
index 0000000..353c3a6
--- /dev/null
@@ -0,0 +1,15 @@
+<?import javafx.scene.layout.GridPane?>
+<GridPane xmlns:fx="http://javafx.com/fxml">
+    <hgap>1</hgap>
+    <vgap>0</vgap>
+    <minWidth>
+      100
+    </minWidth>
+    <minHeight>
+      -1
+    </minHeight>
+    <maxWidth>500</maxWidth>
+    <maxHe<caret>ight>-1</maxHeight>
+    <opacity>0.99</opacity>
+    <cache>false</cache>
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/inheritedTag_after.fxml b/plugins/javaFX/testData/inspections/redundantValue/inheritedTag_after.fxml
new file mode 100644 (file)
index 0000000..5502aa3
--- /dev/null
@@ -0,0 +1,14 @@
+<?import javafx.scene.layout.GridPane?>
+<GridPane xmlns:fx="http://javafx.com/fxml">
+    <hgap>1</hgap>
+    <vgap>0</vgap>
+    <minWidth>
+        100
+    </minWidth>
+    <minHeight>
+        -1
+    </minHeight>
+    <maxWidth>500</maxWidth>
+    <opacity>0.99</opacity>
+    <cache>false</cache>
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/modifiedAttribute.fxml b/plugins/javaFX/testData/inspections/redundantValue/modifiedAttribute.fxml
new file mode 100644 (file)
index 0000000..e748266
--- /dev/null
@@ -0,0 +1,8 @@
+<?import javafx.scene.layout.GridPane?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          maxHeight="-1"
+          minHeight="-Infinity"
+          alignm<caret>ent="CENTER"
+          prefHeight="400.0"
+          prefWidth="600.0">
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/modifiedTag.fxml b/plugins/javaFX/testData/inspections/redundantValue/modifiedTag.fxml
new file mode 100644 (file)
index 0000000..d857853
--- /dev/null
@@ -0,0 +1,12 @@
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.control.Label?>
+<GridPane xmlns:fx="http://javafx.com/fxml"
+          maxHeight="-1"
+          minHeight="-Infinity"
+          prefHeight="400.0"
+          prefWidth="600.0">
+    <alignm<caret>ent>CENTER</alignment>
+    <Label text="Hi">
+        <alignment>TOP_LEFT</alignment>
+    </Label>
+</GridPane>
\ No newline at end of file
diff --git a/plugins/javaFX/testData/inspections/redundantValue/tagHighlighting.fxml b/plugins/javaFX/testData/inspections/redundantValue/tagHighlighting.fxml
new file mode 100644 (file)
index 0000000..66d15f7
--- /dev/null
@@ -0,0 +1,19 @@
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.control.Label?>
+<GridPane xmlns:fx="http://javafx.com/fxml">
+  <minWidth>
+    100
+  </minWidth>
+  <warning descr="Tag is redundant because it contains default value"><minHeight>
+    -1
+  </minHeight></warning>
+  <maxWidth>500</maxWidth>
+  <warning descr="Tag is redundant because it contains default value"><maxHeight>-1</maxHeight></warning>
+  <hgap>1</hgap>
+  <warning descr="Tag is redundant because it contains default value"><vgap>0</vgap></warning>
+  <opacity>0.99</opacity>
+  <warning descr="Tag is redundant because it contains default value"><cache>false</cache></warning>
+  <Label text="Hi">
+    <alignment>TOP_LEFT</alignment>
+  </Label>
+</GridPane>
\ No newline at end of file