Display metrics in node info section

This commit is contained in:
Clément Fournier
2017-09-07 22:52:03 +02:00
parent 68cb110491
commit 61c98d25cb
9 changed files with 303 additions and 97 deletions

View File

@ -31,5 +31,10 @@
<artifactId>richtextfx</artifactId>
<version>0.6.10</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-apex</artifactId>
<version>6.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -18,6 +18,7 @@ import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery;
import net.sourceforge.pmd.util.fxdesigner.model.ASTManager;
import net.sourceforge.pmd.util.fxdesigner.model.MetricResult;
import net.sourceforge.pmd.util.fxdesigner.model.ParseTimeException;
import net.sourceforge.pmd.util.fxdesigner.model.XPathEvaluationException;
import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil;
@ -28,6 +29,7 @@ import net.sourceforge.pmd.util.fxdesigner.view.DesignerWindow;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.Alert;
@ -38,6 +40,7 @@ import javafx.scene.control.RadioMenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
/**
@ -66,6 +69,7 @@ public class DesignerWindowPresenter {
initializeLanguageVersionMenu();
initializeASTTreeView();
initializeXPath();
initialiseNodeInfoSection();
bindModelToView();
try {
@ -109,6 +113,11 @@ public class DesignerWindowPresenter {
}
private void initialiseNodeInfoSection() {
view.getMetricResultsListView().setCellFactory(param -> new MetricResultListCell());
}
private void initializeXPath() {
ToggleGroup xpathVersionToggleGroup = view.getXpathVersionToggleGroup();
@ -136,13 +145,20 @@ public class DesignerWindowPresenter {
TreeView<Node> astTreeView = view.getAstTreeView();
astTreeView.setCellFactory(param -> new ASTTreeCell());
astTreeView.getSelectionModel()
.selectedItemProperty()
.addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
onNodeItemSelected(newValue.getValue());
}
});
ReadOnlyObjectProperty<TreeItem<Node>> selectedItemProperty
= astTreeView.getSelectionModel().selectedItemProperty();
selectedItemProperty.addListener(observable -> {
view.getMetricResultsListView().getItems().clear();
view.getXpathAttributesListView().getItems().clear();
});
selectedItemProperty.addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
onNodeItemSelected(newValue.getValue());
}
});
}
@ -152,6 +168,14 @@ public class DesignerWindowPresenter {
ObservableList<String> atts = DesignerUtil.getAttributes(selectedValue);
view.getXpathAttributesListView().setItems(atts);
ObservableList<MetricResult> metrics = model.evaluateAllMetrics(selectedValue);
view.getMetricResultsListView().setItems(metrics);
view.notifyMetricsAvailable(metrics.stream()
.map(MetricResult::getValue)
.filter(result -> !result.isNaN())
.count());
DesignerUtil.highlightNode(view.getCodeEditorArea(), selectedValue);
}
}

View File

@ -0,0 +1,45 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util.fxdesigner;
import java.util.Locale;
import net.sourceforge.pmd.util.fxdesigner.model.MetricResult;
import javafx.scene.control.ListCell;
/**
* List cell for a metric result.
*
* @author Clément Fournier
* @since 6.0.0
*/
public class MetricResultListCell extends ListCell<MetricResult> {
@Override
protected void updateItem(MetricResult item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
setText(item.getKey().name() + " = " + niceDoubleString(item.getValue()));
}
}
/** Gets a nice string representation of a double. */
private String niceDoubleString(double val) {
if (val == (int) val) {
return String.valueOf((int) val);
} else {
return String.format(Locale.ROOT, "%.4f", val);
}
}
}

View File

@ -38,9 +38,12 @@ public class ASTManager {
/** Selected language version. */
private ObjectProperty<LanguageVersion> languageVersion = new SimpleObjectProperty<>();
/** Evaluates XPath queries and stores the results. */
/** Evaluates XPath queries. */
private XPathEvaluator xpathEvaluator = new XPathEvaluator();
/** Evaluates metrics on a node. */
private MetricEvaluator metricEvaluator = new MetricEvaluator();
public LanguageVersion getLanguageVersion() {
return languageVersion.get();
@ -62,6 +65,22 @@ public class ASTManager {
}
/**
* Evaluates all available metrics for that node.
*
* @param n Node
*
* @return A list of all the metric results that could be computed, possibly with some Double.NaN results
*/
public ObservableList<MetricResult> evaluateAllMetrics(Node n) {
try {
return FXCollections.observableArrayList(metricEvaluator.evaluateAllMetrics(n));
} catch (UnsupportedOperationException e) {
return FXCollections.emptyObservableList();
}
}
/**
* Evaluates an XPath request, returns the matching nodes.
*
@ -94,6 +113,7 @@ public class ASTManager {
Node node = parser.parse(null, new StringReader(source));
languageVersionHandler.getSymbolFacade().start(node);
languageVersionHandler.getTypeResolutionFacade(ASTManager.class.getClassLoader()).start(node);
languageVersionHandler.getMetricsVisitorFacade().start(node);
compilationUnit = node;
lastValidSource = source;
lastLanguageVersion = languageVersion.get();

View File

@ -0,0 +1,92 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util.fxdesigner.model;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
import net.sourceforge.pmd.lang.apex.ast.ASTUserClass;
import net.sourceforge.pmd.lang.apex.metrics.ApexMetrics;
import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey;
import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.metrics.JavaMetrics;
import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
/**
* Evaluates metrics.
*
* @author Clément Fournier
* @since 6.0.0
*/
class MetricEvaluator {
/**
* Evaluates all available metrics and returns a list of results.
*
* @param node Node
*
* @return List of all metric results (metric key + result), including NaN results
*
* @throws UnsupportedOperationException If no metrics are available for this node
*/
List<MetricResult> evaluateAllMetrics(Node node) throws UnsupportedOperationException {
if (ASTAnyTypeDeclaration.class.isInstance(node)) {
return evaluateAllMetrics((ASTAnyTypeDeclaration) node);
} else if (ASTMethodOrConstructorDeclaration.class.isInstance(node)) {
return evaluateAllMetrics((ASTMethodOrConstructorDeclaration) node);
} else if (ASTMethod.class.isInstance(node)) {
return evaluateAllMetrics((ASTMethod) node);
} else if (ASTUserClass.class.isInstance(node)) {
return evaluateAllMetrics((ASTUserClass) node);
}
throw new UnsupportedOperationException("That language does not support metrics");
}
private List<MetricResult> evaluateAllMetrics(ASTMethodOrConstructorDeclaration node) {
List<MetricResult> metricResults = new ArrayList<>();
for (JavaOperationMetricKey key : JavaOperationMetricKey.values()) {
metricResults.add(new MetricResult(key, JavaMetrics.get(key, node)));
}
return metricResults;
}
private List<MetricResult> evaluateAllMetrics(ASTAnyTypeDeclaration node) {
List<MetricResult> metricResults = new ArrayList<>();
for (JavaClassMetricKey key : JavaClassMetricKey.values()) {
metricResults.add(new MetricResult(key, JavaMetrics.get(key, node)));
}
return metricResults;
}
private List<MetricResult> evaluateAllMetrics(ASTMethod node) {
List<MetricResult> metricResults = new ArrayList<>();
for (ApexOperationMetricKey key : ApexOperationMetricKey.values()) {
metricResults.add(new MetricResult(key, ApexMetrics.get(key, node)));
}
return metricResults;
}
private List<MetricResult> evaluateAllMetrics(ASTUserClass node) {
List<MetricResult> metricResults = new ArrayList<>();
for (ApexClassMetricKey key : ApexClassMetricKey.values()) {
metricResults.add(new MetricResult(key, ApexMetrics.get(key, node)));
}
return metricResults;
}
}

View File

@ -0,0 +1,39 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util.fxdesigner.model;
import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import net.sourceforge.pmd.lang.metrics.MetricKey;
/**
* @author Clément Fournier
* @since 6.0.0
*/
public class MetricResult {
private final SimpleEntry<MetricKey<?>, Double> simpleEntry;
public MetricResult(MetricKey<?> key, Double value) {
simpleEntry = new SimpleEntry<>(key, value);
}
MetricResult(Entry<? extends MetricKey<?>, ? extends Double> entry) {
simpleEntry = new SimpleEntry<>(entry);
}
public MetricKey<?> getKey() {
return simpleEntry.getKey();
}
public Double getValue() {
return simpleEntry.getValue();
}
}

View File

@ -69,6 +69,10 @@ public class DesignerUtil {
*/
public static void highlightNode(CodeArea codeArea, Node node) {
if (node.getBeginLine() == node.getEndLine()
&& node.getBeginColumn() == node.getEndColumn()) {
return;
}
StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>();

View File

@ -12,6 +12,7 @@ import org.fxmisc.richtext.LineNumberFactory;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.util.fxdesigner.DesignerWindowPresenter;
import net.sourceforge.pmd.util.fxdesigner.model.MetricResult;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
@ -40,6 +41,8 @@ import javafx.util.Duration;
*/
public class DesignerWindow implements Initializable {
@FXML
public TitledPane metricResultsTitledPane;
@FXML
private CodeArea codeEditorArea;
@FXML
@ -72,6 +75,9 @@ public class DesignerWindow implements Initializable {
private TitledPane astTitledPane;
@FXML
private SplitPane mainVerticalSplitPane;
@FXML
private ListView<MetricResult> metricResultsListView;
/* */
private StringProperty sourceCodeProperty;
@ -125,6 +131,12 @@ public class DesignerWindow implements Initializable {
}
public void notifyMetricsAvailable(long numMetrics) {
metricResultsTitledPane.setText("Metrics\t(" + (numMetrics == 0 ? "none" : numMetrics) + " available)");
metricResultsTitledPane.setDisable(numMetrics == 0);
}
public void notifyOutdatedAST() {
astTitledPane.setText("Abstract syntax tree (outdated)");
}
@ -214,4 +226,9 @@ public class DesignerWindow implements Initializable {
public SplitPane getMainVerticalSplitPane() {
return mainVerticalSplitPane;
}
public ListView<MetricResult> getMetricResultsListView() {
return metricResultsListView;
}
}

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.fxmisc.richtext.*?>
<?import org.fxmisc.richtext.CodeArea?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Accordion?>
@ -21,82 +26,67 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane prefHeight="750.0" prefWidth="1200.0" stylesheets="@designer.css" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="net.sourceforge.pmd.util.fxdesigner.view.DesignerWindow">
<AnchorPane prefHeight="750.0" prefWidth="1200.0" stylesheets="@designer.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="net.sourceforge.pmd.util.fxdesigner.view.DesignerWindow">
<children>
<BorderPane prefHeight="600.0" prefWidth="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<BorderPane prefHeight="600.0" prefWidth="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Action 1"/>
<MenuItem mnemonicParsing="false" text="Action 1" />
</items>
</Menu>
<Menu fx:id="languageMenu" mnemonicParsing="false" text="Language"/>
<Menu fx:id="languageMenu" mnemonicParsing="false" text="Language" />
<Menu mnemonicParsing="false" text="About">
<items>
<MenuItem mnemonicParsing="false" text="About"/>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<SplitPane fx:id="mainVerticalSplitPane" dividerPositions="0.2295492487479132">
<SplitPane fx:id="mainVerticalSplitPane" dividerPositions="0.2020033388981636">
<items>
<AnchorPane prefHeight="200.0" prefWidth="200.0">
<children>
<VBox layoutX="84.0" layoutY="14.0" prefHeight="200.0" prefWidth="100.0" spacing="5.0"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<VBox layoutX="84.0" layoutY="14.0" prefHeight="200.0" prefWidth="100.0" spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Pane prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS"/>
<TitledPane collapsible="false" prefHeight="300.0" prefWidth="200.0"
text="Node information">
<Pane prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<TitledPane collapsible="false" prefHeight="300.0" prefWidth="200.0" text="Node information">
<content>
<Accordion fx:id="nodeInfoAccordion" prefHeight="300.0"
prefWidth="236.0">
<Accordion fx:id="nodeInfoAccordion" prefHeight="300.0" prefWidth="236.0">
<panes>
<TitledPane animated="false" prefHeight="234.0"
prefWidth="236.0" text="XPath attributes"
fx:id="xpathAttributesTitledPane">
<TitledPane prefHeight="234.0" prefWidth="236.0" text="XPath attributes" fx:id="xpathAttributesTitledPane">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0"
prefHeight="180.0" prefWidth="200.0">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<ListView layoutX="21.0" layoutY="23.0"
prefHeight="200.0" prefWidth="200.0"
AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0"
fx:id="xpathAttributesListView"/>
<ListView layoutX="21.0" layoutY="23.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" fx:id="xpathAttributesListView" />
</children>
</AnchorPane>
</content>
</TitledPane>
<TitledPane expanded="false" text="Scope hierarchy" />
<TitledPane fx:id="metricResultsTitledPane" expanded="false" prefHeight="200.0" prefWidth="200.0" text="Metrics">
<content>
<AnchorPane>
<children>
<ListView fx:id="metricResultsListView" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
</TitledPane>
<TitledPane animated="false" expanded="false"
text="Scope hierarchy"/>
<TitledPane prefHeight="200.0" prefWidth="200.0"
text="Metrics"/>
</panes>
</Accordion>
</content>
</TitledPane>
<TitledPane fx:id="violationsTitledPane" animated="false" collapsible="false"
prefHeight="232.0" prefWidth="236.0" text="Matched nodes">
<TitledPane fx:id="violationsTitledPane" animated="false" collapsible="false" prefHeight="232.0" prefWidth="236.0" text="Matched nodes">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0"
prefWidth="100.0">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<ListView layoutX="34.0" layoutY="24.0" prefHeight="200.0"
prefWidth="200.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0"
fx:id="xpathResultListView"/>
<ListView layoutX="34.0" layoutY="24.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" fx:id="xpathResultListView" />
</children>
</AnchorPane>
</content>
@ -105,42 +95,26 @@
</VBox>
</children>
</AnchorPane>
<SplitPane fx:id="editorPanelHorizontalSplitPane" dividerPositions="0.6703755215577191"
orientation="VERTICAL" BorderPane.alignment="BOTTOM_CENTER">
<SplitPane fx:id="editorPanelHorizontalSplitPane" dividerPositions="0.6703755215577191" orientation="VERTICAL" BorderPane.alignment="BOTTOM_CENTER">
<items>
<BorderPane fx:id="editorAndASTBorderPane" prefHeight="200.0" prefWidth="200.0">
<center>
<SplitPane dividerPositions="0.5" BorderPane.alignment="CENTER">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0"
prefWidth="100.0">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<TitledPane collapsible="false" prefHeight="200.0"
prefWidth="200.0" text="Source code"
AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0">
<TitledPane collapsible="false" prefHeight="200.0" prefWidth="200.0" text="Source code" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<CodeArea fx:id="codeEditorArea" prefHeight="346.0"
prefWidth="445.0" styleClass="code"/>
<CodeArea fx:id="codeEditorArea" prefHeight="346.0" prefWidth="445.0" styleClass="code" />
</content>
</TitledPane>
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0"
prefWidth="100.0">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<TitledPane fx:id="astTitledPane" collapsible="false"
prefHeight="200.0" prefWidth="200.0"
text="Abstract syntax tree"
AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0">
<TitledPane fx:id="astTitledPane" collapsible="false" prefHeight="200.0" prefWidth="200.0" text="Abstract syntax tree" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<TreeView fx:id="astTreeView" prefHeight="200.0"
prefWidth="200.0"/>
<TreeView fx:id="astTreeView" prefHeight="200.0" prefWidth="200.0" />
</content>
</TitledPane>
</children>
@ -151,51 +125,37 @@
<bottom>
<ToolBar prefHeight="35.0" prefWidth="954.0" BorderPane.alignment="CENTER">
<items>
<Button fx:id="refreshASTButton" mnemonicParsing="false"
prefHeight="25.0" prefWidth="289.0" text="Refresh AST">
<Button fx:id="refreshASTButton" mnemonicParsing="false" prefHeight="25.0" prefWidth="289.0" text="Refresh AST">
<tooltip>
<Tooltip
text="Refresh the AST, and XPath results if there's an expression to evaluate"/>
<Tooltip text="Refresh the AST, and XPath results if there's an expression to evaluate" />
</tooltip>
</Button>
<MenuButton mnemonicParsing="false" text="XPath version">
<items>
<RadioMenuItem mnemonicParsing="false" text="XPath 1.0">
<toggleGroup>
<ToggleGroup fx:id="xpathVersionToggleGroup"/>
<ToggleGroup fx:id="xpathVersionToggleGroup" />
</toggleGroup>
</RadioMenuItem>
<RadioMenuItem mnemonicParsing="false"
text="XPath 1.0 (compatibility)"
toggleGroup="$xpathVersionToggleGroup"/>
<RadioMenuItem mnemonicParsing="false" selected="true"
text="XPath 2.0"
toggleGroup="$xpathVersionToggleGroup"/>
<RadioMenuItem mnemonicParsing="false" text="XPath 1.0 (compatibility)" toggleGroup="$xpathVersionToggleGroup" />
<RadioMenuItem mnemonicParsing="false" selected="true" text="XPath 2.0" toggleGroup="$xpathVersionToggleGroup" />
</items>
</MenuButton>
<Pane HBox.hgrow="ALWAYS"/>
<Pane HBox.hgrow="ALWAYS" />
</items>
<BorderPane.margin>
<Insets/>
<Insets />
</BorderPane.margin>
</ToolBar>
</bottom>
</BorderPane>
<AnchorPane>
<children>
<TitledPane alignment="BOTTOM_LEFT" prefHeight="220.0" prefWidth="898.0"
text="XPath editor" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0" fx:id="xpathEditorTitledPane">
<TitledPane alignment="BOTTOM_LEFT" animated="false" prefHeight="220.0" prefWidth="898.0" text="XPath editor" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" fx:id="xpathEditorTitledPane">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0"
prefWidth="100.0">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<CodeArea AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0"
fx:id="xpathExpressionArea"/>
<CodeArea AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" fx:id="xpathExpressionArea" />
</children>
</AnchorPane>
</content>