Commit 2b65453d authored by Sarah Grebing's avatar Sarah Grebing

revert DockFX

parent ed95fcf7
package org.dockfx;
import java.util.LinkedList;
import java.util.Properties;
/**
* ContentHolder has common functions for storing persistent object for node
*
* @author HongKee Moon
*/
public class ContentHolder
{
/**
* The enum ContentHolder Type.
*/
public enum Type {
/**
* The SplitPane.
*/
SplitPane,
/**
* The TabPane.
*/
TabPane,
/**
* The Collection.
*/
Collection,
/**
* The FloatingNode.
*/
FloatingNode,
/**
* The DockNode.
*/
DockNode
}
String name;
Properties properties;
LinkedList children;
Type type;
public ContentHolder()
{
}
public ContentHolder( String name, Type type )
{
this.name = name;
this.properties = new Properties();
this.children = new LinkedList();
this.type = type;
}
public void addProperty( Object key, Object value )
{
properties.put( key, value );
}
public void addChild( Object child )
{
children.add( child );
}
public String getName()
{
return name;
}
public void setName( String name )
{
this.name = name;
}
public Properties getProperties()
{
return properties;
}
public void setProperties( Properties properties )
{
this.properties = properties;
}
public LinkedList getChildren()
{
return children;
}
public void setChildren( LinkedList children )
{
this.children = children;
}
public Type getType()
{
return type;
}
public void setType( Type type )
{
this.type = type;
}
}
package org.dockfx;
/**
* To support the delayed open process for some specific applications, this interface implementation is used.
*/
public interface DelayOpenHandler {
public DockNode open(String nodeName);
}
......@@ -30,7 +30,7 @@ import javafx.scene.Node;
import javafx.scene.input.PickResult;
/**
* Base class for DockFX events. Each DockFX event has an associated event source, event target and
* Base class for DockFX events. Each DockFX event has associated an event source, event target and
* an event type. The event source specifies for an event handler the object on which that handler
* has been registered and which sent the event to it. The event target defines the path through
* which the event will travel when posted. The event type provides additional classification to
......
......@@ -21,9 +21,14 @@
package org.dockfx;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import com.sun.javafx.stage.StageHelper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
......@@ -52,15 +57,15 @@ public class DockTitleBar extends HBox implements EventHandler<MouseEvent> {
/**
* The DockNode this node is a title bar for.
*/
private DockNode dockNode;
private final DockNode dockNode;
/**
* The label node used for captioning and the graphic.
*/
private Label label;
private final Label label;
/**
* State manipulation buttons including close, maximize, detach, and restore.
*/
private Button closeButton, stateButton;
private final Button closeButton, stateButton, minimizeButton;
/**
* Creates a default DockTitleBar with captions and dragging behavior.
......@@ -88,28 +93,67 @@ public class DockTitleBar extends HBox implements EventHandler<MouseEvent> {
closeButton = new Button();
closeButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
dockNode.close();
}
});
closeButton.visibleProperty().bind(dockNode.closableProperty());
// create a pane that will stretch to make the buttons right aligned
Pane fillPane = new Pane();
HBox.setHgrow(fillPane, Priority.ALWAYS);
getChildren().addAll(label, fillPane, stateButton, closeButton);
minimizeButton = new Button();
minimizeButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
dockNode.setMinimized(true);
}
});
this.addEventHandler(MouseEvent.MOUSE_PRESSED, this);
this.addEventHandler(MouseEvent.DRAG_DETECTED, this);
this.addEventHandler(MouseEvent.MOUSE_DRAGGED, this);
this.addEventHandler(MouseEvent.MOUSE_RELEASED, this);
label.getStyleClass().add("dock-title-label");
closeButton.getStyleClass().add("dock-close-button");
stateButton.getStyleClass().add("dock-state-button");
minimizeButton.getStyleClass().add("dock-minimize-button");
this.getStyleClass().add("dock-title-bar");
// create a pane that will stretch to make the buttons right aligned
Pane fillPane = new Pane();
HBox.setHgrow(fillPane, Priority.ALWAYS);
dockNode.closableProperty().addListener( new ChangeListener< Boolean >()
{
@Override public void changed( ObservableValue< ? extends Boolean > observable, Boolean oldValue, Boolean newValue )
{
if(newValue)
{
if(!getChildren().contains( closeButton ))
getChildren().add( closeButton );
}
else
{
getChildren().removeIf( c -> c.equals( closeButton ) );
}
}
} );
dockNode.minimizableProperty().addListener( new ChangeListener< Boolean >()
{
@Override public void changed( ObservableValue< ? extends Boolean > observable, Boolean oldValue, Boolean newValue )
{
if(newValue)
{
getChildren().add(2, minimizeButton);
}
else
{
getChildren().remove( minimizeButton );
}
}
} );
getChildren().addAll( label, fillPane, stateButton, closeButton );
}
/**
......@@ -149,6 +193,15 @@ public class DockTitleBar extends HBox implements EventHandler<MouseEvent> {
public final Button getStateButton() {
return stateButton;
}
/**
* The button used for minimizing this title bar and its associated dock node.
*
* @return The button used for minimizing this title bar and its associated dock node.
*/
public final Button getMinimizeButton() {
return minimizeButton;
}
/**
* The dock node that is associated with this title bar.
......@@ -225,14 +278,10 @@ public class DockTitleBar extends HBox implements EventHandler<MouseEvent> {
// RFE for public scene graph traversal API filed but closed:
// https://bugs.openjdk.java.net/browse/JDK-8133331
List<DockPane> dockPanes = DockPane.dockPanes;
ObservableList<Stage> stages =
FXCollections.unmodifiableObservableList(StageHelper.getStages());
// fire the dock over event for the active stages
for (DockPane dockPane : dockPanes) {
Window window = dockPane.getScene().getWindow();
if (!(window instanceof Stage)) continue;
Stage targetStage = (Stage) window;
for (Stage targetStage : stages) {
// obviously this title bar does not need to receive its own events
// though users of this library may want to know when their
// dock node is being dragged by subclassing it or attaching
......@@ -303,7 +352,7 @@ public class DockTitleBar extends HBox implements EventHandler<MouseEvent> {
// then we need to offset the stage position by
// the height of this title bar
if (!dockNode.isCustomTitleBar() && dockNode.isDecorated()) {
dockNode.setFloating(true, new Point2D(0, DockTitleBar.this.getHeight()));
dockNode.setFloating(true, new Point2D(0, DockTitleBar.this.getHeight()), null);
} else {
dockNode.setFloating(true);
}
......@@ -355,6 +404,12 @@ public class DockTitleBar extends HBox implements EventHandler<MouseEvent> {
Stage stage = dockNode.getStage();
Insets insetsDelta = this.getDockNode().getBorderPane().getInsets();
// it is possible that drag start has not been set if some other node had focus when
// we started the drag
if (null == dragStart) {
dragStart = new Point2D(event.getX(), event.getY());
}
// dragging this way makes the interface more responsive in the event
// the system is lagging as is the case with most current JavaFX
// implementations on Linux
......@@ -364,13 +419,13 @@ public class DockTitleBar extends HBox implements EventHandler<MouseEvent> {
// TODO: change the pick result by adding a copyForPick()
DockEvent dockEnterEvent =
new DockEvent(this, DockEvent.NULL_SOURCE_TARGET, DockEvent.DOCK_ENTER, event.getX(),
event.getY(), event.getScreenX(), event.getScreenY(), null);
event.getY(), event.getScreenX(), event.getScreenY(), null, this.getDockNode());
DockEvent dockOverEvent =
new DockEvent(this, DockEvent.NULL_SOURCE_TARGET, DockEvent.DOCK_OVER, event.getX(),
event.getY(), event.getScreenX(), event.getScreenY(), null);
event.getY(), event.getScreenX(), event.getScreenY(), null, this.getDockNode());
DockEvent dockExitEvent =
new DockEvent(this, DockEvent.NULL_SOURCE_TARGET, DockEvent.DOCK_EXIT, event.getX(),
event.getY(), event.getScreenX(), event.getScreenY(), null);
event.getY(), event.getScreenX(), event.getScreenY(), null, this.getDockNode());
EventTask eventTask = new EventTask() {
@Override
......
......@@ -21,32 +21,35 @@
package org.dockfx.demo;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Random;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import org.dockfx.DockNode;
import org.dockfx.DockPane;
import org.dockfx.DockPos;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.Separator;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.ToolBar;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.layout.AnchorPane;
import javafx.scene.web.HTMLEditor;
import javafx.stage.Stage;
......@@ -99,50 +102,63 @@ public class DockFX extends Application {
DockNode tabsDock = new DockNode(tabs, "Tabs Dock", new ImageView(dockImage));
tabsDock.setPrefSize(300, 100);
tabsDock.dock(dockPane, DockPos.TOP);
DockNode tableDock = new DockNode(tableView);
// let's disable our table from being undocked
tableDock.setDockTitleBar(null);
DockNode tableDock = new DockNode(tableView, "Table");
tableDock.setPrefSize(300, 100);
tableDock.dock(dockPane, DockPos.BOTTOM);
final Menu menu1 = new Menu("File");
final Menu menu2 = new Menu("Options");
final Menu menu3 = new Menu("Help");
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(menu1, menu2, menu3);
ToolBar toolBar = new ToolBar(
new Button("New"),
new Button("Open"),
new Button("Save"),
new Separator(),
new Button("Clean"),
new Button("Compile"),
new Button("Run"),
new Separator(),
new Button("Debug"),
new Button("Profile")
);
VBox vbox = new VBox();
vbox.getChildren().addAll(menuBar, toolBar, dockPane);
VBox.setVgrow(dockPane, Priority.ALWAYS);
primaryStage.setScene(new Scene(vbox, 800, 500));
MenuItem saveMenuItem = new MenuItem("Save");
saveMenuItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if(dirExist(getUserDataDirectory()))
dockPane.storePreference(getUserDataDirectory() + "dock.pref");
}
});
MenuItem restoreMenuItem = new MenuItem("Restore");
restoreMenuItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
dockPane.loadPreference(getUserDataDirectory() + "dock.pref");
}
});
Menu fileMenu = new Menu("File");
MenuBar menuBar = new MenuBar(fileMenu);
fileMenu.getItems().addAll(saveMenuItem, restoreMenuItem);
BorderPane mainBorderPane = new BorderPane();
mainBorderPane.setTop(menuBar);
mainBorderPane.setCenter(dockPane);
// show that overlays are relative to the docking area
mainBorderPane.setLeft(new AnchorPane(generateRandomTree()));
primaryStage.setScene(new Scene(mainBorderPane, 800, 500));
primaryStage.sizeToScene();
primaryStage.show();
// can be created and docked before or after the scene is created
// and the stage is shown
DockNode treeDock = new DockNode(generateRandomTree(), "Tree Dock", new ImageView(dockImage));
DockNode treeDock = new DockNode(generateRandomTree(), "Tree Dock1", new ImageView(dockImage));
treeDock.setPrefSize(100, 100);
treeDock.dock(dockPane, DockPos.LEFT);
treeDock = new DockNode(generateRandomTree(), "Tree Dock", new ImageView(dockImage));
treeDock = new DockNode(generateRandomTree(), "Tree Dock2", new ImageView(dockImage));
treeDock.setPrefSize(100, 100);
treeDock.dock(dockPane, DockPos.RIGHT);
// If you want to get notified when the docknode is closed. You can add ChangeListener to DockNode's closedProperty()
treeDock.closedProperty().addListener( new ChangeListener< Boolean >()
{
@Override public void changed( ObservableValue< ? extends Boolean > observable, Boolean oldValue, Boolean newValue )
{
if(newValue)
System.out.println("TreeDock(DockPos.RIGHT) is closed.");
}
} );
// test the look and feel with both Caspian and Modena
Application.setUserAgentStylesheet(Application.STYLESHEET_MODENA);
// initialize the default styles for the dock pane and undocked nodes using the DockFX
......@@ -175,4 +191,23 @@ public class DockFX extends Application {
return treeView;
}
public static boolean dirExist(String dir)
{
String path = getUserDataDirectory();
if(!new File(path).exists())
return new File(path).mkdirs();
else
return true;
}
public static String getUserDataDirectory() {
return System.getProperty("user.home") + File.separator + ".dockfx" + File.separator
+ getApplicationVersionString() + File.separator;
}
public static String getApplicationVersionString() {
return "1.0";
}
}
/**
* @file DockFX.java
* @brief Driver demonstrating basic dock layout with prototypes. Maintained in a separate package
* to ensure the encapsulation of org.dockfx private package members.
*
* @section License
*
* This file is a part of the DockFX Library. Copyright (C) 2015 Robert B. Colton
*
* This program is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program. If not, see <http://www.gnu.org/licenses/>.
**/
package org.dockfx.demo;
import org.dockfx.DockPane;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToolBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.dockfx.DockNode;
import org.dockfx.DockPos;
/**
* This app creates two dock panes, one over the other. Nodes can be added to either.
* If dock pane A is "exclusive", then A will ignore nodes from B (because A is
* exclusive and won't accept nodes from any other dockpane, and B will ignore nodes
* from A because A is exclusive and won't let go of them.
*
* If neither A or B is exclusive, Issue #24 from RobertBColton/DockFX will occur.
* @author will
*/
public class TwoDockPanes extends Application {
public static void main(String[] args) {
launch(args);
}
private VBox vbox;
private DockPane dp1;
private DockPane dp2;
private int counter = 0;
private final Image dockImage =
new Image(DockFX.class.getResource("docknode.png").toExternalForm());
@SuppressWarnings("unchecked")
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("DockFX");
vbox = new VBox();
dp1 = makeDockPane("A");
dp2 = makeDockPane("B");
dp1.setExclusive(true);
primaryStage.setScene(new Scene(vbox, 800, 500));
primaryStage.sizeToScene();
primaryStage.show();
// test the look and feel with both Caspian and Modena
Application.setUserAgentStylesheet(Application.STYLESHEET_MODENA);
DockPane.initializeDefaultUserAgentStylesheet();
}
private DockPane makeDockPane(String name) {
ToolBar bar = new ToolBar();
Label lab = new Label(name);
Button addButton = new Button("Add");
bar.getItems().add(lab);
bar.getItems().add(addButton);
DockPane dp = new DockPane();
VBox.setVgrow(dp, Priority.ALWAYS);
addButton.setOnAction(evt -> addNode(dp, name));
vbox.getChildren().add(bar);
vbox.getChildren().add(dp);
return dp;
}
private void addNode(DockPane dp, String dockName) {
int n = ++counter;
String title = dockName + "Node " + counter;
TextArea ta = new TextArea();
ta.setText(title + "\n\nJust some test data");
DockNode dn = new DockNode(ta, title, new ImageView(dockImage));
dn.dock(dp, DockPos.BOTTOM);
}
}
package org.dockfx.pane;
import org.dockfx.DockPos;
import java.util.List;
import java.util.Stack;
import javafx.scene.Node;
import javafx.scene.Parent;
/**
* ContentPane interface has common functions for Content window
*
* @author HongKee Moon
*/
public interface ContentPane {
/**
* The enum ContentPane Type.
*/
public enum Type {
/**
* The SplitPane.
*/
SplitPane,
/**
* The TabPane.
*/
TabPane
}
/**
* Gets type of ContentPane.
*
* @return the type
*/
Type getType();
/**
* Add a node.
*
* @param root the root
* @param sibling the sibling
* @param node the node
* @param dockPos the dock pos
*/
void addNode(Node root, Node sibling, Node node, DockPos dockPos);
/**
* Remove the node.
*
* @param stack the stack
* @param node the node
* @return true if the node removed successfully, otherwise false
*/
boolean removeNode(Stack<Parent> stack, Node node);
/**
* Gets sibling's parent.
*
* @param stack the stack
* @param sibling the sibling
* @return the sibling parent
*/
ContentPane getSiblingParent(Stack<Parent> stack, Node sibling);
/**
* Gets children list.
*
* @return the children list
*/
List<Node> getChildrenList();
/**
* Replace the previous element with new one
*
* @param sibling the sibling
* @param node the node
*/
void set(Node sibling, Node node);
/**
* Replace the previous element with new one by index id
*
* @param idx the idx
* @param node the node
*/
void set(int idx, Node node);
/**
* Gets content parent.
*
* @return the content parent
*/
ContentPane getContentParent();
/**
* Sets content parent.
*
* @param pane the pane
*/
void setContentParent(ContentPane pane);
}
package org.dockfx.pane;
import java.util.Comparator;
import org.dockfx.DockNode;
import org.dockfx.DockPos;
import java.util.List;
import java.util.Stack;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.SplitPane;
/**
* ContentSplitPane contains multiple SplitPane
*
* @author Robert B. Colton
* @author HongKee Moon
*/
public class ContentSplitPane extends SplitPane implements ContentPane {