diff --git a/README.md b/README.md index 46138ee..54c0a77 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ -# WorkbenchFX [![Travis CI](https://img.shields.io/travis/entera/WorkbenchFX/master.svg?label=travis&style=flat-square)](https://travis-ci.org/entera/WorkbenchFX) +# WorkbenchFX -Workbench control element for JavaFX — https://github.com/entera/WorkbenchFX +[![](https://img.shields.io/travis/entera/WorkbenchFX/master.svg?label=travis)][Travis CI] +[![](https://img.shields.io/maven-central/v/de.entera/workbenchfx.svg?label=bintray)][Bintray JCenter] +[![](https://img.shields.io/maven-central/v/de.entera/workbenchfx.svg?label=maven)][Maven Central] + +[Travis CI]: https://travis-ci.org/entera/WorkbenchFX "Travis CI" +[Bintray JCenter]: https://bintray.com/entera/workbenchfx "Bintray JCenter" +[Maven Central]: https://search.maven.org/#search|ga|1|de.entera "Maven Central" + +A workbench user interface for JavaFX. — https://github.com/entera/WorkbenchFX ## Status @@ -15,7 +23,25 @@ _TBD._ ## Usage -_TBD._ +~~~groovy +@GrabResolver("https://jcenter.bintray.com/") +@Grab("org.codehaus.groovyfx:groovyfx:0.4.0") +@Grab("de.entera:workbenchfx:0.1.0") + +import groovyx.javafx.GroovyFX +import de.entera.workbenchfx.Workbench + +GroovyFX.start { + stage(title: this.class.simpleName, visible: true) { + scene(width: 640, height: 480) { + def workbench = new Workbench() + workbench.content = stackPane(label("content")) + workbench.leftViews << label("left first") << label("left second") + stackPane(workbench) + } + } +} +~~~ ## Motivation diff --git a/workbenchfx/src/main/groovy/de/entera/workbenchfx/Workbench.groovy b/workbenchfx/src/main/groovy/de/entera/workbenchfx/Workbench.groovy index 98c6d58..0b80c17 100644 --- a/workbenchfx/src/main/groovy/de/entera/workbenchfx/Workbench.groovy +++ b/workbenchfx/src/main/groovy/de/entera/workbenchfx/Workbench.groovy @@ -7,6 +7,7 @@ import javafx.collections.ObservableList import javafx.scene.Node import javafx.scene.control.Control import javafx.scene.control.Skin +import javafx.scene.control.ToggleButton import de.entera.workbenchfx.impl.WorkbenchSkin @@ -32,6 +33,10 @@ class Workbench extends Control { final ObservableList getRightViews() { return this.rightViews } + final ObservableList getLeftButtons() { return this.leftButtons } + + final ObservableList getRightButtons() { return this.rightButtons } + //--------------------------------------------------------------------------------------------- // PRIVATE FIELDS. //--------------------------------------------------------------------------------------------- @@ -42,6 +47,10 @@ class Workbench extends Control { private final ObservableList rightViews = FXCollections.observableArrayList() + private final ObservableList leftButtons = FXCollections.observableArrayList() + + private final ObservableList rightButtons = FXCollections.observableArrayList() + //--------------------------------------------------------------------------------------------- // CONSTRUCTORS. //--------------------------------------------------------------------------------------------- diff --git a/workbenchfx/src/main/groovy/de/entera/workbenchfx/impl/WorkbenchSkin.groovy b/workbenchfx/src/main/groovy/de/entera/workbenchfx/impl/WorkbenchSkin.groovy index 3338deb..19ffaea 100644 --- a/workbenchfx/src/main/groovy/de/entera/workbenchfx/impl/WorkbenchSkin.groovy +++ b/workbenchfx/src/main/groovy/de/entera/workbenchfx/impl/WorkbenchSkin.groovy @@ -2,10 +2,11 @@ package de.entera.workbenchfx.impl import javafx.application.Platform import javafx.collections.ListChangeListener +import javafx.collections.ObservableList import javafx.geometry.Orientation -import javafx.scene.Node import javafx.scene.Parent import javafx.scene.control.SplitPane +import javafx.scene.control.ToolBar import javafx.scene.layout.BorderPane import javafx.scene.layout.StackPane @@ -23,11 +24,19 @@ class WorkbenchSkin extends BehaviorSkinBase> private static final String PROPERTY_LEFT_VIEWS = "left-views" - private static final String STYLE_CLASS_CONTENT_CONTAINER = "content-container" + private static final String PROPERTY_RIGHT_VIEWS = "right-views" - private static final String STYLE_CLASS_LEFT_CONTAINER = "left-container" + private static final String PROPERTY_LEFT_BUTTONS = "left-buttons" - private static final String STYLE_CLASS_RIGHT_CONTAINER = "right-container" + private static final String PROPERTY_RIGHT_BUTTONS = "right-buttons" + + private static final String STYLE_CLASS_CONTAINER = "container" + + private static final String STYLE_CLASS_CONTENT = "content" + + private static final String STYLE_CLASS_LEFT = "left" + + private static final String STYLE_CLASS_RIGHT = "right" //--------------------------------------------------------------------------------------------- // PRIVATE FIELDS. @@ -35,6 +44,8 @@ class WorkbenchSkin extends BehaviorSkinBase> private StackPane rootContainer + private BorderPane outerBorderPane + private BorderPane innerBorderPane private StackPane contentContainer @@ -43,6 +54,10 @@ class WorkbenchSkin extends BehaviorSkinBase> private SplitPane rightContainer + private ToolBar leftToolBar + + private ToolBar rightToolBar + //--------------------------------------------------------------------------------------------- // CONSTRUCTORS. //--------------------------------------------------------------------------------------------- @@ -61,23 +76,34 @@ class WorkbenchSkin extends BehaviorSkinBase> private void initializeSkin() { this.contentContainer = new StackPane() - this.contentContainer.styleClass << STYLE_CLASS_CONTENT_CONTAINER + this.contentContainer.styleClass << STYLE_CLASS_CONTENT << STYLE_CLASS_CONTAINER this.leftContainer = new SplitPane() - this.leftContainer.styleClass << STYLE_CLASS_LEFT_CONTAINER + this.leftContainer.styleClass << STYLE_CLASS_LEFT << STYLE_CLASS_CONTAINER this.leftContainer.orientation = Orientation.VERTICAL this.rightContainer = new SplitPane() - this.rightContainer.styleClass << STYLE_CLASS_RIGHT_CONTAINER + this.rightContainer.styleClass << STYLE_CLASS_RIGHT << STYLE_CLASS_CONTAINER this.rightContainer.orientation = Orientation.VERTICAL + this.leftToolBar = new ToolBar() + this.leftToolBar.styleClass << STYLE_CLASS_LEFT + + this.rightToolBar = new ToolBar() + this.rightToolBar.styleClass << STYLE_CLASS_RIGHT + this.innerBorderPane = new BorderPane() this.innerBorderPane.center = this.contentContainer this.innerBorderPane.left = this.leftContainer this.innerBorderPane.right = this.rightContainer + this.outerBorderPane = new BorderPane() + this.outerBorderPane.center = this.innerBorderPane + this.outerBorderPane.left = this.leftToolBar + this.outerBorderPane.right = this.rightToolBar + this.rootContainer = new StackPane() - this.rootContainer.children.setAll(this.innerBorderPane) + this.rootContainer.children.setAll(this.outerBorderPane) } private void installSkin(Parent container) { @@ -86,15 +112,17 @@ class WorkbenchSkin extends BehaviorSkinBase> } private void installBehavior() { - this.skinnable.leftViews.addListener({ change -> - handleLeftViewsListChanged() - } as ListChangeListener) - this.skinnable.rightViews.addListener({ change -> - handleRightViewsListChanged() - } as ListChangeListener) - - registerChangeListener(this.skinnable.contentProperty(), PROPERTY_CONTENT) - handleControlPropertyChanged(PROPERTY_CONTENT) + this.registerChangeListener(this.skinnable.contentProperty(), PROPERTY_CONTENT) + this.registerListChangeListener(this.skinnable.leftViews, PROPERTY_LEFT_VIEWS) + this.registerListChangeListener(this.skinnable.rightViews, PROPERTY_RIGHT_VIEWS) + this.registerListChangeListener(this.skinnable.leftButtons, PROPERTY_LEFT_BUTTONS) + this.registerListChangeListener(this.skinnable.rightButtons, PROPERTY_RIGHT_BUTTONS) + + this.handleControlPropertyChanged(PROPERTY_CONTENT) + this.handleControlPropertyChanged(PROPERTY_LEFT_VIEWS) + this.handleControlPropertyChanged(PROPERTY_RIGHT_VIEWS) + this.handleControlPropertyChanged(PROPERTY_LEFT_BUTTONS) + this.handleControlPropertyChanged(PROPERTY_RIGHT_BUTTONS) } protected void handleControlPropertyChanged(String propertyReference) { @@ -103,6 +131,18 @@ class WorkbenchSkin extends BehaviorSkinBase> if (propertyReference == PROPERTY_CONTENT) { this.handleContentPropertyChanged() } + else if (propertyReference == PROPERTY_LEFT_VIEWS) { + this.handleLeftViewsObservableChanged() + } + else if (propertyReference == PROPERTY_RIGHT_VIEWS) { + this.handleRightViewsObservableChanged() + } + else if (propertyReference == PROPERTY_LEFT_BUTTONS) { + this.handleLeftButtonsObservableChanged() + } + else if (propertyReference == PROPERTY_RIGHT_BUTTONS) { + this.handleRightButtonsObservableChanged() + } } private void handleContentPropertyChanged() { @@ -114,20 +154,34 @@ class WorkbenchSkin extends BehaviorSkinBase> } } - private void handleLeftViewsListChanged() { + private void handleLeftViewsObservableChanged() { assert Platform.isFxApplicationThread() def leftViews = this.skinnable.leftViews this.leftContainer.items.setAll(leftViews) } - private void handleRightViewsListChanged() { + private void handleRightViewsObservableChanged() { assert Platform.isFxApplicationThread() def rightViews = this.skinnable.rightViews this.rightContainer.items.setAll(rightViews) } + private void handleLeftButtonsObservableChanged() { + assert Platform.isFxApplicationThread() + + def leftButtons = this.skinnable.leftButtons + this.leftToolBar.items.setAll(leftButtons) + } + + private void handleRightButtonsObservableChanged() { + assert Platform.isFxApplicationThread() + + def rightButtons = this.skinnable.rightButtons + this.rightToolBar.items.setAll(rightButtons) + } + protected void layoutChildren(double x, double y, double width, @@ -135,4 +189,11 @@ class WorkbenchSkin extends BehaviorSkinBase> super.layoutChildren(x, y, width, height) } + private void registerListChangeListener(ObservableList observableList, + String reference) { + observableList.addListener({ change -> + this.handleControlPropertyChanged(reference) + } as ListChangeListener) + } + } diff --git a/workbenchfx/src/test/groovy/de/entera/workbenchfx/WorkbenchTest.groovy b/workbenchfx/src/test/groovy/de/entera/workbenchfx/WorkbenchTest.groovy index 5a71047..cf6e552 100644 --- a/workbenchfx/src/test/groovy/de/entera/workbenchfx/WorkbenchTest.groovy +++ b/workbenchfx/src/test/groovy/de/entera/workbenchfx/WorkbenchTest.groovy @@ -2,6 +2,7 @@ package de.entera.workbenchfx import javafx.scene.Scene import javafx.scene.control.Label +import javafx.scene.control.ToggleButton import javafx.stage.Stage import org.junit.Test @@ -49,7 +50,7 @@ class WorkbenchTest extends ApplicationTest { } // then: - verifyThat(".workbench .content-container", hasChild("content")) + verifyThat(".workbench .content.container", hasChild("content")) } @Test @@ -60,8 +61,8 @@ class WorkbenchTest extends ApplicationTest { } // then: - verifyThat(".workbench .left-container", hasChild("left one")) - verifyThat(".workbench .left-container", hasChild("left two")) + verifyThat(".workbench .left.container", hasChild("left one")) + verifyThat(".workbench .left.container", hasChild("left two")) } @Test @@ -72,8 +73,30 @@ class WorkbenchTest extends ApplicationTest { } // then: - verifyThat(".workbench .right-container", hasChild("right one")) - verifyThat(".workbench .right-container", hasChild("right two")) + verifyThat(".workbench .right.container", hasChild("right one")) + verifyThat(".workbench .right.container", hasChild("right two")) + } + + @Test + void "should update left buttons"() { + // when: + interact { + workbench.leftButtons << new ToggleButton("left first button") + } + + // then: + verifyThat(".workbench .left.tool-bar", hasChild("left first button")) + } + + @Test + void "should update right buttons"() { + // when: + interact { + workbench.rightButtons << new ToggleButton("right first button") + } + + // then: + verifyThat(".workbench .right.tool-bar", hasChild("right first button")) } }