Make the XPath version local to the rule builder

This commit is contained in:
Clément Fournier
2019-01-09 21:58:51 +01:00
parent a0109aeef9
commit be12946bdd
8 changed files with 110 additions and 43 deletions

View File

@ -112,7 +112,7 @@
<dependency>
<groupId>org.fxmisc.richtext</groupId>
<artifactId>richtextfx</artifactId>
<version>0.9.0</version>
<version>0.9.2</version>
</dependency>
<dependency>
<groupId>org.controlsfx</groupId>

View File

@ -123,7 +123,6 @@ public class MainDesignerController implements Initializable, SettingsOwner {
private Stack<File> recentFiles = new LimitedSizeStack<>(5);
// Properties
private Val<LanguageVersion> languageVersion = Val.constant(DesignerUtil.defaultLanguageVersion());
private Val<String> xpathVersion = Val.constant(DesignerUtil.defaultXPathVersion());
public MainDesignerController(DesignerRoot owner) {
@ -147,13 +146,8 @@ public class MainDesignerController implements Initializable, SettingsOwner {
xpathPanelController.initialiseVersionChoiceBox(xpathVersionChoiceBox);
languageVersion = Val.wrap(languageChoiceBox.getSelectionModel().selectedItemProperty());
DesignerUtil.rewire(sourceEditorController.languageVersionProperty(),
languageVersion, this::setLanguageVersion);
xpathVersion = Val.wrap(xpathVersionChoiceBox.getSelectionModel().selectedItemProperty());
DesignerUtil.rewire(xpathPanelController.xpathVersionProperty(),
xpathVersion, this::setXpathVersion);
DesignerUtil.rewireInit(sourceEditorController.languageVersionProperty(),
languageVersion, this::setLanguageVersion);
licenseMenuItem.setOnAction(e -> showLicensePopup());
openFileMenuItem.setOnAction(e -> onOpenFileClicked());
@ -434,19 +428,19 @@ public class MainDesignerController implements Initializable, SettingsOwner {
public String getXpathVersion() {
return xpathVersion.getValue();
return xpathPanelController.getXpathVersion();
}
public void setXpathVersion(String version) {
if (xpathVersionChoiceBox.getItems().contains(version)) {
xpathVersionChoiceBox.getSelectionModel().select(version);
if ("1.0".equals(version) || "2.0".equals(version)) {
xpathPanelController.setXpathVersion(version);
}
}
public Val<String> xpathVersionProperty() {
return xpathVersion;
return xpathPanelController.xpathVersionProperty();
}

View File

@ -40,7 +40,6 @@ import net.sourceforge.pmd.util.fxdesigner.popups.ExportXPathWizardController;
import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil;
import net.sourceforge.pmd.util.fxdesigner.util.TextAwareNodeWrapper;
import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsOwner;
import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil.PersistentProperty;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SyntaxHighlightingCodeArea;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.XPathSyntaxHighlighter;
import net.sourceforge.pmd.util.fxdesigner.util.controls.ContextMenuWithNoArrows;
@ -64,6 +63,7 @@ import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.control.TitledPane;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
@ -77,7 +77,8 @@ import javafx.stage.StageStyle;
/**
* XPath panel controller.
* XPath panel controller. One such controller is a presenter for an {@link ObservableXPathRuleBuilder},
* which stores all data about one currently edited rule.
*
* @author Clément Fournier
* @see ExportXPathWizardController
@ -90,6 +91,8 @@ public class XPathPanelController implements Initializable, SettingsOwner {
private final MainDesignerController parent;
private final XPathEvaluator xpathEvaluator = new XPathEvaluator();
private final ObservableXPathRuleBuilder ruleBuilder = new ObservableXPathRuleBuilder();
public Button exportButton;
public ToggleButton xpath20ToggleButton;
@FXML
private PropertyTableView propertyTableView;
@ -105,6 +108,9 @@ public class XPathPanelController implements Initializable, SettingsOwner {
private ChoiceBox<String> xpathVersionChoiceBox;
private Var<String> myXpathVersion = Var.newSimpleVar(XPathRuleQuery.XPATH_2_0);
public XPathPanelController(DesignerRoot owner, MainDesignerController mainController) {
this.designerRoot = owner;
parent = mainController;
@ -119,6 +125,18 @@ public class XPathPanelController implements Initializable, SettingsOwner {
initGenerateXPathFromStackTrace();
Var<String> xpathVersionUIProp = DesignerUtil.booleanVar(xpath20ToggleButton.selectedProperty())
.mapBidirectional(
is20 -> is20 ? "2.0" : "1.0",
"2.0"::equals
);
DesignerUtil.rewireInit(xpathVersionProperty(), xpathVersionUIProp);
Var<String> xpathExprUIProp = Var.fromVal(xpathExpressionArea.textProperty(), xpathExpressionArea::replaceText);
DesignerUtil.rewireInit(getRuleBuilder().xpathExpressionProperty(), xpathExprUIProp);
xpathResultListView.setCellFactory(v -> new XpathViolationListCell());
EventStreams.valuesOf(xpathResultListView.getSelectionModel().selectedItemProperty())
@ -268,8 +286,8 @@ public class XPathPanelController implements Initializable, SettingsOwner {
DesignerUtil.rewire(getRuleBuilder().xpathVersionProperty(), parent.xpathVersionProperty());
DesignerUtil.rewire(getRuleBuilder().xpathExpressionProperty(), xpathExpressionProperty());
DesignerUtil.rewire(getRuleBuilder().rulePropertiesProperty(),
propertyTableView.rulePropertiesProperty(), propertyTableView::setRuleProperties);
DesignerUtil.rewireInit(getRuleBuilder().rulePropertiesProperty(),
propertyTableView.rulePropertiesProperty(), propertyTableView::setRuleProperties);
}
@ -356,23 +374,21 @@ public class XPathPanelController implements Initializable, SettingsOwner {
}
@PersistentProperty
public String getXpathExpression() {
return xpathExpressionArea.getText();
return getRuleBuilder().getXpathExpression();
}
public void setXpathExpression(String expression) {
xpathExpressionArea.replaceText(expression);
getRuleBuilder().setXpathExpression(expression);
}
public Val<String> xpathExpressionProperty() {
return Val.wrap(xpathExpressionArea.textProperty());
public Var<String> xpathExpressionProperty() {
return Var.fromVal(xpathExpressionArea.textProperty(), this::setXpathExpression);
}
@PersistentProperty
public String getXpathVersion() {
return getRuleBuilder().getXpathVersion();
}

View File

@ -7,6 +7,7 @@ package net.sourceforge.pmd.util.fxdesigner.model;
import org.reactfx.value.Var;
import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil;
import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil.PersistentProperty;
/**
@ -22,6 +23,7 @@ public class ObservableXPathRuleBuilder extends ObservableRuleBuilder {
private final Var<String> xpathExpression = Var.newSimpleVar("");
@PersistentProperty
public String getXpathVersion() {
return xpathVersion.getValue();
}
@ -32,6 +34,7 @@ public class ObservableXPathRuleBuilder extends ObservableRuleBuilder {
}
@PersistentProperty
public Var<String> xpathVersionProperty() {
return xpathVersion;
}
@ -42,6 +45,11 @@ public class ObservableXPathRuleBuilder extends ObservableRuleBuilder {
}
public void setXpathExpression(String value) {
xpathExpression.setValue(value);
}
public Var<String> xpathExpressionProperty() {
return xpathExpression;
}

View File

@ -6,7 +6,6 @@ package net.sourceforge.pmd.util.fxdesigner.popups;
import static net.sourceforge.pmd.properties.MultiValuePropertyDescriptor.DEFAULT_DELIMITER;
import static net.sourceforge.pmd.properties.MultiValuePropertyDescriptor.DEFAULT_NUMERIC_DELIMITER;
import static net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil.rewire;
import java.net.URL;
import java.util.Objects;
@ -127,10 +126,10 @@ public class EditPropertyDialogController implements Initializable {
public void bindToDescriptor(PropertyDescriptorSpec spec, ObservableList<PropertyDescriptorSpec> allDescriptors) {
backingDescriptor.setValue(spec);
backingDescriptorList.setValue(allDescriptors);
rewire(spec.nameProperty(), this.nameProperty(), this::setName);
rewire(spec.typeIdProperty(), this.typeIdProperty(), this::setTypeId);
rewire(spec.valueProperty(), this.valueProperty(), this::setValue);
rewire(spec.descriptionProperty(), this.descriptionProperty(), this::setDescription);
DesignerUtil.rewireInit(spec.nameProperty(), this.nameProperty(), this::setName);
DesignerUtil.rewireInit(spec.typeIdProperty(), this.typeIdProperty(), this::setTypeId);
DesignerUtil.rewireInit(spec.valueProperty(), this.valueProperty(), this::setValue);
DesignerUtil.rewireInit(spec.descriptionProperty(), this.descriptionProperty(), this::setDescription);
}

View File

@ -23,6 +23,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.reactfx.value.Var;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
@ -30,6 +31,7 @@ import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.Parser;
import net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.Property;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ListCell;
@ -172,20 +174,27 @@ public final class DesignerUtil {
}
/** Like the other overload, using the setter of the ui property. */
public static <T> void rewireInit(Property<T> underlying, Property<T> ui) {
rewireInit(underlying, ui, ui::setValue);
}
/**
* Binds the underlying property to a source of values. The source property is also initialised using the setter.
* Binds the underlying property to a source of values (UI property). The UI
* property is also initialised using a setter.
*
* @param underlying The underlying property
* @param ui The property exposed to the user (the one in this wizard)
* @param setter Setter to initialise the UI value
* @param <T> Type of values
*/
public static <T> void rewire(Property<T> underlying, ObservableValue<? extends T> ui, Consumer<? super T> setter) {
public static <T> void rewireInit(Property<T> underlying, ObservableValue<? extends T> ui, Consumer<? super T> setter) {
setter.accept(underlying.getValue());
rewire(underlying, ui);
}
/** Like rewire, with no initialisation. */
/** Like rewireInit, with no initialisation. */
public static <T> void rewire(Property<T> underlying, ObservableValue<? extends T> source) {
underlying.unbind();
underlying.bind(source); // Bindings are garbage collected after the popup dies
@ -230,4 +239,9 @@ public final class DesignerUtil {
public static Optional<String> stackTraceToXPath(Throwable e) {
return stackTraceToXPath(ExceptionUtils.getStackTrace(e));
}
public static Var<Boolean> booleanVar(BooleanProperty p) {
return Var.mapBidirectional(p, Boolean::booleanValue, Function.identity());
}
}

View File

@ -1,14 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
<?import net.sourceforge.pmd.util.fxdesigner.util.codearea.SyntaxHighlightingCodeArea?>
<?import net.sourceforge.pmd.util.fxdesigner.util.controls.PropertyTableView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="1200.0" stylesheets="@../css/designer.css" xmlns="http://javafx.com/javafx/9" xmlns:fx="http://javafx.com/fxml/1" fx:controller="net.sourceforge.pmd.util.fxdesigner.XPathPanelController">
<?import javafx.scene.control.ToggleButton?>
<AnchorPane minHeight="0.0"
minWidth="0.0"
prefHeight="180.0"
prefWidth="1200.0"
stylesheets="@../css/designer.css"
xmlns="http://javafx.com/javafx/10.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="net.sourceforge.pmd.util.fxdesigner.XPathPanelController">
<children>
<SplitPane dividerPositions="0.2, 0.8" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
@ -30,22 +41,47 @@
<children>
<TitledPane collapsible="false" styleClass="accent-header" text="XPath Expression" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<SyntaxHighlightingCodeArea stylesheets="@../css/editor-theme.css"
fx:id="xpathExpressionArea">
</SyntaxHighlightingCodeArea>
<AnchorPane>
<children>
<ToolBar orientation="VERTICAL"
AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="30.0"
AnchorPane.topAnchor="0.0">
<items>
<ToggleButton mnemonicParsing="false" styleClass="icon-button" fx:id="xpath20ToggleButton"/>
<Button fx:id="exportButton" mnemonicParsing="false" styleClass="icon-button">
<graphic>
<FontIcon iconLiteral="fa-sign-out" />
</graphic>
</Button>
</items>
</ToolBar>
<SyntaxHighlightingCodeArea stylesheets="@../css/editor-theme.css"
fx:id="xpathExpressionArea"
AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="30.0"
AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
</TitledPane>
</children>
</AnchorPane>
<AnchorPane>
<children>
<TitledPane fx:id="violationsTitledPane" animated="false"
collapsible="false" styleClass="accent-header"
text="Matched Nodes" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
<TitledPane fx:id="violationsTitledPane"
animated="false"
collapsible="false"
styleClass="accent-header"
text="Matched Nodes"
AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0">
<content>
<ListView fx:id="xpathResultListView" stylesheets="@../css/syntax-highlighting.css" />
<ListView stylesheets="@../css/syntax-highlighting.css" fx:id="xpathResultListView" />
</content>
</TitledPane>
</children>

View File

@ -156,8 +156,8 @@
// This is used for buttons that have just an icon and no text
.button.icon-button {
-fx-pref-width: 20;
-fx-pref-height: 20;
.fix-width(20);
.fix-height(20);
}
/* This is the special button to reduce the lower split pane. */