REVERT ME Remove crumbbar to prep for PR
This commit is contained in:
parent
75da199b06
commit
2c357fe941
@ -16,9 +16,6 @@
|
||||
<maven.compiler.source>1.${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>1.${java.version}</maven.compiler.target>
|
||||
|
||||
<build.mr.java9.output>${project.build.outputDirectory}/META-INF/versions/9</build.mr.java9.output>
|
||||
|
||||
|
||||
<openjfx.version>11</openjfx.version>
|
||||
</properties>
|
||||
|
||||
@ -64,57 +61,6 @@
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Unpack Java 8 specific dependencies into the root output dir -->
|
||||
<!-- Code specific to higher versions is unpacked into META-INF/versions/n -->
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>layout-java-8-specific-code</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifact>org.controlsfx:controlsfx:8.40.13</artifact>
|
||||
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
|
||||
<includes>**/*</includes>
|
||||
<excludes>MANIFEST.MF</excludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>layout-java-9-specific-code</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifact>org.controlsfx:controlsfx:9.0.0</artifact>
|
||||
<outputDirectory>${build.mr.java9.output}</outputDirectory>
|
||||
<includes>**/*</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<!-- Important for it to work on JRE 9+ -->
|
||||
<Multi-Release>true</Multi-Release>
|
||||
<Main-Class>net.sourceforge.pmd.util.fxdesigner.DesignerStarter</Main-Class>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<finalName>pmd-ui-${project.version}</finalName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@ -169,12 +115,9 @@
|
||||
<version>0.9.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- That one is "provided" because several versions are unpacked into versioned dirs -->
|
||||
<!-- to create a multi-release jar. -->
|
||||
<groupId>org.controlsfx</groupId>
|
||||
<artifactId>controlsfx</artifactId>
|
||||
<version>8.40.13</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
|
@ -29,13 +29,13 @@ import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
import net.sourceforge.pmd.util.ClasspathClassLoader;
|
||||
import net.sourceforge.pmd.util.fxdesigner.app.AbstractController;
|
||||
import net.sourceforge.pmd.util.fxdesigner.app.CompositeSelectionSource;
|
||||
import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource;
|
||||
import net.sourceforge.pmd.util.fxdesigner.model.ASTManager;
|
||||
import net.sourceforge.pmd.util.fxdesigner.model.ParseAbortedException;
|
||||
import net.sourceforge.pmd.util.fxdesigner.popups.AuxclasspathSetupController;
|
||||
import net.sourceforge.pmd.util.fxdesigner.app.AbstractController;
|
||||
import net.sourceforge.pmd.util.fxdesigner.app.CompositeSelectionSource;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil;
|
||||
import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.TextAwareNodeWrapper;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil.PersistentProperty;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.codearea.AvailableSyntaxHighlighters;
|
||||
@ -43,7 +43,6 @@ import net.sourceforge.pmd.util.fxdesigner.util.codearea.HighlightLayerCodeArea;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.codearea.HighlightLayerCodeArea.LayerId;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.controls.ASTTreeItem;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.controls.AstTreeView;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.controls.NodeParentageCrumbBar;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.controls.ToolbarTitledPane;
|
||||
|
||||
import javafx.application.Platform;
|
||||
@ -76,8 +75,6 @@ public class SourceEditorController extends AbstractController<MainDesignerContr
|
||||
private AstTreeView astTreeView;
|
||||
@FXML
|
||||
private HighlightLayerCodeArea<StyleLayerIds> codeEditorArea;
|
||||
@FXML
|
||||
private NodeParentageCrumbBar focusNodeParentageCrumbBar;
|
||||
|
||||
private final ASTManager astManager;
|
||||
|
||||
@ -107,7 +104,6 @@ public class SourceEditorController extends AbstractController<MainDesignerContr
|
||||
protected void beforeParentInit() {
|
||||
|
||||
astTreeView.setDesignerRoot(getDesignerRoot());
|
||||
focusNodeParentageCrumbBar.setDesignerRoot(getDesignerRoot());
|
||||
|
||||
initializeLanguageSelector(); // languageVersionProperty() must be initialized
|
||||
|
||||
@ -193,7 +189,7 @@ public class SourceEditorController extends AbstractController<MainDesignerContr
|
||||
|
||||
@Override
|
||||
public ObservableSet<? extends NodeSelectionSource> getSubSelectionSources() {
|
||||
return FXCollections.observableSet(astTreeView, focusNodeParentageCrumbBar);
|
||||
return FXCollections.observableSet(astTreeView);
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,14 +10,14 @@ import org.reactfx.EventStream;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.util.fxdesigner.MainDesignerController;
|
||||
import net.sourceforge.pmd.util.fxdesigner.XPathPanelController;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsOwner;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.controls.AstTreeView;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.controls.NodeParentageCrumbBar;
|
||||
|
||||
|
||||
/**
|
||||
* A control or controller that somehow displays nodes in a form that the user can select.
|
||||
* When a node is selected by the user (e.g. {@link AstTreeView}, {@link NodeParentageCrumbBar}, etc),
|
||||
* When a node is selected by the user (e.g. {@link AstTreeView}, {@link XPathPanelController}, etc),
|
||||
* the whole UI is synchronized to reflect information about the node. This includes scrolling
|
||||
* the TreeView, the editor, etc. To achieve that uniformly, node selection events are merged
|
||||
* into a global stream for the whole app. Events from that stream are handled by {@link MainDesignerController}.
|
||||
|
@ -1,237 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.util.fxdesigner.util.controls;
|
||||
|
||||
|
||||
import static net.sourceforge.pmd.internal.util.IteratorUtil.asReversed;
|
||||
import static net.sourceforge.pmd.internal.util.IteratorUtil.count;
|
||||
import static net.sourceforge.pmd.util.fxdesigner.util.DesignerIteratorUtil.parentIterator;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.controlsfx.control.BreadCrumbBar;
|
||||
import org.reactfx.EventSource;
|
||||
import org.reactfx.EventStream;
|
||||
import org.reactfx.value.Val;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.util.fxdesigner.app.DesignerRoot;
|
||||
import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.css.PseudoClass;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Labeled;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.control.TreeItem;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.util.Callback;
|
||||
|
||||
|
||||
/**
|
||||
* Bread crumb bar to display the parents of a node. Avoids overflow
|
||||
* by estimating the number of crumbs we can layout based on the actual
|
||||
* size of the control.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public class NodeParentageCrumbBar extends BreadCrumbBar<Node> implements NodeSelectionSource {
|
||||
|
||||
private static final int DEFAULT_PX_BY_CHAR = 5;
|
||||
private static final int DEFAULT_CONSTANT_PADDING = 19;
|
||||
|
||||
/** Special item used to truncate paths when they're too long. */
|
||||
private final TreeItem<Node> ellipsisCrumb = new TreeItem<>(null);
|
||||
/** number of nodes currently behind the ellipsis */
|
||||
private int numElidedNodes = 0;
|
||||
private final EventSource<Node> selectionEvents = new EventSource<>();
|
||||
|
||||
private DesignerRoot designerRoot;
|
||||
|
||||
|
||||
public NodeParentageCrumbBar() {
|
||||
// This allows to click on a parent crumb and keep the children crumb
|
||||
setAutoNavigationEnabled(false);
|
||||
|
||||
// captured in the closure
|
||||
final Callback<TreeItem<Node>, Button> originalCrumbFactory = getCrumbFactory();
|
||||
|
||||
setOnCrumbAction(ev -> {
|
||||
if (ev.getSelectedCrumb() != ellipsisCrumb) {
|
||||
selectionEvents.push(ev.getSelectedCrumb().getValue());
|
||||
}
|
||||
});
|
||||
|
||||
setCrumbFactory(item -> {
|
||||
Button button = originalCrumbFactory.call(item);
|
||||
if (item == ellipsisCrumb) {
|
||||
button.setText("... (" + numElidedNodes + ")");
|
||||
button.setTooltip(new Tooltip(numElidedNodes + " ancestors are not shown"));
|
||||
}
|
||||
// we use that to communicate the node later on
|
||||
button.setUserData(item);
|
||||
Val.wrap(button.focusedProperty())
|
||||
.values()
|
||||
.distinct()
|
||||
.filter(Boolean::booleanValue)
|
||||
// will change the node in the treeview on <- -> key presses
|
||||
.subscribe(b -> getOnCrumbAction().handle(new BreadCrumbActionEvent<>(item)));
|
||||
return button;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean alwaysHandleSelection() {
|
||||
// We need to reset the pseudo class we artificially added.
|
||||
// if the event originated from here, then we know the crumb is displayed
|
||||
// and we won't reset the displayed nodes
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EventStream<NodeSelectionEvent> getSelectionEvents() {
|
||||
return selectionEvents.map(n -> new NodeSelectionEvent(n, this));
|
||||
}
|
||||
|
||||
// getSelectedCrumb gets the deepest displayed node
|
||||
|
||||
|
||||
/**
|
||||
* If the node is already displayed on the crumbbar, only
|
||||
* sets the focus on it. Otherwise, sets the node to be
|
||||
* the deepest one of the crumb bar. Noop if node is null.
|
||||
*/
|
||||
@Override
|
||||
public void setFocusNode(Node node) {
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
// We're trying to estimate the ratio of px/crumb,
|
||||
// to make an educated guess about how many crumbs we can fit
|
||||
// in case we need to call setDeepestNode
|
||||
int totalNumChar = 0;
|
||||
int totalNumCrumbs = 0;
|
||||
// the sum of children width is the actual width with overflow
|
||||
// the width of this control is the max acceptable width *without* overflow
|
||||
double totalChildrenWidth = 0;
|
||||
// constant padding around the graphic of a BreadCrumbButton
|
||||
// (difference between width of a BreadCrumbButton and that of its graphic)
|
||||
double constantPadding = Double.NaN;
|
||||
|
||||
for (javafx.scene.Node button : asReversed(getChildren())) {
|
||||
Node n = (Node) ((TreeItem<?>) button.getUserData()).getValue();
|
||||
|
||||
// set the focus on the one being selected, remove on the others
|
||||
// calling requestFocus would switch the focus from eg the treeview to the crumb bar (unusable)
|
||||
button.pseudoClassStateChanged(PseudoClass.getPseudoClass("focused"), node.equals(n));
|
||||
|
||||
// update counters
|
||||
totalNumChar += ((Labeled) button).getText().length();
|
||||
double childWidth = ((Region) button).getWidth();
|
||||
totalChildrenWidth += childWidth;
|
||||
totalNumCrumbs++;
|
||||
if (Double.isNaN(constantPadding)) {
|
||||
Region graphic = (Region) ((Labeled) button).getGraphic();
|
||||
if (graphic != null) {
|
||||
constantPadding = childWidth - graphic.getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
if (node.equals(n)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// Then we reset the deepest node.
|
||||
|
||||
setDeepestNode(node, getWidthEstimator(totalNumChar, totalChildrenWidth, totalNumCrumbs, constantPadding));
|
||||
// set the deepest as focused
|
||||
Platform.runLater(() ->
|
||||
getChildren()
|
||||
.get(getChildren().size() - 1)
|
||||
.pseudoClassStateChanged(PseudoClass.getPseudoClass("focused"), true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the given node to the selected (deepest) crumb. Parent crumbs are
|
||||
* added until they are estimated to overflow the visual space, after
|
||||
* which they are hidden into the ellipsis crumb.
|
||||
*
|
||||
* @param node Node to set
|
||||
* @param widthEstimator Estimates the visual width of the crumb for one node
|
||||
*/
|
||||
private void setDeepestNode(Node node, Function<Node, Double> widthEstimator) {
|
||||
TreeItem<Node> deepest = new TreeItem<>(node);
|
||||
TreeItem<Node> current = deepest;
|
||||
Node parent = node.jjtGetParent();
|
||||
double pathLength = widthEstimator.apply(node);
|
||||
|
||||
final double maxPathLength = getWidth() * 0.9;
|
||||
|
||||
while (parent != null && pathLength < maxPathLength) {
|
||||
TreeItem<Node> newItem = new TreeItem<>(parent);
|
||||
newItem.getChildren().add(current);
|
||||
current = newItem;
|
||||
pathLength += widthEstimator.apply(parent);
|
||||
parent = current.getValue().jjtGetParent();
|
||||
}
|
||||
|
||||
if (pathLength >= maxPathLength
|
||||
// if parent == null then it's the root, no need for ellipsis
|
||||
&& parent != null) {
|
||||
|
||||
numElidedNodes = count(parentIterator(parent, true));
|
||||
|
||||
// the rest are children of the ellipsis
|
||||
ellipsisCrumb.getChildren().clear();
|
||||
ellipsisCrumb.getChildren().add(current);
|
||||
}
|
||||
|
||||
setSelectedCrumb(deepest);
|
||||
}
|
||||
|
||||
|
||||
private Function<Node, Double> getWidthEstimator(int totalNumDisplayedChars, double totalChildrenWidth, int totalNumCrumbs, double constantPadding) {
|
||||
|
||||
double safeConstantPadding = Double.isNaN(constantPadding)
|
||||
? DEFAULT_CONSTANT_PADDING // that's the value on my machine
|
||||
: constantPadding;
|
||||
|
||||
double thisPxByChar = totalNumDisplayedChars == 0
|
||||
? DEFAULT_PX_BY_CHAR // we have no data, too bad
|
||||
: (totalChildrenWidth - safeConstantPadding * totalNumCrumbs) / totalNumDisplayedChars;
|
||||
|
||||
return node -> node.getXPathNodeName().length() * (thisPxByChar + 1 /*scale it up a bit*/) + safeConstantPadding;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DesignerRoot getDesignerRoot() {
|
||||
return designerRoot;
|
||||
}
|
||||
|
||||
|
||||
public void setDesignerRoot(DesignerRoot designerRoot) {
|
||||
this.designerRoot = designerRoot;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDebugName() {
|
||||
return "crumb-bar";
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@
|
||||
<?import org.kordamp.ikonli.javafx.FontIcon?>
|
||||
<?import net.sourceforge.pmd.util.fxdesigner.util.codearea.HighlightLayerCodeArea?>
|
||||
<?import net.sourceforge.pmd.util.fxdesigner.util.controls.AstTreeView?>
|
||||
<?import net.sourceforge.pmd.util.fxdesigner.util.controls.NodeParentageCrumbBar?>
|
||||
<?import net.sourceforge.pmd.util.fxdesigner.util.controls.ToolbarTitledPane?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.MenuButton?>
|
||||
@ -80,8 +79,8 @@
|
||||
</SplitPane>
|
||||
</center>
|
||||
<bottom>
|
||||
<NodeParentageCrumbBar fx:id="focusNodeParentageCrumbBar"
|
||||
stylesheets="@../css/crumbbar.css"
|
||||
prefHeight="30" id="main-toolbar" />
|
||||
<!--<NodeParentageCrumbBar fx:id="focusNodeParentageCrumbBar"-->
|
||||
<!--stylesheets="@../css/crumbbar.css"-->
|
||||
<!--prefHeight="30" id="main-toolbar" />-->
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
|
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
/*
|
||||
* Sheet for the AST crumb bar.
|
||||
*/
|
||||
@import "constants";
|
||||
|
||||
.bread-crumb-bar {
|
||||
|
||||
-fx-border-color: transparent;
|
||||
.button {
|
||||
-fx-background-color: @fx-base;
|
||||
-fx-border-color: @darker-accent;
|
||||
-fx-border-style: none solid none solid;
|
||||
-fx-border-width: 1;
|
||||
}
|
||||
|
||||
.button:focused {
|
||||
-fx-background-color: @selection-focus-color;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user