From 8db4f69797e0ea1221a9b41ed06a1f0a87afafe9 Mon Sep 17 00:00:00 2001 From: Colin DuPlantis Date: Fri, 17 Mar 2023 17:01:29 -0700 Subject: [PATCH 1/4] MATP-1102 Speculative work on changing window manager --- photon/pom.xml | 2 +- .../org/marketcetera/ui/DragResizeMod.java | 337 +++++++++ .../java/org/marketcetera/ui/DragResizer.java | 115 +++ .../java/org/marketcetera/ui/Draggable.java | 152 ++++ .../ui/{App.java => PhotonApp.java} | 25 +- .../marketcetera/ui/PrimaryController.java | 2 +- .../marketcetera/ui/SecondaryController.java | 2 +- .../ui/admin/view/PermissionView.java | 37 +- .../marketcetera/ui/admin/view/RoleView.java | 37 +- .../marketcetera/ui/admin/view/UserView.java | 43 +- .../ui/fix/view/FixSessionView.java | 23 +- .../marketdata/view/MarketDataDetailView.java | 15 +- .../marketdata/view/MarketDataListView.java | 16 +- .../ui/service/PhotonNotificationService.java | 4 +- .../marketcetera/ui/service/StyleService.java | 2 +- .../ui/service/WindowManagerService.java | 711 +++++++++++++----- .../ui/strategy/view/StrategyView.java | 27 +- .../view/FixMessageDetailsView.java | 15 +- .../view/AbstractDeletableFixMessageView.java | 6 +- .../ui/trade/view/AbstractFixMessageView.java | 24 +- .../view/averageprice/AveragePriceView.java | 6 +- .../ui/trade/view/fills/FillsView.java | 6 +- .../trade/view/openorders/OpenOrderView.java | 5 +- .../view/orderticket/OrderTicketView.java | 24 +- .../ui/trade/view/reports/ReportsView.java | 6 +- .../ui/view/AbstractContentView.java | 12 +- .../ui/view/AbstractContentViewFactory.java | 4 +- .../org/marketcetera/ui/view/ContentView.java | 8 +- .../ui/view/ContentViewFactory.java | 6 +- photon/src/main/resources/dark-mode.css | 27 + photon/todo.txt | 8 +- 31 files changed, 1320 insertions(+), 387 deletions(-) create mode 100644 photon/src/main/java/org/marketcetera/ui/DragResizeMod.java create mode 100644 photon/src/main/java/org/marketcetera/ui/DragResizer.java create mode 100644 photon/src/main/java/org/marketcetera/ui/Draggable.java rename photon/src/main/java/org/marketcetera/ui/{App.java => PhotonApp.java} (95%) diff --git a/photon/pom.xml b/photon/pom.xml index 77d24b7e64..0080e3bb00 100644 --- a/photon/pom.xml +++ b/photon/pom.xml @@ -134,7 +134,7 @@ default-cli - org.marketcetera.ui.App + org.marketcetera.ui.PhotonApp src/test/cmd_exec diff --git a/photon/src/main/java/org/marketcetera/ui/DragResizeMod.java b/photon/src/main/java/org/marketcetera/ui/DragResizeMod.java new file mode 100644 index 0000000000..e3b039940e --- /dev/null +++ b/photon/src/main/java/org/marketcetera/ui/DragResizeMod.java @@ -0,0 +1,337 @@ +package org.marketcetera.ui; + +import javafx.event.EventHandler; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.canvas.Canvas; +import javafx.scene.input.MouseEvent; +import javafx.scene.shape.Rectangle; + +/** + * ************* How to use ************************ + * + * Rectangle rectangle = new Rectangle(50, 50); + * rectangle.setFill(Color.BLACK); + * DragResizeMod.makeResizable(rectangle, null); + * + * Pane root = new Pane(); + * root.getChildren().add(rectangle); + * + * primaryStage.setScene(new Scene(root, 300, 275)); + * primaryStage.show(); + * + * ************* OnDragResizeEventListener ********** + * + * You need to override OnDragResizeEventListener and + * 1) preform out of main field bounds check + * 2) make changes to the node + * (this class will not change anything in node coordinates) + * + * There is defaultListener and it works only with Canvas nad Rectangle + */ + +public class DragResizeMod { + public interface OnDragResizeEventListener { + void onDrag(Node node, double x, double y, double h, double w); + + void onResize(Node node, double x, double y, double h, double w); + } + + private static final OnDragResizeEventListener defaultListener = new OnDragResizeEventListener() { + @Override + public void onDrag(Node node, double x, double y, double h, double w) { + /* + // TODO find generic way to get parent width and height of any node + // can perform out of bounds check here if you know your parent size + if (x > width - w ) x = width - w; + if (y > height - h) y = height - h; + if (x < 0) x = 0; + if (y < 0) y = 0; + */ + setNodeSize(node, x, y, h, w); + } + + @Override + public void onResize(Node node, double x, double y, double h, double w) { + /* + // TODO find generic way to get parent width and height of any node + // can perform out of bounds check here if you know your parent size + if (w > width - x) w = width - x; + if (h > height - y) h = height - y; + if (x < 0) x = 0; + if (y < 0) y = 0; + */ + setNodeSize(node, x, y, h, w); + } + + private void setNodeSize(Node node, double x, double y, double h, double w) { + node.setLayoutX(x); + node.setLayoutY(y); + // TODO find generic way to set width and height of any node + // here we cant set height and width to node directly. + // or i just cant find how to do it, + // so you have to wright resize code anyway for your Nodes... + //something like this + if (node instanceof Canvas) { + ((Canvas) node).setWidth(w); + ((Canvas) node).setHeight(h); + } else if (node instanceof Rectangle) { + ((Rectangle) node).setWidth(w); + ((Rectangle) node).setHeight(h); + } + } + }; + + public static enum S { + DEFAULT, + DRAG, + NW_RESIZE, + SW_RESIZE, + NE_RESIZE, + SE_RESIZE, + E_RESIZE, + W_RESIZE, + N_RESIZE, + S_RESIZE; + } + + + private double clickX, clickY, nodeX, nodeY, nodeH, nodeW; + + private S state = S.DEFAULT; + + private Node node; + private OnDragResizeEventListener listener = defaultListener; + + private static final int MARGIN = 8; + private static final double MIN_W = 30; + private static final double MIN_H = 20; + + private DragResizeMod(Node node, OnDragResizeEventListener listener) { + this.node = node; + if (listener != null) + this.listener = listener; + } + + public static void makeResizable(Node node) { + makeResizable(node, null); + } + + public static void makeResizable(Node node, OnDragResizeEventListener listener) { + final DragResizeMod resizer = new DragResizeMod(node, listener); + + node.setOnMousePressed(new EventHandler() { + @Override + public void handle(MouseEvent event) { + resizer.mousePressed(event); + } + }); + node.setOnMouseDragged(new EventHandler() { + @Override + public void handle(MouseEvent event) { + resizer.mouseDragged(event); + } + }); + node.setOnMouseMoved(new EventHandler() { + @Override + public void handle(MouseEvent event) { + resizer.mouseOver(event); + } + }); + node.setOnMouseReleased(new EventHandler() { + @Override + public void handle(MouseEvent event) { + resizer.mouseReleased(event); + } + }); + } + + protected void mouseReleased(MouseEvent event) { + node.setCursor(Cursor.DEFAULT); + state = S.DEFAULT; + } + + protected void mouseOver(MouseEvent event) { + S state = currentMouseState(event); + Cursor cursor = getCursorForState(state); + node.setCursor(cursor); + } + + private S currentMouseState(MouseEvent event) { + S state = S.DEFAULT; + boolean left = isLeftResizeZone(event); + boolean right = isRightResizeZone(event); + boolean top = isTopResizeZone(event); + boolean bottom = isBottomResizeZone(event); + + if (left && top) state = S.NW_RESIZE; + else if (left && bottom) state = S.SW_RESIZE; + else if (right && top) state = S.NE_RESIZE; + else if (right && bottom) state = S.SE_RESIZE; + else if (right) state = S.E_RESIZE; + else if (left) state = S.W_RESIZE; + else if (top) state = S.N_RESIZE; + else if (bottom) state = S.S_RESIZE; + else if (isInDragZone(event)) state = S.DRAG; + + return state; + } + + private static Cursor getCursorForState(S state) { + switch (state) { + case NW_RESIZE: + return Cursor.NW_RESIZE; + case SW_RESIZE: + return Cursor.SW_RESIZE; + case NE_RESIZE: + return Cursor.NE_RESIZE; + case SE_RESIZE: + return Cursor.SE_RESIZE; + case E_RESIZE: + return Cursor.E_RESIZE; + case W_RESIZE: + return Cursor.W_RESIZE; + case N_RESIZE: + return Cursor.N_RESIZE; + case S_RESIZE: + return Cursor.S_RESIZE; + default: + return Cursor.DEFAULT; + } + } + + + protected void mouseDragged(MouseEvent event) { + + if (listener != null) { + double mouseX = parentX(event.getX()); + double mouseY = parentY(event.getY()); + if (state == S.DRAG) { + listener.onDrag(node, mouseX - clickX, mouseY - clickY, nodeH, nodeW); + } else if (state != S.DEFAULT) { + //resizing + double newX = nodeX; + double newY = nodeY; + double newH = nodeH; + double newW = nodeW; + + // Right Resize + if (state == S.E_RESIZE || state == S.NE_RESIZE || state == S.SE_RESIZE) { + newW = mouseX - nodeX; + } + // Left Resize + if (state == S.W_RESIZE || state == S.NW_RESIZE || state == S.SW_RESIZE) { + newX = mouseX; + newW = nodeW + nodeX - newX; + } + + // Bottom Resize + if (state == S.S_RESIZE || state == S.SE_RESIZE || state == S.SW_RESIZE) { + newH = mouseY - nodeY; + } + // Top Resize + if (state == S.N_RESIZE || state == S.NW_RESIZE || state == S.NE_RESIZE) { + newY = mouseY; + newH = nodeH + nodeY - newY; + } + + //min valid rect Size Check + if (newW < MIN_W) { + if (state == S.W_RESIZE || state == S.NW_RESIZE || state == S.SW_RESIZE) + newX = newX - MIN_W + newW; + newW = MIN_W; + } + + if (newH < MIN_H) { + if (state == S.N_RESIZE || state == S.NW_RESIZE || state == S.NE_RESIZE) + newY = newY + newH - MIN_H; + newH = MIN_H; + } + + listener.onResize(node, newX, newY, newH, newW); + } + } + } + + protected void mousePressed(MouseEvent event) { + + if (isInResizeZone(event)) { + setNewInitialEventCoordinates(event); + state = currentMouseState(event); + } else if (isInDragZone(event)) { + setNewInitialEventCoordinates(event); + state = S.DRAG; + } else { + state = S.DEFAULT; + } + } + + private void setNewInitialEventCoordinates(MouseEvent event) { + nodeX = nodeX(); + nodeY = nodeY(); + nodeH = nodeH(); + nodeW = nodeW(); + clickX = event.getX(); + clickY = event.getY(); + } + + private boolean isInResizeZone(MouseEvent event) { + return isLeftResizeZone(event) || isRightResizeZone(event) + || isBottomResizeZone(event) || isTopResizeZone(event); + } + + private boolean isInDragZone(MouseEvent event) { + double xPos = parentX(event.getX()); + double yPos = parentY(event.getY()); + double nodeX = nodeX() + MARGIN; + double nodeY = nodeY() + MARGIN; + double nodeX0 = nodeX() + nodeW() - MARGIN; + double nodeY0 = nodeY() + nodeH() - MARGIN; + + return (xPos > nodeX && xPos < nodeX0) && (yPos > nodeY && yPos < nodeY0); + } + + private boolean isLeftResizeZone(MouseEvent event) { + return intersect(0, event.getX()); + } + + private boolean isRightResizeZone(MouseEvent event) { + return intersect(nodeW(), event.getX()); + } + + private boolean isTopResizeZone(MouseEvent event) { + return intersect(0, event.getY()); + } + + private boolean isBottomResizeZone(MouseEvent event) { + return intersect(nodeH(), event.getY()); + } + + private boolean intersect(double side, double point) { + return side + MARGIN > point && side - MARGIN < point; + } + + private double parentX(double localX) { + return nodeX() + localX; + } + + private double parentY(double localY) { + return nodeY() + localY; + } + + private double nodeX() { + return node.getBoundsInParent().getMinX(); + } + + private double nodeY() { + return node.getBoundsInParent().getMinY(); + } + + private double nodeW() { + return node.getBoundsInParent().getWidth(); + } + + private double nodeH() { + return node.getBoundsInParent().getHeight(); + } +} diff --git a/photon/src/main/java/org/marketcetera/ui/DragResizer.java b/photon/src/main/java/org/marketcetera/ui/DragResizer.java new file mode 100644 index 0000000000..29191c7ddd --- /dev/null +++ b/photon/src/main/java/org/marketcetera/ui/DragResizer.java @@ -0,0 +1,115 @@ +package org.marketcetera.ui; + + +import javafx.event.EventHandler; +import javafx.scene.Cursor; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Region; + +/** + * {@link DragResizer} can be used to add mouse listeners to a {@link Region} + * and make it resizable by the user by clicking and dragging the border in the + * same way as a window. + *

+ * Only height resizing is currently implemented. Usage:

DragResizer.makeResizable(myAnchorPane);
+ * + * @author atill + * + */ +public class DragResizer { + + /** + * The margin around the control that a user can click in to start resizing + * the region. + */ + private static final int RESIZE_MARGIN = 5; + + private final Region region; + + private double y; + + private boolean initMinHeight; + + private boolean dragging; + + private DragResizer(Region aRegion) { + region = aRegion; + } + + public static void makeResizable(Region region) { + final DragResizer resizer = new DragResizer(region); + + region.setOnMousePressed(new EventHandler() { + @Override + public void handle(MouseEvent event) { + resizer.mousePressed(event); + }}); + region.setOnMouseDragged(new EventHandler() { + @Override + public void handle(MouseEvent event) { + resizer.mouseDragged(event); + }}); + region.setOnMouseMoved(new EventHandler() { + @Override + public void handle(MouseEvent event) { + resizer.mouseOver(event); + }}); + region.setOnMouseReleased(new EventHandler() { + @Override + public void handle(MouseEvent event) { + resizer.mouseReleased(event); + }}); + } + + protected void mouseReleased(MouseEvent event) { + dragging = false; + region.setCursor(Cursor.DEFAULT); + } + + protected void mouseOver(MouseEvent event) { + if(isInDraggableZone(event) || dragging) { + region.setCursor(Cursor.S_RESIZE); + } + else { + region.setCursor(Cursor.DEFAULT); + } + } + + protected boolean isInDraggableZone(MouseEvent event) { + return event.getY() > (region.getHeight() - RESIZE_MARGIN); + } + + protected void mouseDragged(MouseEvent event) { + if(!dragging) { + return; + } + + double mousey = event.getY(); + + double newHeight = region.getMinHeight() + (mousey - y); + + region.setMinHeight(newHeight); + + y = mousey; + } + + protected void mousePressed(MouseEvent event) { + + // ignore clicks outside of the draggable margin + if(!isInDraggableZone(event)) { + return; + } + + dragging = true; + + // make sure that the minimum height is set to the current height once, + // setting a min height that is smaller than the current height will + // have no effect + if (!initMinHeight) { + region.setMinHeight(region.getHeight()); + initMinHeight = true; + } + + y = event.getY(); + } +} diff --git a/photon/src/main/java/org/marketcetera/ui/Draggable.java b/photon/src/main/java/org/marketcetera/ui/Draggable.java new file mode 100644 index 0000000000..a44d673e0a --- /dev/null +++ b/photon/src/main/java/org/marketcetera/ui/Draggable.java @@ -0,0 +1,152 @@ +package org.marketcetera.ui; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javafx.event.EventHandler; +import javafx.scene.Node; +import javafx.scene.input.MouseEvent; + +/** + * Generalised implementation of 'Draggability' of a {@link Node}. The Draggable class is used as a 'namespace' for the internal + * class/interfaces/enum. + * @author phill + * + */ +public class Draggable { + public enum Event { + None, DragStart, Drag, DragEnd + } + + /** + * Marker for an entity that has draggable nature. + * @author phill + */ + public interface Interface { + public abstract Draggable.Nature getDraggableNature(); + } + + public interface Listener { + public void accept(Nature draggableNature, Event dragEvent); + } + + /** + * Class that encapsulates the draggable nature of a node. + *
    + *
  • EventNode: the event that receives the drag events
  • + *
  • One or more DragNodes: that move in response to the drag events. The EventNode is usually (but not always) a + * DragNode
  • + *
  • Listeners: listen for the drag events
  • + *
+ * @author phill + * + */ + public static final class Nature implements EventHandler { + private double lastMouseX = 0, lastMouseY = 0; // scene coords + + private boolean dragging = false; + + private final boolean enabled = true; + private final Node eventNode; + private final List dragNodes = new ArrayList<>(); + private final List dragListeners = new ArrayList<>(); + + public Nature(final Node node) { + this(node, node); + } + + public Nature(final Node eventNode, final Node... dragNodes) { + this.eventNode = eventNode; + this.dragNodes.addAll(Arrays.asList(dragNodes)); + this.eventNode.addEventHandler(MouseEvent.ANY, this); + } + + public final boolean addDraggedNode(final Node node) { + if (!this.dragNodes.contains(node)) { + return this.dragNodes.add(node); + } + return false; + } + + public final boolean addListener(final Listener listener) { + return this.dragListeners.add(listener); + } + + public final void detatch() { + this.eventNode.removeEventFilter(MouseEvent.ANY, this); + } + + public final List getDragNodes() { + return new ArrayList<>(this.dragNodes); + } + + public final Node getEventNode() { + return this.eventNode; + } + + @Override + public final void handle(final MouseEvent event) { + if (MouseEvent.MOUSE_PRESSED == event.getEventType()) { + if (this.enabled && this.eventNode.contains(event.getX(), event.getY())) { + this.lastMouseX = event.getSceneX(); + this.lastMouseY = event.getSceneY(); + event.consume(); + } + } else if (MouseEvent.MOUSE_DRAGGED == event.getEventType()) { + if (!this.dragging) { + this.dragging = true; + for (final Listener listener : this.dragListeners) { + listener.accept(this, Draggable.Event.DragStart); + } + } + if (this.dragging) { + final double deltaX = event.getSceneX() - this.lastMouseX; + final double deltaY = event.getSceneY() - this.lastMouseY; + + for (final Node dragNode : this.dragNodes) { + final double initialTranslateX = dragNode.getTranslateX(); + final double initialTranslateY = dragNode.getTranslateY(); + dragNode.setTranslateX(initialTranslateX + deltaX); + dragNode.setTranslateY(initialTranslateY + deltaY); + } + + this.lastMouseX = event.getSceneX(); + this.lastMouseY = event.getSceneY(); + + event.consume(); + for (final Listener listener : this.dragListeners) { + listener.accept(this, Draggable.Event.Drag); + } + } + } else if (MouseEvent.MOUSE_RELEASED == event.getEventType()) { + if (this.dragging) { + event.consume(); + this.dragging = false; + for (final Listener listener : this.dragListeners) { + listener.accept(this, Draggable.Event.DragEnd); + } + } + } + + } + + public final boolean removeDraggedNode(final Node node) { + return this.dragNodes.remove(node); + } + + public final boolean removeListener(final Listener listener) { + return this.dragListeners.remove(listener); + } + + /** + * When the initial mousePressed is missing we can supply the first coordinates programmatically. + * @param lastMouseX + * @param lastMouseY + */ + public final void setLastMouse(final double lastMouseX, final double lastMouseY) { + this.lastMouseX = lastMouseX; + this.lastMouseY = lastMouseY; + } + } +} diff --git a/photon/src/main/java/org/marketcetera/ui/App.java b/photon/src/main/java/org/marketcetera/ui/PhotonApp.java similarity index 95% rename from photon/src/main/java/org/marketcetera/ui/App.java rename to photon/src/main/java/org/marketcetera/ui/PhotonApp.java index 65f00d2336..b3c077721e 100644 --- a/photon/src/main/java/org/marketcetera/ui/App.java +++ b/photon/src/main/java/org/marketcetera/ui/PhotonApp.java @@ -31,23 +31,24 @@ import javafx.scene.control.ToolBar; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; import javafx.scene.layout.Priority; -import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.stage.Stage; /* $License$ */ /** - * + * Main Photon Application. * * @author Colin DuPlantis * @version $Id$ * @since $Release$ * @see https://openjfx.io/openjfx-docs/#maven */ -public class App +public class PhotonApp extends Application { /* (non-Javadoc) @@ -77,7 +78,7 @@ public void start(Stage inPrimaryStage) windowManagerService.initializeMainStage(primaryStage); root = new VBox(); menuLayout = new VBox(); - workspace = new VBox(); + workspace = new FlowPane(); workspace.setId(getClass().getCanonicalName() + ".workspace"); workspace.setPrefWidth(1024); workspace.setPrefHeight(768); @@ -87,8 +88,8 @@ public void start(Stage inPrimaryStage) workspace, separator, footer); - Scene mainScene = new Scene(root); - inPrimaryStage.setScene(mainScene); + scene = new Scene(root); + inPrimaryStage.setScene(scene); inPrimaryStage.setTitle("Marketcetera Automated Trading Platform"); inPrimaryStage.getIcons().addAll(new Image("/images/photon-16x16.png"), new Image("/images/photon-24x24.png"), @@ -125,8 +126,8 @@ public void start(Stage inPrimaryStage) separator, footer, root); - mainScene.getStylesheets().clear(); - mainScene.getStylesheets().add("dark-mode.css"); + scene.getStylesheets().clear(); + scene.getStylesheets().add("dark-mode.css"); inPrimaryStage.show(); doLogin(); } @@ -221,7 +222,7 @@ private void showMenu() } ApplicationMenu applicationMenu = currentUser.getAttribute(ApplicationMenu.class); if(applicationMenu == null) { - SLF4JLoggerProxy.debug(App.class, + SLF4JLoggerProxy.debug(PhotonApp.class, "Session is now logged in, building application menu"); applicationMenu = applicationContext.getBean(ApplicationMenu.class); menuLayout.getChildren().add(applicationMenu.getMenu()); @@ -245,14 +246,14 @@ static void setRoot(String fxml) private static Parent loadFXML(String fxml) throws IOException { - FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml")); + FXMLLoader fxmlLoader = new FXMLLoader(PhotonApp.class.getResource(fxml + ".fxml")); return fxmlLoader.load(); } public static Stage getPrimaryStage() { return primaryStage; } - public static Region getWorkspace() + public static Pane getWorkspace() { return workspace; } @@ -292,7 +293,7 @@ public static void main(String[] args) private HBox footer; private Label clockLabel; private Label userLabel; - private static VBox workspace; + private static FlowPane workspace; private ToolBar statusToolBar; private ToolBar footerToolBar; private PhotonNotificationService notificationService; diff --git a/photon/src/main/java/org/marketcetera/ui/PrimaryController.java b/photon/src/main/java/org/marketcetera/ui/PrimaryController.java index e8b1d203fc..609bf40a4e 100644 --- a/photon/src/main/java/org/marketcetera/ui/PrimaryController.java +++ b/photon/src/main/java/org/marketcetera/ui/PrimaryController.java @@ -7,6 +7,6 @@ public class PrimaryController { @FXML private void switchToSecondary() throws IOException { - App.setRoot("secondary"); + PhotonApp.setRoot("secondary"); } } diff --git a/photon/src/main/java/org/marketcetera/ui/SecondaryController.java b/photon/src/main/java/org/marketcetera/ui/SecondaryController.java index d2b40cf004..9cc72bd1f3 100644 --- a/photon/src/main/java/org/marketcetera/ui/SecondaryController.java +++ b/photon/src/main/java/org/marketcetera/ui/SecondaryController.java @@ -7,6 +7,6 @@ public class SecondaryController { @FXML private void switchToPrimary() throws IOException { - App.setRoot("primary"); + PhotonApp.setRoot("primary"); } } \ No newline at end of file diff --git a/photon/src/main/java/org/marketcetera/ui/admin/view/PermissionView.java b/photon/src/main/java/org/marketcetera/ui/admin/view/PermissionView.java index 7d748e8e35..47a5498468 100644 --- a/photon/src/main/java/org/marketcetera/ui/admin/view/PermissionView.java +++ b/photon/src/main/java/org/marketcetera/ui/admin/view/PermissionView.java @@ -5,6 +5,8 @@ import java.util.function.Consumer; import java.util.function.Function; +import javax.annotation.PostConstruct; + import org.apache.commons.lang3.StringUtils; import org.marketcetera.admin.AdminPermissions; import org.marketcetera.admin.impl.SimplePermission; @@ -16,7 +18,6 @@ import org.marketcetera.ui.service.admin.AdminClientService; import org.marketcetera.ui.view.AbstractContentView; import org.marketcetera.util.log.SLF4JLoggerProxy; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -25,7 +26,7 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; import javafx.geometry.Insets; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; @@ -43,7 +44,6 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import javafx.stage.Stage; /* $License$ */ @@ -62,11 +62,11 @@ public class PermissionView /** * Create a new PermissionView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - public PermissionView(Stage inParentWindow, + public PermissionView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { @@ -77,11 +77,11 @@ public PermissionView(Stage inParentWindow, /** * Validate and start the object. */ - @Autowired + @PostConstruct public void start() { adminClientService = serviceManager.getService(AdminClientService.class); - VBox layout = new VBox(5); + mainLayout = new VBox(5); initializeTable(); buttonLayout = new HBox(5); addPermissionButton = new Button("Add Permission"); @@ -90,9 +90,16 @@ public void start() addPermissionButton.setDisable(!userHasCreatePermissionPermission); addPermissionButton.setOnAction(event -> doAddOrUpdatePermission(new SimplePermission(),true)); buttonLayout.getChildren().add(addPermissionButton); - layout.getChildren().addAll(permissionsTable, + mainLayout.getChildren().addAll(permissionsTable, buttonLayout); - mainScene = new Scene(layout); + } + /* (non-Javadoc) + * @see org.marketcetera.ui.view.ContentView#getNode() + */ + @Override + public Node getNode() + { + return mainLayout; } /** * Update the users displayed in the table. @@ -351,14 +358,6 @@ public String getViewName() { return NAME; } - /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() - */ - @Override - public Scene getScene() - { - return mainScene; - } /** * update user context menu item */ @@ -396,9 +395,9 @@ public Scene getScene() */ private ContextMenu permissionsTableContextMenu; /** - * main scene of the view + * main layout */ - private Scene mainScene; + private VBox mainLayout; /** * global name of this view */ diff --git a/photon/src/main/java/org/marketcetera/ui/admin/view/RoleView.java b/photon/src/main/java/org/marketcetera/ui/admin/view/RoleView.java index 2df96f30bf..35996f27c6 100644 --- a/photon/src/main/java/org/marketcetera/ui/admin/view/RoleView.java +++ b/photon/src/main/java/org/marketcetera/ui/admin/view/RoleView.java @@ -6,6 +6,8 @@ import java.util.function.Consumer; import java.util.function.Function; +import javax.annotation.PostConstruct; + import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.CompareToBuilder; import org.marketcetera.admin.AdminPermissions; @@ -20,7 +22,6 @@ import org.marketcetera.ui.service.admin.AdminClientService; import org.marketcetera.ui.view.AbstractContentView; import org.marketcetera.util.log.SLF4JLoggerProxy; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -31,7 +32,7 @@ import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; @@ -52,7 +53,6 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import javafx.stage.Stage; import javafx.util.Callback; /* $License$ */ @@ -72,11 +72,11 @@ public class RoleView /** * Create a new RoleView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - public RoleView(Stage inParentWindow, + public RoleView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { @@ -92,22 +92,14 @@ public String getViewName() { return NAME; } - /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() - */ - @Override - public Scene getScene() - { - return mainScene; - } /** * Validate and start the object. */ - @Autowired + @PostConstruct public void start() { adminClientService = serviceManager.getService(AdminClientService.class); - VBox layout = new VBox(5); + mainLayout = new VBox(5); initializeTable(); buttonLayout = new HBox(5); addRoleButton = new Button("Add Role"); @@ -116,9 +108,16 @@ public void start() addRoleButton.setDisable(!userHasCreateRolePermission); addRoleButton.setOnAction(event -> doAddOrUpdateRole(new SimpleRole(),true)); buttonLayout.getChildren().add(addRoleButton); - layout.getChildren().addAll(rolesTable, + mainLayout.getChildren().addAll(rolesTable, buttonLayout); - mainScene = new Scene(layout); + } + /* (non-Javadoc) + * @see org.marketcetera.ui.view.ContentView#getNode() + */ + @Override + public Node getNode() + { + return mainLayout; } /** * Update the users displayed in the table. @@ -506,9 +505,9 @@ public void updateItem(Permission person, boolean empty) { */ private ContextMenu rolesTableContextMenu; /** - * main scene of the view + * main layout of the view */ - private Scene mainScene; + private VBox mainLayout; /** * global name of this view */ diff --git a/photon/src/main/java/org/marketcetera/ui/admin/view/UserView.java b/photon/src/main/java/org/marketcetera/ui/admin/view/UserView.java index cfb23d8048..56528856fe 100644 --- a/photon/src/main/java/org/marketcetera/ui/admin/view/UserView.java +++ b/photon/src/main/java/org/marketcetera/ui/admin/view/UserView.java @@ -5,6 +5,8 @@ import java.util.function.Consumer; import java.util.function.Function; +import javax.annotation.PostConstruct; + import org.apache.commons.lang3.StringUtils; import org.marketcetera.admin.AdminPermissions; import org.marketcetera.admin.impl.SimpleUser; @@ -16,7 +18,6 @@ import org.marketcetera.ui.service.admin.AdminClientService; import org.marketcetera.ui.view.AbstractContentView; import org.marketcetera.util.log.SLF4JLoggerProxy; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -25,7 +26,7 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; import javafx.geometry.Insets; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; @@ -46,7 +47,6 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import javafx.stage.Stage; /* $License$ */ @@ -63,28 +63,36 @@ public class UserView extends AbstractContentView { /** - * Create a new FillsView instance. + * Create a new UserView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - public UserView(Stage inParentWindow, - NewWindowEvent inEvent, - Properties inViewProperties) + public UserView(Node inParentWindow, + NewWindowEvent inEvent, + Properties inViewProperties) { super(inParentWindow, inEvent, inViewProperties); } + /* (non-Javadoc) + * @see org.marketcetera.ui.view.ContentView#getNode() + */ + @Override + public Node getNode() + { + return mainLayout; + } /** * Validate and start the object. */ - @Autowired + @PostConstruct public void start() { adminClientService = serviceManager.getService(AdminClientService.class); - VBox layout = new VBox(5); + mainLayout = new VBox(5); initializeTable(); buttonLayout = new HBox(5); addUserButton = new Button("Add User"); @@ -93,9 +101,8 @@ public void start() addUserButton.setDisable(!userHasCreateUserPermission); addUserButton.setOnAction(event -> doAddOrUpdateUser(new SimpleUser(),true)); buttonLayout.getChildren().add(addUserButton); - layout.getChildren().addAll(usersTable, + mainLayout.getChildren().addAll(usersTable, buttonLayout); - mainScene = new Scene(layout); } /** * Update the users displayed in the table. @@ -574,14 +581,6 @@ public String getViewName() { return NAME; } - /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() - */ - @Override - public Scene getScene() - { - return mainScene; - } /** * update user context menu item */ @@ -635,9 +634,9 @@ public Scene getScene() */ private ContextMenu usersTableContextMenu; /** - * main scene of the view + * main node of the view */ - private Scene mainScene; + private VBox mainLayout; /** * global name of this view */ diff --git a/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java b/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java index 28cd35452a..11f1eb51ce 100644 --- a/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java +++ b/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java @@ -39,7 +39,7 @@ import org.marketcetera.persist.CollectionPageResponse; import org.marketcetera.persist.PageRequest; import org.marketcetera.quickfix.FIXVersion; -import org.marketcetera.ui.App; +import org.marketcetera.ui.PhotonApp; import org.marketcetera.ui.PhotonServices; import org.marketcetera.ui.events.NewWindowEvent; import org.marketcetera.ui.events.NotificationEvent; @@ -63,7 +63,6 @@ import javafx.beans.value.ChangeListener; import javafx.geometry.Insets; import javafx.scene.Node; -import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; @@ -104,12 +103,12 @@ public class FixSessionView implements ContentView,BrokerStatusListener { /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() + * @see org.marketcetera.ui.view.ContentView#getNode() */ @Override - public Scene getScene() + public Node getNode() { - return scene; + return rootLayout; } /* (non-Javadoc) * @see org.marketcetera.brokers.BrokerStatusListener#receiveBrokerStatus(org.marketcetera.fix.ActiveFixSession) @@ -171,19 +170,18 @@ public void start() initializeTable(); rootLayout.getChildren().addAll(fixSessionsTable, buttonLayout); - scene = new Scene(rootLayout); updateSessions(); } /** - * Create a new OrderTicketView instance. + * Create a new FixSessionView instance. * - * @param inParent a Window value + * @param inParent a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inProperties a Properties value */ - public FixSessionView(Stage inParent, - NewWindowEvent inEvent, - Properties inProperties) + public FixSessionView(Node inParent, + NewWindowEvent inEvent, + Properties inProperties) { super(inParent, inEvent, @@ -454,7 +452,7 @@ private void updateFixSession(DisplayFixSession inFixSession, final String acceptorString = "Acceptor"; final String initiatorString = "Initiator"; final String incomingFixSessionName = inFixSession.getSource().getFixSession().getName(); - Wizard wizard = new Wizard(App.getPrimaryStage()); + Wizard wizard = new Wizard(PhotonApp.getPrimaryStage()); wizard.setTitle((inIsNew ? "Add" : "Edit") + " Session"); final ComboBox connectionTypeComboBox = new ComboBox<>(); connectionTypeComboBox.getItems().addAll(acceptorString, @@ -1700,7 +1698,6 @@ public StringProperty valueProperty() private TableColumn senderSequenceNumberTableColumn; private TableColumn targetSequenceNumberTableColumn; private AdminClientService fixAdminClient; - private Scene scene; private VBox rootLayout; private TableView fixSessionsTable; /** diff --git a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailView.java b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailView.java index 3e6b648b7c..94c01a37fd 100644 --- a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailView.java +++ b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailView.java @@ -43,7 +43,7 @@ import javafx.application.Platform; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; @@ -62,7 +62,6 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.RowConstraints; import javafx.scene.layout.VBox; -import javafx.stage.Stage; import javafx.stage.WindowEvent; /* $License$ */ @@ -81,12 +80,12 @@ public class MarketDataDetailView implements ContentView { /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() + * @see org.marketcetera.ui.view.ContentView#getNode() */ @Override - public Scene getScene() + public Node getNode() { - return scene; + return rootLayout; } /* (non-Javadoc) * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) @@ -173,7 +172,6 @@ public void start() event.consume(); } }); - scene = new Scene(rootLayout); if(marketDataInstrument != null) { doMarketDataRequest(); } @@ -181,11 +179,11 @@ public void start() /** * Create a new MarketDataDetailView instance. * - * @param inParent a Window value + * @param inParent a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inProperties a Properties value */ - public MarketDataDetailView(Stage inParent, + public MarketDataDetailView(Node inParent, NewWindowEvent inEvent, Properties inProperties) { @@ -429,7 +427,6 @@ private void initializeChart() private TableView askMarketDataTable; private MarketDataClientService marketDataClient; private TradeClientService tradeClient; - private Scene scene; private VBox rootLayout; private final String symbolsKey = "SYMBOLS"; private HBox addSymbolLayout; diff --git a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java index 998f6dc6fd..ac1d1e84a8 100644 --- a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java +++ b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java @@ -42,7 +42,7 @@ import javafx.application.Platform; import javafx.geometry.Pos; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; @@ -59,7 +59,6 @@ import javafx.scene.input.KeyEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import javafx.stage.Stage; import javafx.stage.WindowEvent; /* $License$ */ @@ -78,12 +77,12 @@ public class MarketDataListView implements ContentView { /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() + * @see org.marketcetera.ui.view.ContentView#getNode() */ @Override - public Scene getScene() + public Node getNode() { - return scene; + return rootLayout; } /* (non-Javadoc) * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) @@ -139,7 +138,6 @@ public void start() event.consume(); } }); - scene = new Scene(rootLayout); } @PreDestroy public void stop() @@ -149,18 +147,17 @@ public void stop() /** * Create a new MarketDataListView instance. * - * @param inParent a Window value + * @param inParent a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inProperties a Properties value */ - public MarketDataListView(Stage inParent, + public MarketDataListView(Node inParent, NewWindowEvent inEvent, Properties inProperties) { super(inParent, inEvent, inProperties); - System.out.println("COCO: view properties: " + inProperties); } private void updateViewProperties() { @@ -458,7 +455,6 @@ private MarketDataRowListener(MarketDataItem inMarketDataItem) private TableView marketDataTable; private MarketDataClientService marketdataClient; private TradeClientService tradeClient; - private Scene scene; private VBox rootLayout; private final String symbolsKey = "SYMBOLS"; private HBox addSymbolLayout; diff --git a/photon/src/main/java/org/marketcetera/ui/service/PhotonNotificationService.java b/photon/src/main/java/org/marketcetera/ui/service/PhotonNotificationService.java index d3f040c17c..cc88632a62 100644 --- a/photon/src/main/java/org/marketcetera/ui/service/PhotonNotificationService.java +++ b/photon/src/main/java/org/marketcetera/ui/service/PhotonNotificationService.java @@ -5,7 +5,7 @@ import org.controlsfx.control.Notifications; import org.marketcetera.core.PlatformServices; -import org.marketcetera.ui.App; +import org.marketcetera.ui.PhotonApp; import org.marketcetera.ui.events.NotificationEvent; import org.marketcetera.util.log.SLF4JLoggerProxy; import org.springframework.beans.factory.annotation.Autowired; @@ -75,7 +75,7 @@ public void run() .darkStyle() .title(inEvent.getTitle()) .text(inEvent.getMessage()) - .owner(App.getWorkspace()) + .owner(PhotonApp.getWorkspace()) .hideAfter(Duration.seconds(notificationDelay)); notification.threshold(notificationThreshold, notification); diff --git a/photon/src/main/java/org/marketcetera/ui/service/StyleService.java b/photon/src/main/java/org/marketcetera/ui/service/StyleService.java index 732af0acd2..fa9678cfc7 100644 --- a/photon/src/main/java/org/marketcetera/ui/service/StyleService.java +++ b/photon/src/main/java/org/marketcetera/ui/service/StyleService.java @@ -45,7 +45,7 @@ public void start() */ public void addStyle(ContentView inContentView) { - addStyle(inContentView.getScene()); +// addStyle(inContentView.getScene()); } /** * diff --git a/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java b/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java index c83055af0d..93d7cd3a30 100644 --- a/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java +++ b/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java @@ -18,7 +18,10 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.marketcetera.core.PlatformServices; import org.marketcetera.core.Util; -import org.marketcetera.ui.App; +import org.marketcetera.ui.DragResizeMod; +import org.marketcetera.ui.DragResizeMod.OnDragResizeEventListener; +import org.marketcetera.ui.Draggable; +import org.marketcetera.ui.PhotonApp; import org.marketcetera.ui.events.CascadeWindowsEvent; import org.marketcetera.ui.events.CloseWindowsEvent; import org.marketcetera.ui.events.LoginEvent; @@ -39,16 +42,22 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.event.EventHandler; -import javafx.scene.Scene; -import javafx.scene.input.ContextMenuEvent; -import javafx.scene.input.MouseEvent; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; import javafx.stage.Modality; import javafx.stage.Stage; -import javafx.stage.Window; -import javafx.stage.WindowEvent; /* $License$ */ @@ -122,8 +131,8 @@ public void onNewWindow(NewWindowEvent inEvent) "onWindow: {}", inEvent.getWindowTitle()); // create the UI window element - final Stage newWindow = new Stage(); - newWindow.initOwner(App.getPrimaryStage()); + final WindowLayout newWindow = createNewWindowLayout(); +// newWindow.initOwner(PhotonApp.getPrimaryStage()); if(inEvent.getWindowIcon() != null) { // TODO need to convert to Image to show here // newWindow.getIcons().add(PhotonServices.getSvgResource(inEvent.getWindowIcon())); @@ -136,22 +145,12 @@ public void onNewWindow(NewWindowEvent inEvent) WindowMetaData newWindowWrapper = new WindowMetaData(inEvent, newWindow, viewFactory); - ContentView contentView = viewFactory.create(newWindow, + ContentView contentView = viewFactory.create(newWindow.getMainLayout(), inEvent, newWindowWrapper.getProperties()); - newWindow.setOnCloseRequest(inCloseEvent -> { - contentView.onClose(inCloseEvent); - }); - styleService.addStyle(contentView); - Scene rootScene = contentView.getScene(); - rootScene.getStylesheets().clear(); - rootScene.getStylesheets().add("dark-mode.css"); newWindow.setTitle(inEvent.getWindowTitle()); // set properties of the new window based on the received event -// newWindow.initModality(inEvent.isModal()?Modality.APPLICATION_MODAL:Modality.NONE); -// newWindow.initModality(Modality.NONE); - // TODO not sure how to disallow dragging -// newWindow.setDraggable(inEvent.isDraggable()); + newWindow.setDraggable(inEvent.isDraggable()); newWindow.setResizable(inEvent.isResizable()); if(inEvent.getWindowSize().getFirstMember() > 0) { newWindow.setWidth(inEvent.getWindowSize().getFirstMember()); @@ -161,16 +160,367 @@ public void onNewWindow(NewWindowEvent inEvent) } windowRegistry.addWindow(newWindowWrapper); // set the content of the new window - newWindow.setScene(rootScene); + newWindow.setRoot(contentView.getNode()); windowRegistry.addWindowListeners(newWindowWrapper); windowRegistry.updateDisplayLayout(); // TODO pretty sure this isn't right newWindow.getProperties().put(WindowManagerService.windowUuidProp, inEvent.getWindowStyleId()); - newWindow.sizeToScene(); - newWindow.show(); + PhotonApp.getWorkspace().getChildren().add(newWindow.getMainLayout()); newWindow.requestFocus(); -// newWindow.setOnCloseRequest(null); + } + private class WindowLayout + { + private WindowLayout() + { + windowLayout = new VBox(); + windowTitleLayout = new HBox(); + titleLayout = new HBox(); + closeButtonLayout = new HBox(); + contentLayout = new VBox(); + windowLayout.getChildren().addAll(windowTitleLayout, + contentLayout); + windowTitleLayout.getChildren().addAll(titleLayout, + closeButtonLayout); + windowTitle = new Label(); + windowTitle.textProperty().bind(windowTitleProperty); + closeLabel = new Label("X"); + // TODO trigger this when the X is pushed +// newWindow.setOnCloseRequest(inCloseEvent -> { +// contentView.onClose(inCloseEvent); +// }); + + titleLayout.getChildren().addAll(windowTitle); + closeButtonLayout.getChildren().addAll(closeLabel); + windowTitleLayout.getStyleClass().add("title-bar"); + + HBox.setHgrow(windowTitleLayout, + Priority.ALWAYS); + HBox.setHgrow(titleLayout, + Priority.ALWAYS); + HBox.setHgrow(closeButtonLayout, + Priority.NEVER); + windowTitleLayout.setAlignment(Pos.CENTER); + closeButtonLayout.setAlignment(Pos.BASELINE_RIGHT); + closeButtonLayout.setPrefWidth(20); + contentLayout.setAlignment(Pos.CENTER); + VBox.setVgrow(contentLayout, + Priority.ALWAYS); + Draggable.Nature nature = new Draggable.Nature(windowLayout); + DragResizeMod.makeResizable(windowLayout, + new OnDragResizeEventListener() { + @Override + public void onDrag(Node inNode, + double inX, + double inY, + double inH, + double inW) + { + System.out.println("COCO: drag " + inNode + " x=" + inX + " y=" + inY + " height=" + inH + " width=" + inW); + xProperty.set(inX); + yProperty.set(inY); + heightProperty.set(inH); + widthProperty.set(inW); + } + @Override + public void onResize(Node inNode, + double inX, + double inY, + double inH, + double inW) + { + System.out.println("COCO: resize " + inNode + " x=" + inX + " y=" + inY + " height=" + inH + " width=" + inW); + xProperty.set(inX); + yProperty.set(inY); + heightProperty.set(inH); + widthProperty.set(inW); + } + }); + windowLayout.getStyleClass().add("view"); + windowLayout.getStylesheets().clear(); + windowLayout.getStylesheets().add("dark-mode.css"); + windowLayout.minWidthProperty().bindBidirectional(widthProperty); + windowLayout.minHeightProperty().bindBidirectional(heightProperty); +// windowLayout.setAlignment(Pos.CENTER); +// windowLayout.setOnMouseClicked(event -> { +//// windowLayout.toFront(); +// // TODO this warps the window to the upper left +// }); +// windowLayout.addEventHandler(MouseEvent.ANY, this); + +// windowLayout.heightProperty().addListener((observableValue,oldValue,newValue)->{ +// System.out.println("COCO: " + windowTitleProperty.get() + " height: " + newValue); +// heightProperty.set((double)newValue); +// }); +// windowLayout.widthProperty().addListener((observableValue,oldValue,newValue)->{ +// System.out.println("COCO: " + windowTitleProperty.get() + " width: " + newValue); +// widthProperty.set((double)newValue); +// }); +// windowLayout.layoutXProperty().addListener((observableValue,oldValue,newValue)->{ +// System.out.println("COCO: " + windowTitleProperty.get() + " layoutX: " + newValue); +// xProperty.set((double)newValue); +// }); +// windowLayout.layoutYProperty().addListener((observableValue,oldValue,newValue)->{ +// System.out.println("COCO: " + windowTitleProperty.get() + " layoutY: " + newValue); +// yProperty.set((double)newValue); +// }); +// windowLayout.relocate(200,200); + } + /** + * + * + */ + private void requestFocus() + { + windowLayout.requestFocus(); + } + /** + * + * + * @return + */ + private Properties getProperties() + { + return windowProperties; + } + /** + * + * + * @param inNode + */ + private void setRoot(Node inNode) + { + contentLayout.getChildren().add(inNode); + } + /** + * + * + * @param inDraggable + */ + private void setDraggable(boolean inDraggable) + { + draggableProperty.set(inDraggable); + } + /** + * + * + * @param inHeight + */ + private void setHeight(double inHeight) + { + windowLayout.setPrefHeight(inHeight); + } + /** + * + * + * @param inWidth + */ + private void setWidth(double inWidth) + { + windowLayout.setPrefWidth(inWidth); + } + /** + * + * + * @param inResizable + */ + public void setResizable(boolean inResizable) + { + resizableProperty.set(inResizable); + } + /** + * + * + * @param inWindowTitle + */ + private void setTitle(String inWindowTitle) + { + windowTitleProperty.set(inWindowTitle); + } + /** + * + * + * @return + */ + private Node getMainLayout() + { + return windowLayout; + } + /** + * + * + * @return + */ + private double getX() + { + return xProperty.get(); + } + /** + * + * + * @return + */ + private double getY() + { + return yProperty.get(); + } + /** + * + * + * @return + */ + private double getHeight() + { + return heightProperty.get(); + } + /** + * + * + * @return + */ + private double getWidth() + { + return widthProperty.get(); + } + /** + * + * + * @return + */ + private boolean isMaximized() + { + return maximizedProperty.get(); + } + /** + * + * + * @return + */ + private String getTitle() + { + return windowTitle.getText(); + } + /** + * + * + * @return + */ + private Modality getModality() + { + return modalityProperty.get(); + } + /** + * + * + * @return + */ + private boolean isDraggable() + { + return draggableProperty.get(); + } + /** + * + * + * @return + */ + private boolean isResizable() + { + return resizableProperty.get(); + } + /** + * + * + * @return + */ + private double getScrollLeft() + { + return scrollLeftProperty.get(); + } + /** + * + * + * @param inModality + */ + private void setModality(Modality inModality) + { + modalityProperty.set(inModality); + } + /** + * + * + * @param inMaximized + */ + private void setMaximized(boolean inMaximized) + { + maximizedProperty.set(inMaximized); + } + /** + * + * + * @param inScrollLeft + */ + private void setScrollLeft(double inScrollLeft) + { + scrollLeftProperty.set(inScrollLeft); + } + /** + * + * + * @param inScrollTop + */ + private void setScrollTop(double inScrollTop) + { + scrollTopProperty.set(inScrollTop); + } + /** + * + * + * @param inX + */ + private void setX(double inX) + { + xProperty.set(inX); + } + /** + * + * + * @param inY + */ + private void setY(double inY) + { + yProperty.set(inY); + } + /** + * + * + */ + public void close() + { + throw new UnsupportedOperationException(); // TODO + } + private final DoubleProperty heightProperty = new SimpleDoubleProperty(); + private final DoubleProperty widthProperty = new SimpleDoubleProperty(); + private final DoubleProperty xProperty = new SimpleDoubleProperty(); + private final DoubleProperty yProperty = new SimpleDoubleProperty(); + private final BooleanProperty maximizedProperty = new SimpleBooleanProperty(); + private final BooleanProperty draggableProperty = new SimpleBooleanProperty(); + private final BooleanProperty resizableProperty = new SimpleBooleanProperty(); + private final DoubleProperty scrollLeftProperty = new SimpleDoubleProperty(); + private final DoubleProperty scrollTopProperty = new SimpleDoubleProperty(); + private final ObjectProperty modalityProperty = new SimpleObjectProperty<>(); + private final Properties windowProperties = new Properties(); + private final StringProperty windowTitleProperty = new SimpleStringProperty(); + private VBox windowLayout; + private HBox windowTitleLayout; + private HBox titleLayout; + private HBox closeButtonLayout; + private VBox contentLayout; + private Label windowTitle; + private Label closeLabel; + } + private WindowLayout createNewWindowLayout() + { + return new WindowLayout(); } /** * Receive logout events. @@ -232,10 +582,10 @@ public void onCloseAllWindows(CloseWindowsEvent inEvent) /** * Determine if the given window is outside the viewable desktop area or not. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a boolean value */ - private boolean isWindowOutsideDesktop(Window inWindow) + private boolean isWindowOutsideDesktop(WindowLayout inWindow) { DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); return (getWindowBottom(inWindow) > params.getBottom()) || (getWindowLeft(inWindow) < params.getLeft()) || (getWindowTop(inWindow) < params.getTop()) || (getWindowRight(inWindow) > params.getRight()); @@ -243,60 +593,60 @@ private boolean isWindowOutsideDesktop(Window inWindow) /** * Get the window top edge coordinate in pixels. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a double value */ - private double getWindowTop(Window inWindow) + private double getWindowTop(WindowLayout inWindow) { return inWindow.getY(); } /** * Get the window left edge coordinate in pixels. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a double value */ - private double getWindowLeft(Window inWindow) + private double getWindowLeft(WindowLayout inWindow) { return inWindow.getX(); } /** * Get the window bottom edge coordinate in pixels. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a double value */ - private double getWindowBottom(Window inWindow) + private double getWindowBottom(WindowLayout inWindow) { return getWindowTop(inWindow) + getWindowHeight(inWindow); } /** * Get the window right edge coordinate in pixels. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a double value */ - private double getWindowRight(Window inWindow) + private double getWindowRight(WindowLayout inWindow) { return getWindowLeft(inWindow) + getWindowWidth(inWindow); } /** * Get the window height in pixels. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a double value */ - private double getWindowHeight(Window inWindow) + private double getWindowHeight(WindowLayout inWindow) { return inWindow.getHeight(); } /** * Get the window width in pixels. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a double value */ - private double getWindowWidth(Window inWindow) + private double getWindowWidth(WindowLayout inWindow) { return inWindow.getWidth(); } @@ -417,11 +767,11 @@ public String toString() *

This constructor is invoked for a new window. * * @param inEvent a NewWindowEvent value - * @param inWindow a Stage value + * @param inWindow a WindowLayout value * @param inContentViewFactory a ContentViewFactory value */ private WindowMetaData(NewWindowEvent inEvent, - Stage inWindow, + WindowLayout inWindow, ContentViewFactory inContentViewFactory) { properties = inEvent.getProperties(); @@ -436,25 +786,21 @@ private WindowMetaData(NewWindowEvent inEvent, *

This constructor is invoked to recreate a previously-created window. * * @param inProperties a Properties value - * @param inWindow a Stage value + * @param inWindow a WindowLayout value */ private WindowMetaData(Properties inProperties, - Stage inWindow) + WindowLayout inWindow) { // TODO need to do a permissions re-check, perhaps window = inWindow; properties = inProperties; try { ContentViewFactory contentViewFactory = (ContentViewFactory)applicationContext.getBean(Class.forName(inProperties.getProperty(windowContentViewFactoryProp))); - ContentView contentView = contentViewFactory.create(window, + ContentView contentView = contentViewFactory.create(window.getMainLayout(), new RestartNewWindowEvent(contentViewFactory, properties.getProperty(windowTitleProp)), properties); - styleService.addStyle(contentView); - Scene scene = contentView.getScene(); - scene.getStylesheets().clear(); - scene.getStylesheets().add("dark-mode.css"); - window.setScene(scene); + window.setRoot(contentView.getNode()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } @@ -482,9 +828,9 @@ private Properties getProperties() /** * Get the window value. * - * @return a Stage value + * @return a WindowLayout value */ - private Stage getWindow() + private WindowLayout getWindow() { return window; } @@ -496,7 +842,7 @@ private void updateProperties() properties.setProperty(windowPosXProp, String.valueOf(window.getX())); properties.setProperty(windowPosYProp, - String.valueOf(window.getY())); + String.valueOf(window.getX())); properties.setProperty(windowHeightProp, String.valueOf(window.getHeight())); properties.setProperty(windowWidthProp, @@ -507,17 +853,14 @@ private void updateProperties() properties.setProperty(windowTitleProp, window.getTitle()); } - properties.setProperty(windowModalProp, - String.valueOf(window.getModality())); - // TODO not sure what to do about dragging yet -// properties.setProperty(windowDraggableProp, -// String.valueOf(window.isDraggable())); + properties.setProperty(windowDraggableProp, + String.valueOf(window.isDraggable())); properties.setProperty(windowResizableProp, String.valueOf(window.isResizable())); -// properties.setProperty(windowScrollLeftProp, -// String.valueOf(window.getScrollLeft())); -// properties.setProperty(windowScrollTopProp, -// String.valueOf(window.getScrollTop())); + properties.setProperty(windowScrollLeftProp, + String.valueOf(window.getScrollLeft())); + properties.setProperty(windowScrollTopProp, + String.valueOf(window.getScrollLeft())); properties.setProperty(windowFocusProp, String.valueOf(hasFocus())); Object windowId = window.getProperties().getOrDefault(windowStyleId, @@ -536,14 +879,12 @@ private void updateWindow() { window.setWidth(Double.parseDouble(properties.getProperty(windowWidthProp))); window.setHeight(Double.parseDouble(properties.getProperty(windowHeightProp))); -// window.initModality(Modality.valueOf(properties.getProperty(windowModalProp))); - window.initModality(Modality.NONE); + window.setModality(Modality.valueOf(properties.getProperty(windowModalProp))); Boolean isMaximized = Boolean.parseBoolean(properties.getProperty(windowModeProp)); window.setMaximized(isMaximized); - // TODO not sure about these yet -// window.setScrollLeft(Integer.parseInt(properties.getProperty(windowScrollLeftProp))); -// window.setScrollTop(Integer.parseInt(properties.getProperty(windowScrollTopProp))); -// window.setDraggable(Boolean.parseBoolean(properties.getProperty(windowDraggableProp))); + window.setScrollLeft(Double.parseDouble(properties.getProperty(windowScrollLeftProp))); + window.setScrollTop(Double.parseDouble(properties.getProperty(windowScrollTopProp))); + window.setDraggable(Boolean.parseBoolean(properties.getProperty(windowDraggableProp))); window.setResizable(Boolean.parseBoolean(properties.getProperty(windowResizableProp))); window.setTitle(properties.getProperty(windowTitleProp)); window.setX(getDoubleValue(properties, @@ -552,10 +893,10 @@ private void updateWindow() windowPosYProp)); window.getProperties().put(windowStyleId, properties.getProperty(windowStyleId)); -// setHasFocus(Boolean.parseBoolean(properties.getProperty(windowFocusProp))); -// if(hasFocus) { -// window.requestFocus(); -// } + setHasFocus(Boolean.parseBoolean(properties.getProperty(windowFocusProp))); + if(hasFocus) { + window.requestFocus(); + } } /** * Set the immutable properties of this window to the underlying properties storage. @@ -576,7 +917,7 @@ private void setWindowStaticProperties(ContentViewFactory inContentViewFactory, */ private void close() { - ((Stage)getWindow().getScene().getWindow()).close(); + getWindow().close(); } /** * Get the window uuid value. @@ -623,7 +964,7 @@ private void setHasFocus(boolean inHasFocus) /** * underlying UI element */ - private final Stage window; + private final WindowLayout window; } /** * Provides a registry of all windows. @@ -782,14 +1123,12 @@ private void restoreLayout(Properties inDisplayLayout) "Restoring {} {}", windowUid, windowProperties); - Stage newWindow = new Stage(); - newWindow.initOwner(App.getPrimaryStage()); + WindowLayout newWindow = createNewWindowLayout(); WindowMetaData newWindowMetaData = new WindowMetaData(windowProperties, newWindow); addWindow(newWindowMetaData); addWindowListeners(newWindowMetaData); - styleService.addStyle(newWindowMetaData.getWindow().getScene()); - newWindowMetaData.getWindow().show(); + PhotonApp.getWorkspace().getChildren().add(newWindowMetaData.getWindow().getMainLayout()); } } } @@ -819,105 +1158,105 @@ private void updateDisplayLayout() private void addWindowListeners(WindowMetaData inWindowWrapper) { WindowRegistry windowRegistry = this; - Stage newWindow = inWindowWrapper.getWindow(); - newWindow.addEventHandler(MouseEvent.MOUSE_CLICKED, - new EventHandler() { - @Override - public void handle(MouseEvent inEvent) - { - SLF4JLoggerProxy.trace(WindowManagerService.this, - "Click: {}", - inEvent); - verifyWindowLocation(newWindow); - inWindowWrapper.updateProperties(); - updateDisplayLayout(); - }} - ); - newWindow.setOnShown(new EventHandler() { - @Override - public void handle(WindowEvent inEvent) - { - SLF4JLoggerProxy.trace(WindowManagerService.this, - "Shown: {}", - inEvent); - verifyWindowLocation(newWindow); - inWindowWrapper.updateProperties(); - updateDisplayLayout(); - }} - ); -// newWindow.addWindowModeChangeListener(inEvent -> { -// SLF4JLoggerProxy.trace(WindowManagerService.this, -// "Mode change: {}", -// inEvent); -// // TODO might want to do this, might not. a maximized window currently tromps all over the menu bar + WindowLayout newWindow = inWindowWrapper.getWindow(); +// newWindow.addEventHandler(MouseEvent.MOUSE_CLICKED, +// new EventHandler() { +// @Override +// public void handle(MouseEvent inEvent) +// { +// SLF4JLoggerProxy.trace(WindowManagerService.this, +// "Click: {}", +// inEvent); +// verifyWindowLocation(newWindow); +// inWindowWrapper.updateProperties(); +// updateDisplayLayout(); +// }} +// ); +// newWindow.setOnShown(new EventHandler() { +// @Override +// public void handle(WindowEvent inEvent) +// { +// SLF4JLoggerProxy.trace(WindowManagerService.this, +// "Shown: {}", +// inEvent); +// verifyWindowLocation(newWindow); +// inWindowWrapper.updateProperties(); +// updateDisplayLayout(); +// }} +// ); +//// newWindow.addWindowModeChangeListener(inEvent -> { +//// SLF4JLoggerProxy.trace(WindowManagerService.this, +//// "Mode change: {}", +//// inEvent); +//// // TODO might want to do this, might not. a maximized window currently tromps all over the menu bar +////// verifyWindowLocation(newWindow); +//// inWindowWrapper.updateProperties(); +//// updateDisplayLayout(); +//// }); +// newWindow.widthProperty().addListener(new ChangeListener() { +// @Override +// public void changed(ObservableValue inObservable, +// Number inOldValue, +// Number inNewValue) +// { +// newWindowResize("width", +// inWindowWrapper); +// }} +// ); +// newWindow.heightProperty().addListener(new ChangeListener() { +// @Override +// public void changed(ObservableValue inObservable, +// Number inOldValue, +// Number inNewValue) +// { +// newWindowResize("height", +// inWindowWrapper); +// }} +// ); +// newWindow.addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST,new EventHandler() { +// @Override +// public void handle(WindowEvent inEvent) +// { +// SLF4JLoggerProxy.trace(WindowManagerService.this, +// "Close: {}", +// inEvent); +// // this listener will be fired during log out, but, we don't want to update the display layout in that case +// if(!windowRegistry.isLoggingOut()) { +// windowRegistry.removeWindow(inWindowWrapper); +// updateDisplayLayout(); +// } +// }} +// ); +//// newWindow.addBlurListener(inEvent -> { +//// SLF4JLoggerProxy.trace(WindowManagerService.this, +//// "Blur: {}", +//// inEvent); //// verifyWindowLocation(newWindow); -// inWindowWrapper.updateProperties(); -// updateDisplayLayout(); -// }); - newWindow.widthProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue inObservable, - Number inOldValue, - Number inNewValue) - { - newWindowResize("width", - inWindowWrapper); - }} - ); - newWindow.heightProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue inObservable, - Number inOldValue, - Number inNewValue) - { - newWindowResize("height", - inWindowWrapper); - }} - ); - newWindow.addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST,new EventHandler() { - @Override - public void handle(WindowEvent inEvent) - { - SLF4JLoggerProxy.trace(WindowManagerService.this, - "Close: {}", - inEvent); - // this listener will be fired during log out, but, we don't want to update the display layout in that case - if(!windowRegistry.isLoggingOut()) { - windowRegistry.removeWindow(inWindowWrapper); - updateDisplayLayout(); - } - }} - ); -// newWindow.addBlurListener(inEvent -> { -// SLF4JLoggerProxy.trace(WindowManagerService.this, -// "Blur: {}", -// inEvent); -// verifyWindowLocation(newWindow); -// inWindowWrapper.setHasFocus(false); -// inWindowWrapper.updateProperties(); -// updateDisplayLayout(); -// }); -// newWindow.addFocusListener(inEvent -> { -// SLF4JLoggerProxy.trace(WindowManagerService.this, -// "Focus: {}", -// inEvent); -// verifyWindowLocation(newWindow); -// inWindowWrapper.setHasFocus(true); -// inWindowWrapper.updateProperties(); -// updateDisplayLayout(); -// }); - newWindow.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED,new EventHandler() { - @Override - public void handle(ContextMenuEvent inEvent) - { - SLF4JLoggerProxy.trace(WindowManagerService.this, - "Context click: {}", - inEvent); - verifyWindowLocation(newWindow); - inWindowWrapper.updateProperties(); - updateDisplayLayout(); - }} - ); +//// inWindowWrapper.setHasFocus(false); +//// inWindowWrapper.updateProperties(); +//// updateDisplayLayout(); +//// }); +//// newWindow.addFocusListener(inEvent -> { +//// SLF4JLoggerProxy.trace(WindowManagerService.this, +//// "Focus: {}", +//// inEvent); +//// verifyWindowLocation(newWindow); +//// inWindowWrapper.setHasFocus(true); +//// inWindowWrapper.updateProperties(); +//// updateDisplayLayout(); +//// }); +// newWindow.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED,new EventHandler() { +// @Override +// public void handle(ContextMenuEvent inEvent) +// { +// SLF4JLoggerProxy.trace(WindowManagerService.this, +// "Context click: {}", +// inEvent); +// verifyWindowLocation(newWindow); +// inWindowWrapper.updateProperties(); +// updateDisplayLayout(); +// }} +// ); } private void newWindowResize(String inDimension, WindowMetaData inWindowWrapper) @@ -932,9 +1271,9 @@ private void newWindowResize(String inDimension, /** * Verify that the given window is within the acceptable bounds of the desktop viewable area. * - * @param inWindow a Stage value + * @param inWindow a WindowLayout value */ - private void verifyWindowLocation(Stage inWindow) + private void verifyWindowLocation(WindowLayout inWindow) { synchronized(activeWindows) { if(isWindowOutsideDesktop(inWindow)) { @@ -954,9 +1293,9 @@ private void verifyWindowLocation(Stage inWindow) * *

If the window is already within the acceptable bounds of the desktop viewable area, it will not be repositioned. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value */ - private void returnWindowToDesktop(Window inWindow) + private void returnWindowToDesktop(WindowLayout inWindow) { int pad = desktopViewableAreaPad; DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); @@ -1092,10 +1431,7 @@ public void run() SLF4JLoggerProxy.warn(WindowManagerService.this, ExceptionUtils.getRootCauseMessage(e)); } - }}, - desktopWindowPositionMonitorInterval, - desktopWindowPositionMonitorInterval, - TimeUnit.MILLISECONDS); + }},desktopWindowPositionMonitorInterval,desktopWindowPositionMonitorInterval,TimeUnit.MILLISECONDS); } } /** @@ -1206,11 +1542,6 @@ private Properties getDisplayLayout() * window style id key name */ private static final String windowStyleId = propId + "_windowStyleId"; - /** - * provides access to style services - */ - @Autowired - private StyleService styleService; /** * web message service value */ diff --git a/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyView.java b/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyView.java index f760377c67..566a2435e5 100644 --- a/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyView.java +++ b/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyView.java @@ -38,6 +38,7 @@ import org.marketcetera.strategy.events.StrategyUnloadedEvent; import org.marketcetera.strategy.events.StrategyUploadFailedEvent; import org.marketcetera.strategy.events.StrategyUploadSucceededEvent; +import org.marketcetera.ui.PhotonApp; import org.marketcetera.ui.PhotonServices; import org.marketcetera.ui.events.NewWindowEvent; import org.marketcetera.ui.events.NotificationEvent; @@ -60,7 +61,7 @@ import javafx.geometry.Insets; import javafx.geometry.Orientation; import javafx.scene.Cursor; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.ButtonBar; @@ -87,7 +88,6 @@ import javafx.stage.FileChooser; import javafx.stage.FileChooser.ExtensionFilter; import javafx.stage.Modality; -import javafx.stage.Stage; import javafx.stage.WindowEvent; /* $License$ */ @@ -161,7 +161,6 @@ public void changed(ObservableValue inObservable, eventTablePagination, new Separator(Orientation.HORIZONTAL), buttonLayout); - mainScene = new Scene(mainLayout); updateStrategies(); updateEvents(); strategyClient.addStrategyEventListener(this); @@ -235,12 +234,12 @@ public void run() } } /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() + * @see org.marketcetera.ui.view.ContentView#getNode() */ @Override - public Scene getScene() + public Node getNode() { - return mainScene; + return mainLayout; } /* (non-Javadoc) * @see org.marketcetera.ui.view.ContentView#getViewName() @@ -253,11 +252,11 @@ public String getViewName() /** * Create a new StrategyView instance. * - * @param inParent a Window value + * @param inParent a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inProperties a Properties value */ - public StrategyView(Stage inParent, + public StrategyView(Node inParent, NewWindowEvent inEvent, Properties inProperties) { @@ -310,7 +309,7 @@ private void loadStrategy() strategyFileChooser.setTitle("Choose the Strategy JAR File"); strategyFileChooser.getExtensionFilters().add(new ExtensionFilter("JAR Files", "*.jar")); - File result = strategyFileChooser.showOpenDialog(getParentWindow()); + File result = strategyFileChooser.showOpenDialog(PhotonApp.getPrimaryStage()); if(result != null) { if(!(result.exists() && result.canRead())) { webMessageService.post(new NotificationEvent("Load Strategy", @@ -368,7 +367,7 @@ private void loadStrategy() nameConfirmationDialogPane.getButtonTypes().setAll(okButtonType, cancelButton); nameConfirmationDialog.getDialogPane().lookupButton(okButtonType).disableProperty().bind(disableOkButton); - PhotonServices.style(nameConfirmationDialogPane.getScene()); + PhotonServices.styleDialog(nameConfirmationDialog); nameConfirmationDialog.initModality(Modality.APPLICATION_MODAL); nameConfirmationDialog.setResultConverter(dialogButton -> { if(dialogButton == okButtonType) { @@ -389,7 +388,7 @@ private void loadStrategy() owner.getName()); strategyTable.getItems().add(newItem); try { - getScene().setCursor(Cursor.WAIT); + getNode().setCursor(Cursor.WAIT); // TODO transfer file - this will block? need to use a callback instead? SimpleFileUploadRequest uploadRequest = new SimpleFileUploadRequest(name, nonce, @@ -455,7 +454,7 @@ public void onError(Throwable inThrowable) "File '" + result.getAbsolutePath() + "' could not be read", AlertType.WARNING)); } finally { - getScene().setCursor(Cursor.DEFAULT); + getNode().setCursor(Cursor.DEFAULT); } } } @@ -774,10 +773,6 @@ private void startStrategy(DisplayStrategyInstance inSelectedStrategy) private TableView strategyTable; private TableView eventTable; private StrategyClientService strategyClient; - /** - * main scene object - */ - private Scene mainScene; /** * global name of the strategy */ diff --git a/photon/src/main/java/org/marketcetera/ui/trade/fixmessagedetails/view/FixMessageDetailsView.java b/photon/src/main/java/org/marketcetera/ui/trade/fixmessagedetails/view/FixMessageDetailsView.java index 240b7f2df0..8a1a9e32d2 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/fixmessagedetails/view/FixMessageDetailsView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/fixmessagedetails/view/FixMessageDetailsView.java @@ -18,14 +18,13 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.VBox; -import javafx.stage.Stage; import quickfix.InvalidMessage; /* $License$ */ @@ -52,7 +51,6 @@ public void start() mainLayout = new VBox(); initializeTable(); mainLayout.getChildren().add(fixMessageGrid); - mainScene = new Scene(mainLayout); updateRows(fixMessage); } private void updateRows(quickfix.Message fixMessage) @@ -125,21 +123,21 @@ public String getViewName() return NAME; } /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() + * @see org.marketcetera.ui.view.ContentView#getNode() */ @Override - public Scene getScene() + public Node getNode() { - return mainScene; + return mainLayout; } /** * Create a new FixMessageDetailsView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - public FixMessageDetailsView(Stage inParent, + public FixMessageDetailsView(Node inParent, NewWindowEvent inEvent, Properties inViewProperties) { @@ -225,7 +223,6 @@ public String getValue() private final String type; private final String value; } - private Scene mainScene; private VBox mainLayout; private TableView fixMessageGrid; /** diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractDeletableFixMessageView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractDeletableFixMessageView.java index 96f7361b42..c7e1c31217 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractDeletableFixMessageView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractDeletableFixMessageView.java @@ -8,6 +8,7 @@ import org.marketcetera.ui.events.NotificationEvent; import org.marketcetera.util.log.SLF4JLoggerProxy; +import javafx.scene.Node; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ButtonBar; @@ -17,7 +18,6 @@ import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.TableView; -import javafx.stage.Stage; /* $License$ */ @@ -34,11 +34,11 @@ public abstract class AbstractDeletableFixMessageViewStage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - protected AbstractDeletableFixMessageView(Stage inParentWindow, + protected AbstractDeletableFixMessageView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractFixMessageView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractFixMessageView.java index 19f0707161..6755666e05 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractFixMessageView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractFixMessageView.java @@ -41,7 +41,6 @@ import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.scene.Node; -import javafx.scene.Scene; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; @@ -57,7 +56,6 @@ import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; import javafx.scene.layout.VBox; -import javafx.stage.Stage; import javafx.stage.WindowEvent; /* $License$ */ @@ -92,7 +90,6 @@ public void start() selectionModel.setSelectionMode(SelectionMode.SINGLE); initializeColumns(reportsTableView); initializeContextMenu(reportsTableView); - mainScene = new Scene(mainLayout); pagination = new Pagination(); pagination.setPageCount(10); pagination.setCurrentPageIndex(1); @@ -113,6 +110,14 @@ public void changed(ObservableValue inObservable, pageSize = 10; updateReports(); } + /* (non-Javadoc) + * @see org.marketcetera.ui.view.ContentView#getNode() + */ + @Override + public Node getNode() + { + return mainLayout; + } /* (non-Javadoc) * @see org.marketcetera.trade.TradeMessageListener#receiveTradeMessage(org.marketcetera.trade.TradeMessage) */ @@ -124,14 +129,6 @@ public void receiveTradeMessage(TradeMessage inTradeMessage) inTradeMessage); updateReports(); } - /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() - */ - @Override - public Scene getScene() - { - return mainScene; - } /* (non-Javadoc) * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) */ @@ -489,11 +486,11 @@ protected Node getPlaceholder() /** * Create a new AbstractFixMessageView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - protected AbstractFixMessageView(Stage inParentWindow, + protected AbstractFixMessageView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { @@ -502,7 +499,6 @@ protected AbstractFixMessageView(Stage inParentWindow, inViewProperties); } protected static final DateTimeFormatter isoDateFormatter = TimeFactoryImpl.FULL_MILLISECONDS; - protected Scene mainScene; protected TradeClientService tradeClientService; protected int currentPage; protected int pageSize; diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/averageprice/AveragePriceView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/averageprice/AveragePriceView.java index 6133ca33ac..194fd7e74b 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/averageprice/AveragePriceView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/averageprice/AveragePriceView.java @@ -11,7 +11,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; -import javafx.stage.Stage; +import javafx.scene.Node; /* $License$ */ @@ -30,11 +30,11 @@ public class AveragePriceView /** * Create a new AveragePriceView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - public AveragePriceView(Stage inParentWindow, + public AveragePriceView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/fills/FillsView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/fills/FillsView.java index e84abf9951..37d819640c 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/fills/FillsView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/fills/FillsView.java @@ -11,7 +11,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; -import javafx.stage.Stage; +import javafx.scene.Node; /* $License$ */ @@ -30,11 +30,11 @@ public class FillsView /** * Create a new FillsView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - public FillsView(Stage inParentWindow, + public FillsView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/openorders/OpenOrderView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/openorders/OpenOrderView.java index cd0d9d08a1..811532f02e 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/openorders/OpenOrderView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/openorders/OpenOrderView.java @@ -18,7 +18,6 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; -import javafx.stage.Stage; /* $License$ */ @@ -47,11 +46,11 @@ public String getViewName() /** * Create a new OpenOrderView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - public OpenOrderView(Stage inParentWindow, + public OpenOrderView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/orderticket/OrderTicketView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/orderticket/OrderTicketView.java index 0870cbc62c..5237431c86 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/orderticket/OrderTicketView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/orderticket/OrderTicketView.java @@ -63,7 +63,7 @@ import javafx.beans.value.ObservableValue; import javafx.event.EventHandler; import javafx.geometry.Orientation; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.scene.control.Accordion; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; @@ -88,7 +88,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; -import javafx.stage.Stage; import javafx.stage.WindowEvent; /* $License$ */ @@ -106,13 +105,14 @@ public class OrderTicketView extends AbstractContentView implements ContentView,BrokerStatusListener { + /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#getScene() + * @see org.marketcetera.ui.view.ContentView#getNode() */ @Override - public Scene getScene() + public Node getNode() { - return scene; + return rootLayout; } /* (non-Javadoc) * @see org.marketcetera.brokers.BrokerStatusListener#receiveBrokerStatus(org.marketcetera.fix.ActiveFixSession) @@ -190,7 +190,6 @@ public void start() hashCode()); rootLayout = new VBox(); orderTicketLayout = new GridPane(); - scene = new Scene(rootLayout); // create controls and layouts brokerLabel = new Label("Broker"); brokerComboBox = new ComboBox<>(); @@ -614,7 +613,7 @@ public void handle(MouseEvent inEvent) KeyCombination sendKeyCombination = new KeyCodeCombination(KeyCode.ENTER); Mnemonic sendMnemonic = new Mnemonic(sendButton, sendKeyCombination); - scene.addMnemonic(sendMnemonic); + // TODO add mnemonic? sendClearLayout.getChildren().addAll(sendButton, clearButton); sendButton.setOnMouseClicked(inEvent -> { @@ -706,7 +705,8 @@ public void handle(MouseEvent inEvent) // Type.TRAY_NOTIFICATION); if(replaceExecutionReportOption.isPresent()) { // close containing ticket - getParentWindow().close(); + // TODO need to trigger a close action + getParentWindow().setVisible(false); } else { // partially clear ticket resetTicket(false); @@ -739,11 +739,11 @@ public void handle(MouseEvent inEvent) /** * Create a new OrderTicketView instance. * - * @param inParent a Window value + * @param inParent a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inProperties a Properties value */ - public OrderTicketView(Stage inParent, + public OrderTicketView(Node inParent, NewWindowEvent inEvent, Properties inProperties) { @@ -931,10 +931,6 @@ public StringProperty valueProperty() * root container for the scene */ private GridPane orderTicketLayout; - /** - * main scene object - */ - private Scene scene; /** * provides access to style services */ diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/reports/ReportsView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/reports/ReportsView.java index 70f36997af..39d93f1294 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/reports/ReportsView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/reports/ReportsView.java @@ -19,6 +19,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import javafx.scene.Node; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ButtonBar; @@ -29,7 +30,6 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; -import javafx.stage.Stage; /* $License$ */ @@ -49,11 +49,11 @@ public class ReportsView /** * Create a new ReportsView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - public ReportsView(Stage inParentWindow, + public ReportsView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { diff --git a/photon/src/main/java/org/marketcetera/ui/view/AbstractContentView.java b/photon/src/main/java/org/marketcetera/ui/view/AbstractContentView.java index cc55e8e8ae..0625447f7f 100644 --- a/photon/src/main/java/org/marketcetera/ui/view/AbstractContentView.java +++ b/photon/src/main/java/org/marketcetera/ui/view/AbstractContentView.java @@ -11,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import javafx.stage.Stage; +import javafx.scene.Node; /* $License$ */ @@ -37,9 +37,9 @@ protected Properties getViewProperties() /** * Get the parentWindow value. * - * @return a Stage value + * @return a Node value */ - protected Stage getParentWindow() + protected Node getParentWindow() { return parentWindow; } @@ -55,11 +55,11 @@ protected NewWindowEvent getNewWindowEvent() /** * Create a new AbstractContentView instance. * - * @param inParentWindow a Stage value + * @param inParentWindow a Node value * @param inNewWindowEvent a NewWindowEvent value * @param inViewProperties a Properties value */ - protected AbstractContentView(Stage inParentWindow, + protected AbstractContentView(Node inParentWindow, NewWindowEvent inEvent, Properties inViewProperties) { @@ -104,7 +104,7 @@ protected AbstractContentView(Stage inParentWindow, /** * parent window that owns the view */ - private final Stage parentWindow; + private final Node parentWindow; /** * properties used to seed the view */ diff --git a/photon/src/main/java/org/marketcetera/ui/view/AbstractContentViewFactory.java b/photon/src/main/java/org/marketcetera/ui/view/AbstractContentViewFactory.java index f8c1f160fc..f4cf999ace 100644 --- a/photon/src/main/java/org/marketcetera/ui/view/AbstractContentViewFactory.java +++ b/photon/src/main/java/org/marketcetera/ui/view/AbstractContentViewFactory.java @@ -7,7 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import javafx.stage.Window; +import javafx.scene.Node; /* $License$ */ @@ -25,7 +25,7 @@ public abstract class AbstractContentViewFactory * @see org.marketcetera.web.view.ContentViewFactory#create(com.vaadin.ui.Window, org.marketcetera.web.events.NewWindowEvent, java.util.Properties) */ @Override - public ContentView create(Window inParent, + public ContentView create(Node inParent, NewWindowEvent inEvent, Properties inViewProperties) { diff --git a/photon/src/main/java/org/marketcetera/ui/view/ContentView.java b/photon/src/main/java/org/marketcetera/ui/view/ContentView.java index 4a47d9445d..b67e24d47e 100644 --- a/photon/src/main/java/org/marketcetera/ui/view/ContentView.java +++ b/photon/src/main/java/org/marketcetera/ui/view/ContentView.java @@ -1,6 +1,6 @@ package org.marketcetera.ui.view; -import javafx.scene.Scene; +import javafx.scene.Node; import javafx.stage.WindowEvent; /* $License$ */ @@ -15,11 +15,11 @@ public interface ContentView { /** - * Get the scene which contains the content. + * Contains the root content of the view. * - * @return a Scene value + * @return a Node value */ - Scene getScene(); + Node getNode(); /** * Get the Vaadin name of the view. * diff --git a/photon/src/main/java/org/marketcetera/ui/view/ContentViewFactory.java b/photon/src/main/java/org/marketcetera/ui/view/ContentViewFactory.java index b69b04dbbc..3dd34d283f 100644 --- a/photon/src/main/java/org/marketcetera/ui/view/ContentViewFactory.java +++ b/photon/src/main/java/org/marketcetera/ui/view/ContentViewFactory.java @@ -4,7 +4,7 @@ import org.marketcetera.ui.events.NewWindowEvent; -import javafx.stage.Window; +import javafx.scene.Node; /* $License$ */ @@ -20,12 +20,12 @@ public interface ContentViewFactory /** * Create a new content view. * - * @param inParent a Window value + * @param inParent a Node value * @param inEvent a NewWindowEvent value * @param inViewProperties a Properties value * @return a T value */ - ContentView create(Window inParent, + ContentView create(Node inParent, NewWindowEvent inEvent, Properties inViewProperties); } diff --git a/photon/src/main/resources/dark-mode.css b/photon/src/main/resources/dark-mode.css index 58978555f5..4d5fc720ea 100644 --- a/photon/src/main/resources/dark-mode.css +++ b/photon/src/main/resources/dark-mode.css @@ -7,6 +7,23 @@ -fx-font-size: 12px; } +.view { + -fx-background-color: derive(-fx-base,45%); + background-color: derive(-fx-base,45%); + -fx-padding: 5 5 5 5; + padding: 5 5 5 5; + -fx-border-style: solid; + border-style: solid; + -fx-border-width: 1px; + border-width: 1px; + -fx-background-radius: 5px; + -fx-border-radius: 5px; + border-radius: 5px; + -fx-border-color: black; + border-color: black; +/* this is cool but seems to prevent resizing -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.8), 10, 0, 0, 0); */ +} + .label{ -fx-text-fill: lightgray; } @@ -87,3 +104,13 @@ -fx-text-fill: #000; -fx-alignment: top-left; } + +.title-bar { + -fx-padding: 10px; + -fx-background-color: #676666; + } + +.title-bar Label { + -fx-text-fill: white; +} + diff --git a/photon/todo.txt b/photon/todo.txt index 3e49e03ef2..cb65abe379 100644 --- a/photon/todo.txt +++ b/photon/todo.txt @@ -66,12 +66,10 @@ ***************** * strategy view * ***************** -- don't need runtime update - can calculate locally until the status changes - reverify strategy before starting - how to identify the strategy instance for events emitted through the strategy client? maybe create a special kind of client that knows the strategy instance? otherwise, we run the risk of a strategy impersonating another strategy. - cancel big uploads - run on different cluster members? report strategy status on all cluster members -- special category of events? - compare meta data on activate or discard? - run multiple versions of an uploaded stratergy w/o having to upload it again (duplicate from strategy context menu?) - nonce should not be in the strategy instance - pass it as a parameter to the new strategy instance and it can be stored adjacently @@ -82,13 +80,15 @@ - move verification from StrategyRPCServer to StrategyServiceImpl - add attribute to strategy instance: -- auto start -- strategy events should be in db to allow pagination - could be lots and lots -- strategy persistence? that is, can we reload strategies at start? we had something like this before with executing run files at SE start - merge 1102 to 4.1.x - update build instructions - make 4.1.x the main branch +x strategy events should be in db to allow pagination - could be lots and lots +x strategy persistence? that is, can we reload strategies at start? we had something like this before with executing run files at SE start +x special category of events? +x don't need runtime update - can calculate locally until the status changes x add strategy view x strategy running update events x implement stop strategy From 999abc22f9fcd6b3da812d0f07c451434718bffc Mon Sep 17 00:00:00 2001 From: Colin DuPlantis Date: Sat, 18 Mar 2023 11:03:21 -0700 Subject: [PATCH 2/4] MATP-1102 Update new windows manager --- .../src/test/cmd_exec/conf/log4j2.xml | 1 - .../ui/fix/view/FixSessionView.java | 5 +- .../marketdata/view/MarketDataDetailView.java | 5 +- .../marketdata/view/MarketDataListView.java | 4 +- .../ui/service/WindowManagerService.java | 121 +++++++++--------- .../ui/strategy/view/StrategyView.java | 5 +- .../ui/trade/view/AbstractFixMessageView.java | 5 +- .../view/orderticket/OrderTicketView.java | 5 +- .../org/marketcetera/ui/view/ContentView.java | 5 +- photon/src/main/resources/log4j2.xml | 1 - 10 files changed, 71 insertions(+), 86 deletions(-) diff --git a/packages/dare-package/src/test/cmd_exec/conf/log4j2.xml b/packages/dare-package/src/test/cmd_exec/conf/log4j2.xml index 990f181612..bad4a77513 100644 --- a/packages/dare-package/src/test/cmd_exec/conf/log4j2.xml +++ b/packages/dare-package/src/test/cmd_exec/conf/log4j2.xml @@ -59,7 +59,6 @@ - diff --git a/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java b/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java index 11f1eb51ce..d639209e13 100644 --- a/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java +++ b/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java @@ -85,7 +85,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; -import javafx.stage.WindowEvent; /* $License$ */ @@ -123,10 +122,10 @@ public void receiveBrokerStatus(ActiveFixSession inActiveFixSession) updateSessions(); } /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { try { fixAdminClient.removeBrokerStatusListener(this); diff --git a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailView.java b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailView.java index 94c01a37fd..acb1ac3ff3 100644 --- a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailView.java +++ b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailView.java @@ -62,7 +62,6 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.RowConstraints; import javafx.scene.layout.VBox; -import javafx.stage.WindowEvent; /* $License$ */ @@ -88,10 +87,10 @@ public Node getNode() return rootLayout; } /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { SLF4JLoggerProxy.trace(this, "{} {} stop", diff --git a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java index ac1d1e84a8..4746f6ebab 100644 --- a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java +++ b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java @@ -85,10 +85,10 @@ public Node getNode() return rootLayout; } /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { SLF4JLoggerProxy.trace(this, "{} {} stop", diff --git a/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java b/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java index 93d7cd3a30..88042012f3 100644 --- a/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java +++ b/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java @@ -1,6 +1,7 @@ package org.marketcetera.ui.service; import java.net.URL; +import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Properties; @@ -16,11 +17,11 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.assertj.core.util.Lists; import org.marketcetera.core.PlatformServices; import org.marketcetera.core.Util; import org.marketcetera.ui.DragResizeMod; import org.marketcetera.ui.DragResizeMod.OnDragResizeEventListener; -import org.marketcetera.ui.Draggable; import org.marketcetera.ui.PhotonApp; import org.marketcetera.ui.events.CascadeWindowsEvent; import org.marketcetera.ui.events.CloseWindowsEvent; @@ -55,6 +56,7 @@ import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.stage.Modality; import javafx.stage.Stage; @@ -132,7 +134,6 @@ public void onNewWindow(NewWindowEvent inEvent) inEvent.getWindowTitle()); // create the UI window element final WindowLayout newWindow = createNewWindowLayout(); -// newWindow.initOwner(PhotonApp.getPrimaryStage()); if(inEvent.getWindowIcon() != null) { // TODO need to convert to Image to show here // newWindow.getIcons().add(PhotonServices.getSvgResource(inEvent.getWindowIcon())); @@ -148,6 +149,7 @@ public void onNewWindow(NewWindowEvent inEvent) ContentView contentView = viewFactory.create(newWindow.getMainLayout(), inEvent, newWindowWrapper.getProperties()); + newWindow.setContentView(contentView); newWindow.setTitle(inEvent.getWindowTitle()); // set properties of the new window based on the received event newWindow.setDraggable(inEvent.isDraggable()); @@ -166,11 +168,12 @@ public void onNewWindow(NewWindowEvent inEvent) // TODO pretty sure this isn't right newWindow.getProperties().put(WindowManagerService.windowUuidProp, inEvent.getWindowStyleId()); - PhotonApp.getWorkspace().getChildren().add(newWindow.getMainLayout()); - newWindow.requestFocus(); + newWindow.show(); } - private class WindowLayout + private static class WindowLayout { + private final ObjectProperty contentViewProperty = new SimpleObjectProperty<>(); + private final static Collection windowLayouts = Lists.newArrayList(); private WindowLayout() { windowLayout = new VBox(); @@ -185,11 +188,10 @@ private WindowLayout() windowTitle = new Label(); windowTitle.textProperty().bind(windowTitleProperty); closeLabel = new Label("X"); - // TODO trigger this when the X is pushed -// newWindow.setOnCloseRequest(inCloseEvent -> { -// contentView.onClose(inCloseEvent); -// }); - + closeLabel.setOnMouseClicked(event -> { + contentViewProperty.get().onClose(); + close(); + }); titleLayout.getChildren().addAll(windowTitle); closeButtonLayout.getChildren().addAll(closeLabel); windowTitleLayout.getStyleClass().add("title-bar"); @@ -206,7 +208,6 @@ private WindowLayout() contentLayout.setAlignment(Pos.CENTER); VBox.setVgrow(contentLayout, Priority.ALWAYS); - Draggable.Nature nature = new Draggable.Nature(windowLayout); DragResizeMod.makeResizable(windowLayout, new OnDragResizeEventListener() { @Override @@ -216,11 +217,10 @@ public void onDrag(Node inNode, double inH, double inW) { - System.out.println("COCO: drag " + inNode + " x=" + inX + " y=" + inY + " height=" + inH + " width=" + inW); xProperty.set(inX); yProperty.set(inY); - heightProperty.set(inH); - widthProperty.set(inW); + getMainLayout().translateXProperty().set(inX); + getMainLayout().translateYProperty().set(inY); } @Override public void onResize(Node inNode, @@ -229,9 +229,6 @@ public void onResize(Node inNode, double inH, double inW) { - System.out.println("COCO: resize " + inNode + " x=" + inX + " y=" + inY + " height=" + inH + " width=" + inW); - xProperty.set(inX); - yProperty.set(inY); heightProperty.set(inH); widthProperty.set(inW); } @@ -241,30 +238,24 @@ public void onResize(Node inNode, windowLayout.getStylesheets().add("dark-mode.css"); windowLayout.minWidthProperty().bindBidirectional(widthProperty); windowLayout.minHeightProperty().bindBidirectional(heightProperty); -// windowLayout.setAlignment(Pos.CENTER); -// windowLayout.setOnMouseClicked(event -> { -//// windowLayout.toFront(); -// // TODO this warps the window to the upper left -// }); -// windowLayout.addEventHandler(MouseEvent.ANY, this); - -// windowLayout.heightProperty().addListener((observableValue,oldValue,newValue)->{ -// System.out.println("COCO: " + windowTitleProperty.get() + " height: " + newValue); -// heightProperty.set((double)newValue); -// }); -// windowLayout.widthProperty().addListener((observableValue,oldValue,newValue)->{ -// System.out.println("COCO: " + windowTitleProperty.get() + " width: " + newValue); -// widthProperty.set((double)newValue); -// }); -// windowLayout.layoutXProperty().addListener((observableValue,oldValue,newValue)->{ -// System.out.println("COCO: " + windowTitleProperty.get() + " layoutX: " + newValue); -// xProperty.set((double)newValue); -// }); -// windowLayout.layoutYProperty().addListener((observableValue,oldValue,newValue)->{ -// System.out.println("COCO: " + windowTitleProperty.get() + " layoutY: " + newValue); -// yProperty.set((double)newValue); -// }); -// windowLayout.relocate(200,200); + synchronized(windowLayouts) { + windowLayouts.add(this); + } + windowLayout.setOnMouseClicked(event -> { + synchronized(windowLayouts) { + for(WindowLayout windowLayout : windowLayouts) { + windowLayout.getMainLayout().viewOrderProperty().set(1.0); + } + } + windowLayout.viewOrderProperty().set(-1.0); + }); +// DropShadow dropShadow = new DropShadow(BlurType.THREE_PASS_BOX,new Color(0,0,0,0.8),10,0,0,0); +// windowLayout.setEffect(dropShadow); +// windowLayout.setPickOnBounds(false); + } + private void setContentView(ContentView inContentView) + { + contentViewProperty.set(inContentView); } /** * @@ -494,9 +485,23 @@ private void setY(double inY) * * */ - public void close() + private void close() { - throw new UnsupportedOperationException(); // TODO +// if(!windowRegistry.isLoggingOut()) { +// windowRegistry.removeWindow(inWindowWrapper); +// updateDisplayLayout(); +// } + PhotonApp.getWorkspace().getChildren().remove(getMainLayout()); + } + private void show() + { + getMainLayout().translateXProperty().set(200); + getMainLayout().translateYProperty().set(200); + windowLayout.setMinHeight(Region.USE_COMPUTED_SIZE); + windowLayout.setMinWidth(Region.USE_COMPUTED_SIZE); + windowLayout.setViewOrder(-1); + PhotonApp.getWorkspace().getChildren().add(getMainLayout()); + requestFocus(); } private final DoubleProperty heightProperty = new SimpleDoubleProperty(); private final DoubleProperty widthProperty = new SimpleDoubleProperty(); @@ -800,6 +805,7 @@ private WindowMetaData(Properties inProperties, new RestartNewWindowEvent(contentViewFactory, properties.getProperty(windowTitleProp)), properties); + inWindow.contentViewProperty.set(contentView); window.setRoot(contentView.getNode()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); @@ -863,14 +869,6 @@ private void updateProperties() String.valueOf(window.getScrollLeft())); properties.setProperty(windowFocusProp, String.valueOf(hasFocus())); - Object windowId = window.getProperties().getOrDefault(windowStyleId, - null); - if(windowId == null) { - properties.remove(windowStyleId); - } else { - properties.setProperty(windowStyleId, - String.valueOf(windowId)); - } } /** * Update the window object with the stored telemetry. @@ -879,7 +877,7 @@ private void updateWindow() { window.setWidth(Double.parseDouble(properties.getProperty(windowWidthProp))); window.setHeight(Double.parseDouble(properties.getProperty(windowHeightProp))); - window.setModality(Modality.valueOf(properties.getProperty(windowModalProp))); + window.setModality(properties.getProperty(windowModalProp) == null ? Modality.NONE:Modality.valueOf(properties.getProperty(windowModalProp))); Boolean isMaximized = Boolean.parseBoolean(properties.getProperty(windowModeProp)); window.setMaximized(isMaximized); window.setScrollLeft(Double.parseDouble(properties.getProperty(windowScrollLeftProp))); @@ -891,8 +889,6 @@ private void updateWindow() windowPosXProp)); window.setY(getDoubleValue(properties, windowPosYProp)); - window.getProperties().put(windowStyleId, - properties.getProperty(windowStyleId)); setHasFocus(Boolean.parseBoolean(properties.getProperty(windowFocusProp))); if(hasFocus) { window.requestFocus(); @@ -1013,13 +1009,14 @@ private void cascadeWindows() } try { synchronized(activeWindows) { - int xPos = desktopCascadeWindowOffset; - int yPos = desktopCascadeWindowOffset; + double xPos = desktopCascadeWindowOffset; + double yPos = desktopCascadeWindowOffset; DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); double maxX = params.getRight(); double maxY = params.getBottom(); for(WindowMetaData activeWindow : activeWindows) { - double windowWidth = getWindowWidth(activeWindow.getWindow()); +// double windowWidth = getWindowWidth(activeWindow.getWindow()); + double windowWidth = activeWindow.getWindow().getWidth(); double windowHeight = getWindowHeight(activeWindow.getWindow()); double proposedX = xPos; if(proposedX + windowWidth > maxX) { @@ -1029,8 +1026,10 @@ private void cascadeWindows() if(proposedY + windowHeight > maxY) { proposedY = desktopCascadeWindowOffset; } - activeWindow.getWindow().setX(proposedX); - activeWindow.getWindow().setY(proposedY); + activeWindow.getWindow().getMainLayout().translateXProperty().set(proposedX); + activeWindow.getWindow().getMainLayout().translateYProperty().set(proposedY); +// activeWindow.getWindow().setX(proposedX); +// activeWindow.getWindow().setY(proposedY); activeWindow.getWindow().requestFocus(); xPos += desktopCascadeWindowOffset; yPos += desktopCascadeWindowOffset; @@ -1538,10 +1537,6 @@ private Properties getDisplayLayout() * window scroll top key name */ private static final String windowScrollTopProp = propId + "_scrollTop"; - /** - * window style id key name - */ - private static final String windowStyleId = propId + "_windowStyleId"; /** * web message service value */ diff --git a/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyView.java b/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyView.java index 566a2435e5..78dc2d8e79 100644 --- a/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyView.java +++ b/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyView.java @@ -88,7 +88,6 @@ import javafx.stage.FileChooser; import javafx.stage.FileChooser.ExtensionFilter; import javafx.stage.Modality; -import javafx.stage.WindowEvent; /* $License$ */ @@ -178,10 +177,10 @@ public void run() }},new Date(System.currentTimeMillis() + strategyRuntimeUpdateInterval),strategyRuntimeUpdateInterval); } /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { try { strategyRuntimeUpdateTimer.cancel(); diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractFixMessageView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractFixMessageView.java index 6755666e05..955ea7ddbc 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractFixMessageView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractFixMessageView.java @@ -56,7 +56,6 @@ import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; import javafx.scene.layout.VBox; -import javafx.stage.WindowEvent; /* $License$ */ @@ -130,10 +129,10 @@ public void receiveTradeMessage(TradeMessage inTradeMessage) updateReports(); } /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { tradeClientService.removeTradeMessageListener(this); } diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/orderticket/OrderTicketView.java b/photon/src/main/java/org/marketcetera/ui/trade/view/orderticket/OrderTicketView.java index 5237431c86..9ed72062cb 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/orderticket/OrderTicketView.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/orderticket/OrderTicketView.java @@ -88,7 +88,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; -import javafx.stage.WindowEvent; /* $License$ */ @@ -161,10 +160,10 @@ public void run() } } /* (non-Javadoc) - * @see org.marketcetera.ui.view.ContentView#onClose(javafx.stage.WindowEvent) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { try { serviceManager.getService(AdminClientService.class).removeBrokerStatusListener(this); diff --git a/photon/src/main/java/org/marketcetera/ui/view/ContentView.java b/photon/src/main/java/org/marketcetera/ui/view/ContentView.java index b67e24d47e..328b038b72 100644 --- a/photon/src/main/java/org/marketcetera/ui/view/ContentView.java +++ b/photon/src/main/java/org/marketcetera/ui/view/ContentView.java @@ -1,7 +1,6 @@ package org.marketcetera.ui.view; import javafx.scene.Node; -import javafx.stage.WindowEvent; /* $License$ */ @@ -28,8 +27,6 @@ public interface ContentView String getViewName(); /** * Invoked when the content view is closed. - * - * @param inEvent a WindowEvent value */ - default void onClose(WindowEvent inEvent) {} + default void onClose() {} } diff --git a/photon/src/main/resources/log4j2.xml b/photon/src/main/resources/log4j2.xml index 8c046732fb..40eaaafb99 100644 --- a/photon/src/main/resources/log4j2.xml +++ b/photon/src/main/resources/log4j2.xml @@ -11,6 +11,5 @@ - From f26c6a791c285f8268856fd95275dea4a5923928 Mon Sep 17 00:00:00 2001 From: Colin DuPlantis Date: Mon, 20 Mar 2023 09:09:46 -0700 Subject: [PATCH 3/4] MATP-1102 Partial refactoring of WindowManagerService --- .../java/org/marketcetera/ui/PhotonApp.java | 5 +- .../ui/events/NewWindowEvent.java | 4 +- .../view/MarketDataDetailViewFactory.java | 9 + .../marketdata/view/MarketDataListView.java | 2 - .../view/MarketDataListViewFactory.java | 9 + .../ui/service/WindowManagerService.java | 910 +++++++++++------- .../ui/strategy/view/StrategyViewFactory.java | 9 + .../trade/view/AbstractTradeViewFactory.java | 4 +- 8 files changed, 586 insertions(+), 366 deletions(-) diff --git a/photon/src/main/java/org/marketcetera/ui/PhotonApp.java b/photon/src/main/java/org/marketcetera/ui/PhotonApp.java index b3c077721e..689b9e1f07 100644 --- a/photon/src/main/java/org/marketcetera/ui/PhotonApp.java +++ b/photon/src/main/java/org/marketcetera/ui/PhotonApp.java @@ -31,7 +31,6 @@ import javafx.scene.control.ToolBar; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.Priority; @@ -78,7 +77,7 @@ public void start(Stage inPrimaryStage) windowManagerService.initializeMainStage(primaryStage); root = new VBox(); menuLayout = new VBox(); - workspace = new FlowPane(); + workspace = new Pane(); workspace.setId(getClass().getCanonicalName() + ".workspace"); workspace.setPrefWidth(1024); workspace.setPrefHeight(768); @@ -293,7 +292,7 @@ public static void main(String[] args) private HBox footer; private Label clockLabel; private Label userLabel; - private static FlowPane workspace; + private static Pane workspace; private ToolBar statusToolBar; private ToolBar footerToolBar; private PhotonNotificationService notificationService; diff --git a/photon/src/main/java/org/marketcetera/ui/events/NewWindowEvent.java b/photon/src/main/java/org/marketcetera/ui/events/NewWindowEvent.java index ef8745404e..1e96e885b5 100644 --- a/photon/src/main/java/org/marketcetera/ui/events/NewWindowEvent.java +++ b/photon/src/main/java/org/marketcetera/ui/events/NewWindowEvent.java @@ -65,8 +65,8 @@ default Properties getProperties() */ default Pair getWindowSize() { - return Pair.create(50.0, - 50.0); + return Pair.create(200.0, + 200.0); } /** * Indicate if the new window should be resizable. diff --git a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailViewFactory.java b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailViewFactory.java index 9879bf2f09..867a75e144 100644 --- a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailViewFactory.java +++ b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataDetailViewFactory.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.Set; +import org.marketcetera.core.Pair; import org.marketcetera.marketdata.MarketDataPermissions; import org.marketcetera.ui.events.NewWindowEvent; import org.marketcetera.ui.view.AbstractContentViewFactory; @@ -72,6 +73,14 @@ public Runnable getCommand() public void run() { webMessageService.post(new NewWindowEvent() { + /* (non-Javadoc) + * @see org.marketcetera.ui.events.NewWindowEvent#getWindowSize() + */ + @Override + public Pair getWindowSize() + { + return Pair.create(635.0,365.0); + } @Override public String getWindowTitle() { diff --git a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java index 4746f6ebab..4d2d54fd78 100644 --- a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java +++ b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListView.java @@ -142,7 +142,6 @@ public void start() @PreDestroy public void stop() { - System.out.println("COCO: stopping market data list view"); } /** * Create a new MarketDataListView instance. @@ -165,7 +164,6 @@ private void updateViewProperties() getViewProperties().setProperty(symbolsKey, String.valueOf(symbolsByRequestId.values())); } - System.out.println("COCO: view properties are now: " + getViewProperties()); } private void initializeAddSymbol() { diff --git a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListViewFactory.java b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListViewFactory.java index 10cff36a0a..9f2bd4eeba 100644 --- a/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListViewFactory.java +++ b/photon/src/main/java/org/marketcetera/ui/marketdata/view/MarketDataListViewFactory.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.Set; +import org.marketcetera.core.Pair; import org.marketcetera.marketdata.MarketDataPermissions; import org.marketcetera.ui.events.NewWindowEvent; import org.marketcetera.ui.view.AbstractContentViewFactory; @@ -72,6 +73,14 @@ public Runnable getCommand() public void run() { webMessageService.post(new NewWindowEvent() { + /* (non-Javadoc) + * @see org.marketcetera.ui.events.NewWindowEvent#getWindowSize() + */ + @Override + public Pair getWindowSize() + { + return Pair.create(900.0,300.0); + } @Override public String getWindowTitle() { diff --git a/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java b/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java index 88042012f3..a90d30f0c9 100644 --- a/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java +++ b/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java @@ -1,7 +1,6 @@ package org.marketcetera.ui.service; import java.net.URL; -import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Properties; @@ -17,7 +16,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.assertj.core.util.Lists; +import org.marketcetera.core.Pair; import org.marketcetera.core.PlatformServices; import org.marketcetera.core.Util; import org.marketcetera.ui.DragResizeMod; @@ -56,7 +55,6 @@ import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; -import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.stage.Modality; import javafx.stage.Stage; @@ -116,6 +114,12 @@ public void onLogin(LoginEvent inEvent) WindowRegistry windowRegistry = getCurrentUserRegistry(); windowRegistry.restoreLayout(displayLayout); } + /** + * + * + * + * @param inMainStage + */ public void initializeMainStage(Stage inMainStage) { mainStage = inMainStage; @@ -133,24 +137,21 @@ public void onNewWindow(NewWindowEvent inEvent) "onWindow: {}", inEvent.getWindowTitle()); // create the UI window element - final WindowLayout newWindow = createNewWindowLayout(); - if(inEvent.getWindowIcon() != null) { - // TODO need to convert to Image to show here -// newWindow.getIcons().add(PhotonServices.getSvgResource(inEvent.getWindowIcon())); - } // create the new window content - initially, the properties will be mostly or completely empty, one would expect // the content view factory will be used to create the new window content ContentViewFactory viewFactory = applicationContext.getBean(inEvent.getViewFactoryType()); // create the window meta data object, which will track data about the window + final WindowLayout newWindow = new WindowLayout(inEvent, + viewFactory); + if(inEvent.getWindowIcon() != null) { + // TODO need to convert to Image to show here +// newWindow.getIcons().add(PhotonServices.getSvgResource(inEvent.getWindowIcon())); + } WindowRegistry windowRegistry = getCurrentUserRegistry(); - WindowMetaData newWindowWrapper = new WindowMetaData(inEvent, - newWindow, - viewFactory); ContentView contentView = viewFactory.create(newWindow.getMainLayout(), inEvent, - newWindowWrapper.getProperties()); + newWindow.getProperties()); newWindow.setContentView(contentView); - newWindow.setTitle(inEvent.getWindowTitle()); // set properties of the new window based on the received event newWindow.setDraggable(inEvent.isDraggable()); newWindow.setResizable(inEvent.isResizable()); @@ -160,22 +161,24 @@ public void onNewWindow(NewWindowEvent inEvent) if(inEvent.getWindowSize().getSecondMember() > 0) { newWindow.setHeight(inEvent.getWindowSize().getSecondMember()); } - windowRegistry.addWindow(newWindowWrapper); + windowRegistry.addWindow(newWindow); // set the content of the new window newWindow.setRoot(contentView.getNode()); - windowRegistry.addWindowListeners(newWindowWrapper); + windowRegistry.addWindowListeners(newWindow); windowRegistry.updateDisplayLayout(); - // TODO pretty sure this isn't right - newWindow.getProperties().put(WindowManagerService.windowUuidProp, - inEvent.getWindowStyleId()); newWindow.show(); } - private static class WindowLayout + private class WindowLayout { - private final ObjectProperty contentViewProperty = new SimpleObjectProperty<>(); - private final static Collection windowLayouts = Lists.newArrayList(); - private WindowLayout() + private WindowLayout(NewWindowEvent inEvent, + ContentViewFactory inViewFactory) { + newWindowEventProperty.set(inEvent); + viewFactoryProperty.set(inViewFactory); + properties = inEvent.getProperties(); + setTitle(inEvent.getWindowTitle()); + uuidProperty.set(UUID.randomUUID().toString()); + setWindowStaticProperties(); windowLayout = new VBox(); windowTitleLayout = new HBox(); titleLayout = new HBox(); @@ -188,14 +191,9 @@ private WindowLayout() windowTitle = new Label(); windowTitle.textProperty().bind(windowTitleProperty); closeLabel = new Label("X"); - closeLabel.setOnMouseClicked(event -> { - contentViewProperty.get().onClose(); - close(); - }); titleLayout.getChildren().addAll(windowTitle); closeButtonLayout.getChildren().addAll(closeLabel); windowTitleLayout.getStyleClass().add("title-bar"); - HBox.setHgrow(windowTitleLayout, Priority.ALWAYS); HBox.setHgrow(titleLayout, @@ -217,10 +215,12 @@ public void onDrag(Node inNode, double inH, double inW) { - xProperty.set(inX); - yProperty.set(inY); - getMainLayout().translateXProperty().set(inX); - getMainLayout().translateYProperty().set(inY); + setX(inX); + setY(inY); +// inWindowLayout.updateProperties(); +// WindowRegistry windowRegistry = getCurrentUserRegistry(); +// windowRegistry.verifyWindowLocation(WindowLayout.this); +// windowRegistry.updateDisplayLayout(); } @Override public void onResize(Node inNode, @@ -229,29 +229,149 @@ public void onResize(Node inNode, double inH, double inW) { - heightProperty.set(inH); - widthProperty.set(inW); + setHeight(inH); + setWidth(inW); +// WindowRegistry windowRegistry = getCurrentUserRegistry(); +// windowRegistry.verifyWindowLocation(WindowLayout.this); +// windowRegistry.updateDisplayLayout(); } }); windowLayout.getStyleClass().add("view"); windowLayout.getStylesheets().clear(); windowLayout.getStylesheets().add("dark-mode.css"); - windowLayout.minWidthProperty().bindBidirectional(widthProperty); - windowLayout.minHeightProperty().bindBidirectional(heightProperty); - synchronized(windowLayouts) { - windowLayouts.add(this); +// DropShadow dropShadow = new DropShadow(BlurType.THREE_PASS_BOX,new Color(0,0,0,0.8),10,0,0,0); +// windowLayout.setEffect(dropShadow); +// windowLayout.setPickOnBounds(false); + setupWindowListeners(); + Pair suggestedWindowSize = inEvent.getWindowSize(); + String rawProperty = StringUtils.trimToNull(properties.getProperty(windowWidthProp)); + if(rawProperty == null) { + setWidth(suggestedWindowSize.getFirstMember()); + } else { + setWidth(Double.parseDouble(rawProperty)); + } + rawProperty = StringUtils.trimToNull(properties.getProperty(windowHeightProp)); + if(rawProperty == null) { + setHeight(suggestedWindowSize.getSecondMember()); + } else { + setHeight(Double.parseDouble(rawProperty)); + } + rawProperty = StringUtils.trimToNull(properties.getProperty(windowPosXProp)); + if(rawProperty == null) { + setX(200); + } else { + setX(Double.parseDouble(rawProperty)); } + rawProperty = StringUtils.trimToNull(properties.getProperty(windowPosYProp)); + if(rawProperty == null) { + setY(200); + } else { + setY(Double.parseDouble(rawProperty)); + } + } + private void setupWindowListeners() + { + closeLabel.setOnMouseClicked(event -> { + contentViewProperty.get().onClose(); + close(); + }); windowLayout.setOnMouseClicked(event -> { - synchronized(windowLayouts) { - for(WindowLayout windowLayout : windowLayouts) { - windowLayout.getMainLayout().viewOrderProperty().set(1.0); + WindowRegistry windowRegistry = getCurrentUserRegistry(); + synchronized(windowRegistry.activeWindows) { + for(WindowLayout windowLayout : windowRegistry.activeWindows) { + windowLayout.getMainLayout().viewOrderProperty().set(0.0); } } windowLayout.viewOrderProperty().set(-1.0); }); -// DropShadow dropShadow = new DropShadow(BlurType.THREE_PASS_BOX,new Color(0,0,0,0.8),10,0,0,0); -// windowLayout.setEffect(dropShadow); -// windowLayout.setPickOnBounds(false); + xProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowPosXProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + " updated: " + properties); + }); + yProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowPosYProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + " updated: " + properties); + }); + heightProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowHeightProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + "height updated: " + properties); + }); + widthProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowWidthProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + " width updated: " + properties); + }); + windowTitleProperty.addListener((observableValue,oldValue,newValue) -> { + if(newValue == null) { + properties.remove(windowTitleProp); + } else { + properties.setProperty(windowTitleProp, + getTitle()); + } + System.out.println(uuidProperty.get() + " updated: " + properties); + }); + draggableProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowDraggableProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + " updated: " + properties); + }); + resizableProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowResizableProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + " updated: " + properties); + }); + scrollLeftProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowScrollLeftProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + " updated: " + properties); + }); + scrollTopProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowScrollTopProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + " updated: " + properties); + }); + viewOrderProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowViewOrderProp, + String.valueOf(newValue)); + System.out.println(uuidProperty.get() + " updated: " + properties); + }); + // TODO +// properties.setProperty(windowModeProp, +// String.valueOf(isMaximized())); + } + /** + * Update the window object with the stored telemetry. + */ + private void updateWindow() + { + setWidth(Double.parseDouble(properties.getProperty(windowWidthProp))); + setHeight(Double.parseDouble(properties.getProperty(windowHeightProp))); + setModality(properties.getProperty(windowModalProp) == null ? Modality.NONE:Modality.valueOf(properties.getProperty(windowModalProp))); + Boolean isMaximized = Boolean.parseBoolean(properties.getProperty(windowModeProp)); + setMaximized(isMaximized); + setScrollLeft(Double.parseDouble(properties.getProperty(windowScrollLeftProp))); + setScrollTop(Double.parseDouble(properties.getProperty(windowScrollTopProp))); + setDraggable(Boolean.parseBoolean(properties.getProperty(windowDraggableProp))); + setResizable(Boolean.parseBoolean(properties.getProperty(windowResizableProp))); + setTitle(properties.getProperty(windowTitleProp)); + setX(getDoubleValue(properties, + windowPosXProp)); + setY(getDoubleValue(properties, + windowPosYProp)); + setViewOrder(Double.parseDouble(windowViewOrderProp)); + } + /** + * + * + * @param inViewOrder + */ + private void setViewOrder(double inViewOrder) + { + viewOrderProperty.set(inViewOrder); + Platform.runLater(() -> windowLayout.setViewOrder(inViewOrder)); } private void setContentView(ContentView inContentView) { @@ -299,7 +419,9 @@ private void setDraggable(boolean inDraggable) */ private void setHeight(double inHeight) { + heightProperty.set(inHeight); windowLayout.setPrefHeight(inHeight); + windowLayout.setMinHeight(inHeight); } /** * @@ -308,7 +430,9 @@ private void setHeight(double inHeight) */ private void setWidth(double inWidth) { + widthProperty.set(inWidth); windowLayout.setPrefWidth(inWidth); + windowLayout.setMinWidth(inWidth); } /** * @@ -471,6 +595,7 @@ private void setScrollTop(double inScrollTop) private void setX(double inX) { xProperty.set(inX); + getMainLayout().translateXProperty().set(inX); } /** * @@ -480,6 +605,7 @@ private void setX(double inX) private void setY(double inY) { yProperty.set(inY); + getMainLayout().translateYProperty().set(inY); } /** * @@ -487,22 +613,54 @@ private void setY(double inY) */ private void close() { -// if(!windowRegistry.isLoggingOut()) { -// windowRegistry.removeWindow(inWindowWrapper); -// updateDisplayLayout(); -// } + WindowRegistry windowRegistry = getCurrentUserRegistry(); + if(!windowRegistry.isLoggingOut()) { + windowRegistry.removeWindow(this); + windowRegistry.updateDisplayLayout(); + } PhotonApp.getWorkspace().getChildren().remove(getMainLayout()); } private void show() { - getMainLayout().translateXProperty().set(200); - getMainLayout().translateYProperty().set(200); - windowLayout.setMinHeight(Region.USE_COMPUTED_SIZE); - windowLayout.setMinWidth(Region.USE_COMPUTED_SIZE); + System.out.println("COCO: displaying " + uuidProperty + " x: " + getX() + " y: " + getY() + + " width: " + getWidth() + " height: " + getHeight() + + " minWidth: " + windowLayout.getMinWidth() + " minHeight: " + windowLayout.getMinHeight() + + " prefWidth: " + windowLayout.getPrefWidth() + " prefHeight: " + windowLayout.getPrefHeight() + + " layoutWidth: " + windowLayout.getWidth() + " layoutHeight: " + windowLayout.getHeight()); + getMainLayout().translateXProperty().set(getX()); + getMainLayout().translateYProperty().set(getY()); windowLayout.setViewOrder(-1); + windowLayout.autosize(); + System.out.println("COCO: displaying " + uuidProperty + " x: " + getX() + " y: " + getY() + + " width: " + getWidth() + " height: " + getHeight() + + " minWidth: " + windowLayout.getMinWidth() + " minHeight: " + windowLayout.getMinHeight() + + " prefWidth: " + windowLayout.getPrefWidth() + " prefHeight: " + windowLayout.getPrefHeight() + + " layoutWidth: " + windowLayout.getWidth() + " layoutHeight: " + windowLayout.getHeight()); PhotonApp.getWorkspace().getChildren().add(getMainLayout()); requestFocus(); } + /** + * Set the immutable properties of this window to the underlying properties storage. + */ + private void setWindowStaticProperties() + { + properties.setProperty(windowContentViewFactoryProp, + viewFactoryProperty.get().getClass().getCanonicalName()); + properties.setProperty(windowUuidProp, + uuidProperty.get()); + } + private final ObjectProperty contentViewProperty = new SimpleObjectProperty<>(); + private final ObjectProperty newWindowEventProperty = new SimpleObjectProperty<>(); + private final DoubleProperty viewOrderProperty = new SimpleDoubleProperty(); + /** + * cached uuid value + */ + private final StringProperty uuidProperty = new SimpleStringProperty(); + /** + * properties used to record details about this window + */ + private final Properties properties; + private final ObjectProperty viewFactoryProperty = new SimpleObjectProperty<>(); private final DoubleProperty heightProperty = new SimpleDoubleProperty(); private final DoubleProperty widthProperty = new SimpleDoubleProperty(); private final DoubleProperty xProperty = new SimpleDoubleProperty(); @@ -522,10 +680,25 @@ private void show() private VBox contentLayout; private Label windowTitle; private Label closeLabel; - } - private WindowLayout createNewWindowLayout() - { - return new WindowLayout(); + /** + * + * + * @return + */ + private String getUuid() + { + return uuidProperty.get(); + } + /** + * + * + * @return + */ + private String getStorableValue() + { + System.out.println("Storing: " + properties); + return Util.propertiesToString(properties); + } } /** * Receive logout events. @@ -701,6 +874,14 @@ private static double getDoubleValue(Properties inProperties, private class RestartNewWindowEvent implements NewWindowEvent { + /* (non-Javadoc) + * @see org.marketcetera.ui.events.NewWindowEvent#getProperties() + */ + @Override + public Properties getProperties() + { + return properties; + } /* (non-Javadoc) * @see org.marketcetera.ui.events.NewWindowEvent#getWindowIcon() */ @@ -732,14 +913,19 @@ public Class getViewFactoryType() * Create a new RestartNewWindowEvent instance. * * @param inContentViewFactory a ContentViewFactory value - * @param inWindowTitle a String value + * @param inProperties a Properties value */ private RestartNewWindowEvent(ContentViewFactory inContentViewFactory, - String inWindowTitle) + Properties inProperties) { contentViewFactory = inContentViewFactory; - windowTitle = inWindowTitle; + properties = inProperties; + windowTitle = properties.getProperty(windowTitleProp); } + /** + * window properties value + */ + private final Properties properties; /** * content view factory value */ @@ -749,219 +935,219 @@ private RestartNewWindowEvent(ContentViewFactory inContentViewFactory, */ private final String windowTitle; } - /** - * Holds meta-data for windows. - * - * @author Colin DuPlantis - * @version $Id$ - * @since $Release$ - */ - private class WindowMetaData - { - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - return properties.toString(); - } - /** - * Create a new WindowMetaData instance. - * - *

This constructor is invoked for a new window. - * - * @param inEvent a NewWindowEvent value - * @param inWindow a WindowLayout value - * @param inContentViewFactory a ContentViewFactory value - */ - private WindowMetaData(NewWindowEvent inEvent, - WindowLayout inWindow, - ContentViewFactory inContentViewFactory) - { - properties = inEvent.getProperties(); - window = inWindow; - setWindowStaticProperties(inContentViewFactory, - UUID.randomUUID().toString()); - updateProperties(); - } - /** - * Create a new WindowMetaData instance. - * - *

This constructor is invoked to recreate a previously-created window. - * - * @param inProperties a Properties value - * @param inWindow a WindowLayout value - */ - private WindowMetaData(Properties inProperties, - WindowLayout inWindow) - { - // TODO need to do a permissions re-check, perhaps - window = inWindow; - properties = inProperties; - try { - ContentViewFactory contentViewFactory = (ContentViewFactory)applicationContext.getBean(Class.forName(inProperties.getProperty(windowContentViewFactoryProp))); - ContentView contentView = contentViewFactory.create(window.getMainLayout(), - new RestartNewWindowEvent(contentViewFactory, - properties.getProperty(windowTitleProp)), - properties); - inWindow.contentViewProperty.set(contentView); - window.setRoot(contentView.getNode()); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - // update window from properties, effectively restoring it to its previous state - updateWindow(); - } - /** - * Get the storable value for this window. - * - * @return a String value - */ - private String getStorableValue() - { - return Util.propertiesToString(properties); - } - /** - * Get the properties value. - * - * @return a Properties value - */ - private Properties getProperties() - { - return properties; - } - /** - * Get the window value. - * - * @return a WindowLayout value - */ - private WindowLayout getWindow() - { - return window; - } - /** - * Update the window telemetry from the underlying window object. - */ - private void updateProperties() - { - properties.setProperty(windowPosXProp, - String.valueOf(window.getX())); - properties.setProperty(windowPosYProp, - String.valueOf(window.getX())); - properties.setProperty(windowHeightProp, - String.valueOf(window.getHeight())); - properties.setProperty(windowWidthProp, - String.valueOf(window.getWidth())); - properties.setProperty(windowModeProp, - String.valueOf(window.isMaximized())); - if(window.getTitle() != null) { - properties.setProperty(windowTitleProp, - window.getTitle()); - } - properties.setProperty(windowDraggableProp, - String.valueOf(window.isDraggable())); - properties.setProperty(windowResizableProp, - String.valueOf(window.isResizable())); - properties.setProperty(windowScrollLeftProp, - String.valueOf(window.getScrollLeft())); - properties.setProperty(windowScrollTopProp, - String.valueOf(window.getScrollLeft())); - properties.setProperty(windowFocusProp, - String.valueOf(hasFocus())); - } - /** - * Update the window object with the stored telemetry. - */ - private void updateWindow() - { - window.setWidth(Double.parseDouble(properties.getProperty(windowWidthProp))); - window.setHeight(Double.parseDouble(properties.getProperty(windowHeightProp))); - window.setModality(properties.getProperty(windowModalProp) == null ? Modality.NONE:Modality.valueOf(properties.getProperty(windowModalProp))); - Boolean isMaximized = Boolean.parseBoolean(properties.getProperty(windowModeProp)); - window.setMaximized(isMaximized); - window.setScrollLeft(Double.parseDouble(properties.getProperty(windowScrollLeftProp))); - window.setScrollTop(Double.parseDouble(properties.getProperty(windowScrollTopProp))); - window.setDraggable(Boolean.parseBoolean(properties.getProperty(windowDraggableProp))); - window.setResizable(Boolean.parseBoolean(properties.getProperty(windowResizableProp))); - window.setTitle(properties.getProperty(windowTitleProp)); - window.setX(getDoubleValue(properties, - windowPosXProp)); - window.setY(getDoubleValue(properties, - windowPosYProp)); - setHasFocus(Boolean.parseBoolean(properties.getProperty(windowFocusProp))); - if(hasFocus) { - window.requestFocus(); - } - } - /** - * Set the immutable properties of this window to the underlying properties storage. - * - * @param inContentViewFactory a ContentViewFactory value - * @param inUuid a Stringvalue - */ - private void setWindowStaticProperties(ContentViewFactory inContentViewFactory, - String inUuid) - { - properties.setProperty(windowContentViewFactoryProp, - inContentViewFactory.getClass().getCanonicalName()); - properties.setProperty(windowUuidProp, - inUuid); - } - /** - * Close this window and remove it from active use. - */ - private void close() - { - getWindow().close(); - } - /** - * Get the window uuid value. - * - * @return a String value - */ - private String getUuid() - { - if(uuid == null) { - uuid = properties.getProperty(windowUuidProp); - } - return uuid; - } - /** - * Get the hasFocus value. - * - * @return a boolean value - */ - private boolean hasFocus() - { - return hasFocus; - } - /** - * Sets the hasFocus value. - * - * @param inHasFocus a boolean value - */ - private void setHasFocus(boolean inHasFocus) - { - hasFocus = inHasFocus; - } - /** - * indicates if this window has focus or not - */ - private transient boolean hasFocus; - /** - * cached uuid value - */ - private transient String uuid; - /** - * properties used to record details about this window - */ - private final Properties properties; - /** - * underlying UI element - */ - private final WindowLayout window; - } +// /** +// * Holds meta-data for windows. +// * +// * @author Colin DuPlantis +// * @version $Id$ +// * @since $Release$ +// */ +// private class WindowMetaData +// { +// /* (non-Javadoc) +// * @see java.lang.Object#toString() +// */ +// @Override +// public String toString() +// { +// return properties.toString(); +// } +// /** +// * Create a new WindowMetaData instance. +// * +// *

This constructor is invoked for a new window. +// * +// * @param inEvent a NewWindowEvent value +// * @param inWindow a WindowLayout value +// * @param inContentViewFactory a ContentViewFactory value +// */ +// private WindowMetaData(NewWindowEvent inEvent, +// WindowLayout inWindow, +// ContentViewFactory inContentViewFactory) +// { +// properties = inEvent.getProperties(); +// window = inWindow; +// setWindowStaticProperties(inContentViewFactory, +// UUID.randomUUID().toString()); +// updateProperties(); +// } +// /** +// * Create a new WindowMetaData instance. +// * +// *

This constructor is invoked to recreate a previously-created window. +// * +// * @param inProperties a Properties value +// * @param inWindow a WindowLayout value +// */ +// private WindowMetaData(Properties inProperties, +// WindowLayout inWindow) +// { +// // TODO need to do a permissions re-check, perhaps +// window = inWindow; +// properties = inProperties; +// try { +// ContentViewFactory contentViewFactory = (ContentViewFactory)applicationContext.getBean(Class.forName(inProperties.getProperty(windowContentViewFactoryProp))); +// ContentView contentView = contentViewFactory.create(window.getMainLayout(), +// new RestartNewWindowEvent(contentViewFactory, +// properties.getProperty(windowTitleProp)), +// properties); +// inWindow.contentViewProperty.set(contentView); +// window.setRoot(contentView.getNode()); +// } catch (ClassNotFoundException e) { +// throw new RuntimeException(e); +// } +// // update window from properties, effectively restoring it to its previous state +// updateWindow(); +// } +// /** +// * Get the storable value for this window. +// * +// * @return a String value +// */ +// private String getStorableValue() +// { +// return Util.propertiesToString(properties); +// } +// /** +// * Get the properties value. +// * +// * @return a Properties value +// */ +// private Properties getProperties() +// { +// return properties; +// } +// /** +// * Get the window value. +// * +// * @return a WindowLayout value +// */ +// private WindowLayout getWindow() +// { +// return window; +// } +// /** +// * Update the window telemetry from the underlying window object. +// */ +// private void updateProperties() +// { +// properties.setProperty(windowPosXProp, +// String.valueOf(window.getX())); +// properties.setProperty(windowPosYProp, +// String.valueOf(window.getX())); +// properties.setProperty(windowHeightProp, +// String.valueOf(window.getHeight())); +// properties.setProperty(windowWidthProp, +// String.valueOf(window.getWidth())); +// properties.setProperty(windowModeProp, +// String.valueOf(window.isMaximized())); +// if(window.getTitle() != null) { +// properties.setProperty(windowTitleProp, +// window.getTitle()); +// } +// properties.setProperty(windowDraggableProp, +// String.valueOf(window.isDraggable())); +// properties.setProperty(windowResizableProp, +// String.valueOf(window.isResizable())); +// properties.setProperty(windowScrollLeftProp, +// String.valueOf(window.getScrollLeft())); +// properties.setProperty(windowScrollTopProp, +// String.valueOf(window.getScrollLeft())); +// properties.setProperty(windowFocusProp, +// String.valueOf(hasFocus())); +// } +// /** +// * Update the window object with the stored telemetry. +// */ +// private void updateWindow() +// { +// window.setWidth(Double.parseDouble(properties.getProperty(windowWidthProp))); +// window.setHeight(Double.parseDouble(properties.getProperty(windowHeightProp))); +// window.setModality(properties.getProperty(windowModalProp) == null ? Modality.NONE:Modality.valueOf(properties.getProperty(windowModalProp))); +// Boolean isMaximized = Boolean.parseBoolean(properties.getProperty(windowModeProp)); +// window.setMaximized(isMaximized); +// window.setScrollLeft(Double.parseDouble(properties.getProperty(windowScrollLeftProp))); +// window.setScrollTop(Double.parseDouble(properties.getProperty(windowScrollTopProp))); +// window.setDraggable(Boolean.parseBoolean(properties.getProperty(windowDraggableProp))); +// window.setResizable(Boolean.parseBoolean(properties.getProperty(windowResizableProp))); +// window.setTitle(properties.getProperty(windowTitleProp)); +// window.setX(getDoubleValue(properties, +// windowPosXProp)); +// window.setY(getDoubleValue(properties, +// windowPosYProp)); +// setHasFocus(Boolean.parseBoolean(properties.getProperty(windowFocusProp))); +// if(hasFocus) { +// window.requestFocus(); +// } +// } +// /** +// * Set the immutable properties of this window to the underlying properties storage. +// * +// * @param inContentViewFactory a ContentViewFactory value +// * @param inUuid a Stringvalue +// */ +// private void setWindowStaticProperties(ContentViewFactory inContentViewFactory, +// String inUuid) +// { +// properties.setProperty(windowContentViewFactoryProp, +// inContentViewFactory.getClass().getCanonicalName()); +// properties.setProperty(windowUuidProp, +// inUuid); +// } +// /** +// * Close this window and remove it from active use. +// */ +// private void close() +// { +// getWindow().close(); +// } +// /** +// * Get the window uuid value. +// * +// * @return a String value +// */ +// private String getUuid() +// { +// if(uuid == null) { +// uuid = properties.getProperty(windowUuidProp); +// } +// return uuid; +// } +// /** +// * Get the hasFocus value. +// * +// * @return a boolean value +// */ +// private boolean hasFocus() +// { +// return hasFocus; +// } +// /** +// * Sets the hasFocus value. +// * +// * @param inHasFocus a boolean value +// */ +// private void setHasFocus(boolean inHasFocus) +// { +// hasFocus = inHasFocus; +// } +// /** +// * indicates if this window has focus or not +// */ +// private transient boolean hasFocus; +// /** +// * cached uuid value +// */ +// private transient String uuid; +// /** +// * properties used to record details about this window +// */ +// private final Properties properties; +// /** +// * underlying UI element +// */ +// private final WindowLayout window; +// } /** * Provides a registry of all windows. * @@ -974,9 +1160,9 @@ private class WindowRegistry /** * Add the given window to this registry. * - * @param inWindowMetaData a WindowWrapper value + * @param inWindowLayout a WindowLayout value */ - private void addWindow(WindowMetaData inWindowMetaData) + private void addWindow(WindowLayout inWindowMetaData) { synchronized(activeWindows) { activeWindows.add(inWindowMetaData); @@ -990,8 +1176,8 @@ private void addWindow(WindowMetaData inWindowMetaData) private void closeAllWindows(boolean inUpdateDisplay) { synchronized(activeWindows) { - Set tempActiveWindows = new HashSet<>(activeWindows); - for(WindowMetaData window : tempActiveWindows) { + Set tempActiveWindows = new HashSet<>(activeWindows); + for(WindowLayout window : tempActiveWindows) { window.close(); } if(inUpdateDisplay) { @@ -1014,10 +1200,9 @@ private void cascadeWindows() DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); double maxX = params.getRight(); double maxY = params.getBottom(); - for(WindowMetaData activeWindow : activeWindows) { -// double windowWidth = getWindowWidth(activeWindow.getWindow()); - double windowWidth = activeWindow.getWindow().getWidth(); - double windowHeight = getWindowHeight(activeWindow.getWindow()); + for(WindowLayout activeWindow : activeWindows) { + double windowWidth = activeWindow.getWidth(); + double windowHeight = activeWindow.getHeight(); double proposedX = xPos; if(proposedX + windowWidth > maxX) { proposedX = desktopCascadeWindowOffset; @@ -1026,14 +1211,12 @@ private void cascadeWindows() if(proposedY + windowHeight > maxY) { proposedY = desktopCascadeWindowOffset; } - activeWindow.getWindow().getMainLayout().translateXProperty().set(proposedX); - activeWindow.getWindow().getMainLayout().translateYProperty().set(proposedY); -// activeWindow.getWindow().setX(proposedX); -// activeWindow.getWindow().setY(proposedY); - activeWindow.getWindow().requestFocus(); + activeWindow.setX(proposedX); + activeWindow.setY(proposedY); + activeWindow.requestFocus(); xPos += desktopCascadeWindowOffset; yPos += desktopCascadeWindowOffset; - activeWindow.updateProperties(); +// activeWindow.updateProperties(); } } updateDisplayLayout(); @@ -1069,19 +1252,19 @@ private void tileWindows() int rowNum = 0; double posX = params.getLeft(); double posY = params.getTop(); - for(WindowMetaData activeWindow : activeWindows) { + for(WindowLayout activeWindow : activeWindows) { double suggestedX = posX + (colNum * windowWidth); double suggestedY = posY + (rowNum * windowHeight); - activeWindow.getWindow().setWidth(windowWidth); - activeWindow.getWindow().setHeight(windowHeight); - activeWindow.getWindow().setX(suggestedX); - activeWindow.getWindow().setY(suggestedY); + activeWindow.setWidth(windowWidth); + activeWindow.setHeight(windowHeight); + activeWindow.setX(suggestedX); + activeWindow.setY(suggestedY); colNum += 1; if(colNum == numCols) { colNum = 0; rowNum += 1; } - activeWindow.updateProperties(); +// activeWindow.updateProperties(); } } updateDisplayLayout(); @@ -1122,12 +1305,24 @@ private void restoreLayout(Properties inDisplayLayout) "Restoring {} {}", windowUid, windowProperties); - WindowLayout newWindow = createNewWindowLayout(); - WindowMetaData newWindowMetaData = new WindowMetaData(windowProperties, - newWindow); - addWindow(newWindowMetaData); - addWindowListeners(newWindowMetaData); - PhotonApp.getWorkspace().getChildren().add(newWindowMetaData.getWindow().getMainLayout()); + // TODO need to do a permissions re-check, perhaps + try { + ContentViewFactory viewFactory = (ContentViewFactory)applicationContext.getBean(Class.forName(windowProperties.getProperty(windowContentViewFactoryProp))); + RestartNewWindowEvent restartWindowEvent = new RestartNewWindowEvent(viewFactory, + windowProperties); + WindowLayout newWindow = new WindowLayout(restartWindowEvent, + viewFactory); + ContentView contentView = viewFactory.create(newWindow.getMainLayout(), + restartWindowEvent, + windowProperties); + newWindow.contentViewProperty.set(contentView); + newWindow.setRoot(contentView.getNode()); + addWindow(newWindow); + addWindowListeners(newWindow); + newWindow.show(); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } } } } @@ -1152,12 +1347,12 @@ private void updateDisplayLayout() /** * Add the necessary window listeners to the given window meta data. * - * @param inWindowWrapper a WindowMetaData value + * @param inWindowWrapper a WindowLayout value */ - private void addWindowListeners(WindowMetaData inWindowWrapper) + private void addWindowListeners(WindowLayout inWindowWrapper) { WindowRegistry windowRegistry = this; - WindowLayout newWindow = inWindowWrapper.getWindow(); + WindowLayout newWindow = inWindowWrapper; // newWindow.addEventHandler(MouseEvent.MOUSE_CLICKED, // new EventHandler() { // @Override @@ -1258,13 +1453,13 @@ private void addWindowListeners(WindowMetaData inWindowWrapper) // ); } private void newWindowResize(String inDimension, - WindowMetaData inWindowWrapper) + WindowLayout inWindowLayout) { SLF4JLoggerProxy.trace(WindowManagerService.this, "Verify: {}", inDimension); - verifyWindowLocation(inWindowWrapper.getWindow()); - inWindowWrapper.updateProperties(); + verifyWindowLocation(inWindowLayout); +// inWindowLayout.updateProperties(); updateDisplayLayout(); } /** @@ -1296,59 +1491,60 @@ private void verifyWindowLocation(WindowLayout inWindow) */ private void returnWindowToDesktop(WindowLayout inWindow) { - int pad = desktopViewableAreaPad; - DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); - // the order here is important: first, resize the window, if necessary - double maxWidth = params.getRight()-params.getLeft(); - double windowWidth = getWindowWidth(inWindow); - if(windowWidth > maxWidth) { - inWindow.setWidth(maxWidth - (pad*2)); - } - if(windowWidth <= 10) { - windowWidth = 100; - inWindow.setWidth(windowWidth); - } - double maxHeight = params.getBottom() - params.getTop(); - double windowHeight = getWindowHeight(inWindow); - if(windowHeight > maxHeight) { - inWindow.setHeight(maxHeight - (pad*2)); - } - // window is now no larger than desktop - // check bottom - double windowBottom = getWindowBottom(inWindow); - if(windowBottom > params.getBottom()) { - double newWindowTop = params.getBottom() - getWindowHeight(inWindow) - pad; - inWindow.setY(newWindowTop); - } - // check top - double windowTop = getWindowTop(inWindow); - if(windowTop < params.getTop()+pad) { - double newWindowTop = params.getTop() + pad; - inWindow.setY(newWindowTop); - } - // window is now within the desktop Y range - // check left - double windowLeft = getWindowLeft(inWindow); - if(windowLeft < params.getLeft()) { - double newWindowLeft = params.getLeft() + pad; - inWindow.setX(newWindowLeft); - } - // check right - double windowRight = getWindowRight(inWindow); - if(windowRight > params.getRight()) { - double newWindowLeft = params.getRight() - getWindowWidth(inWindow) - pad; - inWindow.setX(newWindowLeft); - } +// System.out.println("Entering returnWindowToDesktop"); +// int pad = desktopViewableAreaPad; +// DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); +// // the order here is important: first, resize the window, if necessary +// double maxWidth = params.getRight()-params.getLeft(); +// double windowWidth = getWindowWidth(inWindow); +// if(windowWidth > maxWidth) { +// inWindow.setWidth(maxWidth - (pad*2)); +// } +// if(windowWidth <= 10) { +// windowWidth = 100; +// inWindow.setWidth(windowWidth); +// } +// double maxHeight = params.getBottom() - params.getTop(); +// double windowHeight = getWindowHeight(inWindow); +// if(windowHeight > maxHeight) { +// inWindow.setHeight(maxHeight - (pad*2)); +// } +// // window is now no larger than desktop +// // check bottom +// double windowBottom = getWindowBottom(inWindow); +// if(windowBottom > params.getBottom()) { +// double newWindowTop = params.getBottom() - getWindowHeight(inWindow) - pad; +// inWindow.setY(newWindowTop); +// } +// // check top +// double windowTop = getWindowTop(inWindow); +// if(windowTop < params.getTop()+pad) { +// double newWindowTop = params.getTop() + pad; +// inWindow.setY(newWindowTop); +// } +// // window is now within the desktop Y range +// // check left +// double windowLeft = getWindowLeft(inWindow); +// if(windowLeft < params.getLeft()) { +// double newWindowLeft = params.getLeft() + pad; +// inWindow.setX(newWindowLeft); +// } +// // check right +// double windowRight = getWindowRight(inWindow); +// if(windowRight > params.getRight()) { +// double newWindowLeft = params.getRight() - getWindowWidth(inWindow) - pad; +// inWindow.setX(newWindowLeft); +// } } /** * Remove the given window from this registry. * - * @param inWindowMetaData a WindowMetaData value + * @param inWindowLayout a WindowLayout value */ - private void removeWindow(WindowMetaData inWindowMetaData) + private void removeWindow(WindowLayout inWindowLayout) { synchronized(activeWindows) { - activeWindows.remove(inWindowMetaData); + activeWindows.remove(inWindowLayout); } } /** @@ -1382,10 +1578,10 @@ private void verifyAllWindowPositions() @Override public void run() { - for(WindowMetaData windowMetaData : activeWindows) { + for(WindowLayout window : activeWindows) { try { - if(WindowManagerService.this.isWindowOutsideDesktop(windowMetaData.getWindow())) { - returnWindowToDesktop(windowMetaData.getWindow()); + if(WindowManagerService.this.isWindowOutsideDesktop(window)) { + returnWindowToDesktop(window); } } catch (Exception e) { SLF4JLoggerProxy.warn(WindowManagerService.this, @@ -1451,7 +1647,7 @@ private Properties getDisplayLayout() { synchronized(activeWindows) { Properties displayLayout = new Properties(); - for(WindowMetaData activeWindow : activeWindows) { + for(WindowLayout activeWindow : activeWindows) { String windowKey = activeWindow.getUuid(); String windowValue = activeWindow.getStorableValue(); displayLayout.setProperty(windowKey, @@ -1467,7 +1663,7 @@ private Properties getDisplayLayout() /** * holds all active windows */ - private final Set activeWindows = Sets.newHashSet(); + private final Set activeWindows = Sets.newHashSet(); /** * holds the token for the window position monitor job, if any */ @@ -1480,7 +1676,7 @@ private Properties getDisplayLayout() /** * base key for {@see UserAttributeType} display layout properties */ - private static final String propId = WindowMetaData.class.getSimpleName(); + private static final String propId = WindowLayout.class.getSimpleName(); /** * window uuid key name */ @@ -1518,9 +1714,9 @@ private Properties getDisplayLayout() */ private static final String windowModalProp = propId + "_modal"; /** - * window is focused key name + * window view order key name */ - private static final String windowFocusProp = propId + "_focus"; + private static final String windowViewOrderProp = propId + "_viewOrder"; /** * window is draggable key name */ diff --git a/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyViewFactory.java b/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyViewFactory.java index 13d9240158..a076059039 100644 --- a/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyViewFactory.java +++ b/photon/src/main/java/org/marketcetera/ui/strategy/view/StrategyViewFactory.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.Set; +import org.marketcetera.core.Pair; import org.marketcetera.strategy.StrategyPermissions; import org.marketcetera.ui.events.NewWindowEvent; import org.marketcetera.ui.view.AbstractContentViewFactory; @@ -72,6 +73,14 @@ public Runnable getCommand() public void run() { webMessageService.post(new NewWindowEvent() { + /* (non-Javadoc) + * @see org.marketcetera.ui.events.NewWindowEvent#getWindowSize() + */ + @Override + public Pair getWindowSize() + { + return Pair.create(530.0,400.0); + } @Override public String getWindowTitle() { diff --git a/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractTradeViewFactory.java b/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractTradeViewFactory.java index 312dd31e79..ac783b3316 100644 --- a/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractTradeViewFactory.java +++ b/photon/src/main/java/org/marketcetera/ui/trade/view/AbstractTradeViewFactory.java @@ -53,8 +53,8 @@ public void run() */ protected Pair getWindowSize() { - return Pair.create(0.0, - 0.0); + return Pair.create(800.0, + 300.0); } /** * Get the content view factory for this view factory. From 415285ecadcbda2e85e144361928a1156c00ebd7 Mon Sep 17 00:00:00 2001 From: Colin DuPlantis Date: Mon, 20 Mar 2023 15:21:36 -0700 Subject: [PATCH 4/4] MATP-1102 Complete refactoring on WindowManagerService --- .../java/org/marketcetera/ui/PhotonApp.java | 28 +- .../ui/service/WindowManagerService.java | 1413 ++++++----------- 2 files changed, 552 insertions(+), 889 deletions(-) diff --git a/photon/src/main/java/org/marketcetera/ui/PhotonApp.java b/photon/src/main/java/org/marketcetera/ui/PhotonApp.java index 689b9e1f07..1792f5b3ee 100644 --- a/photon/src/main/java/org/marketcetera/ui/PhotonApp.java +++ b/photon/src/main/java/org/marketcetera/ui/PhotonApp.java @@ -4,14 +4,15 @@ import java.awt.Taskbar.Feature; import java.awt.Toolkit; import java.io.IOException; +import java.util.Properties; import org.marketcetera.ui.events.LoginEvent; import org.marketcetera.ui.events.LogoutEvent; +import org.marketcetera.ui.service.DisplayLayoutService; import org.marketcetera.ui.service.PhotonNotificationService; import org.marketcetera.ui.service.SessionUser; import org.marketcetera.ui.service.StyleService; import org.marketcetera.ui.service.WebMessageService; -import org.marketcetera.ui.service.WindowManagerService; import org.marketcetera.ui.view.ApplicationMenu; import org.marketcetera.util.log.SLF4JLoggerProxy; import org.springframework.context.ApplicationContext; @@ -60,8 +61,8 @@ public void init() super.init(); applicationContext = new AnnotationConfigApplicationContext("org.marketcetera","com.marketcetera"); webMessageService = applicationContext.getBean(WebMessageService.class); - windowManagerService = applicationContext.getBean(WindowManagerService.class); styleService = applicationContext.getBean(StyleService.class); + displayLayoutService = applicationContext.getBean(DisplayLayoutService.class); webMessageService.register(this); } /* (non-Javadoc) @@ -74,7 +75,6 @@ public void start(Stage inPrimaryStage) SLF4JLoggerProxy.info(this, "Starting main stage"); primaryStage = inPrimaryStage; - windowManagerService.initializeMainStage(primaryStage); root = new VBox(); menuLayout = new VBox(); workspace = new Pane(); @@ -260,6 +260,23 @@ public static void main(String[] args) { launch(); } + private Properties displayProperties; + /** + * base key for {@see UserAttributeType} display layout properties + */ + private static final String propId = PhotonApp.class.getSimpleName(); + /** + * workspace width key name + */ + private static final String workspaceWidthProp = propId + "_workspaceWidth"; + /** + * workspace height key name + */ + private static final String workspaceHeightProp = propId + "_workspaceHeight"; + /** + * workspace layout key name + */ + private static final String mainWorkspaceLayoutKey = propId + "_workspaceDisplayLayout"; /** * footer holder for the server connection status image */ @@ -285,7 +302,6 @@ public static void main(String[] args) * web message service value */ private WebMessageService webMessageService; - private WindowManagerService windowManagerService; private VBox menuLayout; private ApplicationContext applicationContext; private VBox root; @@ -296,4 +312,8 @@ public static void main(String[] args) private ToolBar statusToolBar; private ToolBar footerToolBar; private PhotonNotificationService notificationService; + /** + * provides access to display layout services + */ + private DisplayLayoutService displayLayoutService; } diff --git a/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java b/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java index a90d30f0c9..a9c0b226eb 100644 --- a/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java +++ b/photon/src/main/java/org/marketcetera/ui/service/WindowManagerService.java @@ -6,10 +6,6 @@ import java.util.Properties; import java.util.Set; import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -39,7 +35,6 @@ import com.google.common.collect.Sets; import com.google.common.eventbus.Subscribe; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; @@ -57,7 +52,6 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.stage.Modality; -import javafx.stage.Stage; /* $License$ */ @@ -91,7 +85,6 @@ public void stop() SLF4JLoggerProxy.info(this, "Stopping {}", PlatformServices.getServiceName(getClass())); - // TODO call something on every window to update data or on-close or something like that webMessageService.unregister(this); } /** @@ -102,10 +95,6 @@ public void stop() @Subscribe public void onLogin(LoginEvent inEvent) { - DesktopParameters desktopParameters = new DesktopParameters(mainStage); - desktopParameters.recalculate(); - SessionUser.getCurrent().setAttribute(DesktopParameters.class, - desktopParameters); Properties displayLayout = displayLayoutService.getDisplayLayout(); SLF4JLoggerProxy.debug(this, "Received {}, retrieved display layout: {}", @@ -114,17 +103,6 @@ public void onLogin(LoginEvent inEvent) WindowRegistry windowRegistry = getCurrentUserRegistry(); windowRegistry.restoreLayout(displayLayout); } - /** - * - * - * - * @param inMainStage - */ - public void initializeMainStage(Stage inMainStage) - { - mainStage = inMainStage; - } - private Stage mainStage; /** * Receive new window events. * @@ -136,7 +114,6 @@ public void onNewWindow(NewWindowEvent inEvent) SLF4JLoggerProxy.debug(this, "onWindow: {}", inEvent.getWindowTitle()); - // create the UI window element // create the new window content - initially, the properties will be mostly or completely empty, one would expect // the content view factory will be used to create the new window content ContentViewFactory viewFactory = applicationContext.getBean(inEvent.getViewFactoryType()); @@ -164,19 +141,271 @@ public void onNewWindow(NewWindowEvent inEvent) windowRegistry.addWindow(newWindow); // set the content of the new window newWindow.setRoot(contentView.getNode()); - windowRegistry.addWindowListeners(newWindow); windowRegistry.updateDisplayLayout(); newWindow.show(); + windowRegistry.verifyWindowLocation(newWindow); + } + /** + * Receive logout events. + * + * @param inEvent a LogoutEvent value + */ + @Subscribe + public void onLogout(LogoutEvent inEvent) + { + SLF4JLoggerProxy.debug(this, + "onLogout: {}", + inEvent); + if(SessionUser.getCurrent() == null) { + return; + } + getCurrentUserRegistry().logout(); + SessionUser.getCurrent().setAttribute(WindowRegistry.class, + null); + } + /** + * Receive window cascade events. + * + * @param inEvent a CascadeWindowEvent inEvent + */ + @Subscribe + public void onCascade(CascadeWindowsEvent inEvent) + { + SLF4JLoggerProxy.trace(this, + "onCascade: {}", + inEvent); + getCurrentUserRegistry().cascadeWindows(); + } + /** + * Receive window tile events. + * + * @param inEvent a TileWindowsEvent value + */ + @Subscribe + public void onTile(TileWindowsEvent inEvent) + { + SLF4JLoggerProxy.trace(this, + "onTile: {}", + inEvent); + getCurrentUserRegistry().tileWindows(); + } + /** + * Receive close all windows events. + * + * @param inEvent a CloseWindowsEvent value + */ + @Subscribe + public void onCloseAllWindows(CloseWindowsEvent inEvent) + { + SLF4JLoggerProxy.trace(this, + "onCloseWindows: {}", + inEvent); + getCurrentUserRegistry().closeAllWindows(true); + } + /** + * Determine if the given window is outside the viewable desktop area or not. + * + * @param inWindow a WindowLayout value + * @return a boolean value + */ + private boolean isWindowOutsideDesktop(WindowLayout inWindow) + { + double windowTop = inWindow.getY(); + double windowLeft = inWindow.getX(); + double windowHeight = inWindow.getHeight(); + double windowWidth = inWindow.getWidth(); + double windowBottom = windowTop + windowHeight; + double windowRight = windowLeft + windowWidth; + double workspaceWidth = getWorkspaceWidth(); + double workspaceBottom = getWorkspaceBottom(); + double workspaceLeft = getWorkspaceLeft(); + double workspaceTop = getWorkspaceTop(); + double workspaceRight = workspaceWidth; + boolean outsideDesktop = windowBottom > workspaceBottom || windowLeft < workspaceLeft || windowTop < workspaceTop || windowRight > workspaceRight; + return outsideDesktop; + } + /** + * Get the window height in pixels. + * + * @param inWindow a WindowLayout value + * @return a double value + */ + private double getWindowHeight(WindowLayout inWindow) + { + return inWindow.getHeight(); + } + /** + * Get the window width in pixels. + * + * @param inWindow a WindowLayout value + * @return a double value + */ + private double getWindowWidth(WindowLayout inWindow) + { + return inWindow.getWidth(); + } + /** + * Get the window registry for the current user. + * + * @return a WindowRegistry value + */ + private WindowRegistry getCurrentUserRegistry() + { + WindowRegistry registry = SessionUser.getCurrent().getAttribute(WindowRegistry.class); + if(registry == null) { + registry = new WindowRegistry(); + SessionUser.getCurrent().setAttribute(WindowRegistry.class, + registry); + } + return registry; + } + /** + * Get the main workspace width. + * + * @return a double value + */ + private double getWorkspaceWidth() + { + return PhotonApp.getWorkspace().getLayoutBounds().getWidth(); + } + /** + * Get the main workspace height. + * + * @return a double value + */ + private double getWorkspaceHeight() + { + return PhotonApp.getWorkspace().getLayoutBounds().getHeight(); + } + /** + * Get the main workspace left. + * + * @return a double value + */ + private double getWorkspaceLeft() + { + return 0.0; + } + /** + * Get the main workspace top. + * + * @return a double value + */ + private double getWorkspaceTop() + { + return 0.0; + } + /** + * Get the main workspace right. + * + * @return a double value + */ + private double getWorkspaceRight() + { + return getWorkspaceLeft() + getWorkspaceWidth(); + } + /** + * Get the main workspace bottom. + * + * @return a double value + */ + private double getWorkspaceBottom() + { + return getWorkspaceTop() + getWorkspaceHeight(); + } + /** + * Event used to open a new window on restart. + * + * @author Colin DuPlantis + * @version $Id$ + * @since $Release$ + */ + private class RestartNewWindowEvent + implements NewWindowEvent + { + /* (non-Javadoc) + * @see org.marketcetera.ui.events.NewWindowEvent#getProperties() + */ + @Override + public Properties getProperties() + { + return properties; + } + /* (non-Javadoc) + * @see org.marketcetera.ui.events.NewWindowEvent#getWindowIcon() + */ + @Override + public URL getWindowIcon() + { + if(contentViewFactory instanceof MenuContent) { + return ((MenuContent)contentViewFactory).getMenuIcon(); + } + return null; + } + /* (non-Javadoc) + * @see org.marketcetera.web.events.NewWindowEvent#getWindowTitle() + */ + @Override + public String getWindowTitle() + { + return windowTitle; + } + /* (non-Javadoc) + * @see org.marketcetera.web.events.NewWindowEvent#getViewFactoryType() + */ + @Override + public Class getViewFactoryType() + { + return contentViewFactory.getClass(); + } + /** + * Create a new RestartNewWindowEvent instance. + * + * @param inContentViewFactory a ContentViewFactory value + * @param inProperties a Properties value + */ + private RestartNewWindowEvent(ContentViewFactory inContentViewFactory, + Properties inProperties) + { + contentViewFactory = inContentViewFactory; + properties = inProperties; + windowTitle = properties.getProperty(windowTitleProp); + } + /** + * window properties value + */ + private final Properties properties; + /** + * content view factory value + */ + private final ContentViewFactory contentViewFactory; + /** + * window title value + */ + private final String windowTitle; } + /** + * Holds the information needed for each window being displayed. + * + * @author Colin DuPlantis + * @version $Id$ + * @since $Release$ + */ + @SuppressWarnings("unused") private class WindowLayout { + /** + * Create a new WindowLayout instance. + * + * @param inEvent a NewWindowEvent value + * @param inViewFactory a ContentViewFactory value + */ private WindowLayout(NewWindowEvent inEvent, ContentViewFactory inViewFactory) { newWindowEventProperty.set(inEvent); viewFactoryProperty.set(inViewFactory); properties = inEvent.getProperties(); - setTitle(inEvent.getWindowTitle()); uuidProperty.set(UUID.randomUUID().toString()); setWindowStaticProperties(); windowLayout = new VBox(); @@ -217,10 +446,9 @@ public void onDrag(Node inNode, { setX(inX); setY(inY); -// inWindowLayout.updateProperties(); -// WindowRegistry windowRegistry = getCurrentUserRegistry(); -// windowRegistry.verifyWindowLocation(WindowLayout.this); -// windowRegistry.updateDisplayLayout(); + WindowRegistry windowRegistry = getCurrentUserRegistry(); + windowRegistry.verifyWindowLocation(WindowLayout.this); + windowRegistry.updateDisplayLayout(); } @Override public void onResize(Node inNode, @@ -231,9 +459,9 @@ public void onResize(Node inNode, { setHeight(inH); setWidth(inW); -// WindowRegistry windowRegistry = getCurrentUserRegistry(); -// windowRegistry.verifyWindowLocation(WindowLayout.this); -// windowRegistry.updateDisplayLayout(); + WindowRegistry windowRegistry = getCurrentUserRegistry(); + windowRegistry.verifyWindowLocation(WindowLayout.this); + windowRegistry.updateDisplayLayout(); } }); windowLayout.getStyleClass().add("view"); @@ -268,7 +496,16 @@ public void onResize(Node inNode, } else { setY(Double.parseDouble(rawProperty)); } + rawProperty = StringUtils.trimToNull(properties.getProperty(windowTitleProp)); + if(rawProperty == null) { + setTitle(inEvent.getWindowTitle()); + } else { + setTitle(rawProperty); + } } + /** + * Set up the window listeners for the new window. + */ private void setupWindowListeners() { closeLabel.setOnMouseClicked(event -> { @@ -287,22 +524,18 @@ private void setupWindowListeners() xProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowPosXProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + " updated: " + properties); }); yProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowPosYProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + " updated: " + properties); }); heightProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowHeightProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + "height updated: " + properties); }); widthProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowWidthProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + " width updated: " + properties); }); windowTitleProperty.addListener((observableValue,oldValue,newValue) -> { if(newValue == null) { @@ -311,111 +544,88 @@ private void setupWindowListeners() properties.setProperty(windowTitleProp, getTitle()); } - System.out.println(uuidProperty.get() + " updated: " + properties); }); draggableProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowDraggableProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + " updated: " + properties); }); resizableProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowResizableProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + " updated: " + properties); }); scrollLeftProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowScrollLeftProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + " updated: " + properties); }); scrollTopProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowScrollTopProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + " updated: " + properties); }); viewOrderProperty.addListener((observableValue,oldValue,newValue) -> { properties.setProperty(windowViewOrderProp, String.valueOf(newValue)); - System.out.println(uuidProperty.get() + " updated: " + properties); }); // TODO // properties.setProperty(windowModeProp, // String.valueOf(isMaximized())); } /** - * Update the window object with the stored telemetry. - */ - private void updateWindow() - { - setWidth(Double.parseDouble(properties.getProperty(windowWidthProp))); - setHeight(Double.parseDouble(properties.getProperty(windowHeightProp))); - setModality(properties.getProperty(windowModalProp) == null ? Modality.NONE:Modality.valueOf(properties.getProperty(windowModalProp))); - Boolean isMaximized = Boolean.parseBoolean(properties.getProperty(windowModeProp)); - setMaximized(isMaximized); - setScrollLeft(Double.parseDouble(properties.getProperty(windowScrollLeftProp))); - setScrollTop(Double.parseDouble(properties.getProperty(windowScrollTopProp))); - setDraggable(Boolean.parseBoolean(properties.getProperty(windowDraggableProp))); - setResizable(Boolean.parseBoolean(properties.getProperty(windowResizableProp))); - setTitle(properties.getProperty(windowTitleProp)); - setX(getDoubleValue(properties, - windowPosXProp)); - setY(getDoubleValue(properties, - windowPosYProp)); - setViewOrder(Double.parseDouble(windowViewOrderProp)); - } - /** + * Set the view order value. * - * - * @param inViewOrder + * @param inViewOrder a double value */ private void setViewOrder(double inViewOrder) { viewOrderProperty.set(inViewOrder); Platform.runLater(() -> windowLayout.setViewOrder(inViewOrder)); } + /** + * Set the content view value. + * + * @param inContentView a ContentView value + */ private void setContentView(ContentView inContentView) { contentViewProperty.set(inContentView); } /** - * - * + * Request the focus for this window. */ private void requestFocus() { - windowLayout.requestFocus(); + Platform.runLater(() -> windowLayout.requestFocus()); } /** + * Get the window properties. * - * - * @return + * @return a Properties value */ private Properties getProperties() { return windowProperties; } /** + * Set the root content. * - * - * @param inNode + * @param inNode a Node value */ private void setRoot(Node inNode) { contentLayout.getChildren().add(inNode); } /** + * Set the draggable value for the window. * - * - * @param inDraggable + * @param inDraggable a boolean value */ private void setDraggable(boolean inDraggable) { draggableProperty.set(inDraggable); } /** + * Set the height value for the window. * - * - * @param inHeight + * @param inHeight a double value */ private void setHeight(double inHeight) { @@ -424,9 +634,9 @@ private void setHeight(double inHeight) windowLayout.setMinHeight(inHeight); } /** + * Set the width value for the window. * - * - * @param inWidth + * @param inWidth a double value */ private void setWidth(double inWidth) { @@ -435,162 +645,162 @@ private void setWidth(double inWidth) windowLayout.setMinWidth(inWidth); } /** + * Set the resizable value for the window. * - * - * @param inResizable + * @param inResizable a boolean value */ public void setResizable(boolean inResizable) { resizableProperty.set(inResizable); } /** + * Set the window title property for the window. * - * - * @param inWindowTitle + * @param inWindowTitle a String value */ private void setTitle(String inWindowTitle) { windowTitleProperty.set(inWindowTitle); } /** + * Get the main layout node for the window. * - * - * @return + * @return a Node value */ private Node getMainLayout() { return windowLayout; } /** + * Get the window X position value. * - * - * @return + * @return a double value */ private double getX() { return xProperty.get(); } /** + * Get the window Y position value. * - * - * @return + * @return a double value */ private double getY() { return yProperty.get(); } /** + * Get the window height value. * - * - * @return + * @return a double value */ private double getHeight() { return heightProperty.get(); } /** + * Get the window width value. * - * - * @return + * @return a double value */ private double getWidth() { return widthProperty.get(); } /** + * Get the window maximized value. * - * - * @return + * @return a boolean value */ private boolean isMaximized() { return maximizedProperty.get(); } /** + * Get the window title value. * - * - * @return + * @return a String value */ private String getTitle() { - return windowTitle.getText(); + return windowTitleProperty.get(); } /** + * Get the window modality value. * - * - * @return + * @return a Modality value */ private Modality getModality() { return modalityProperty.get(); } /** + * Get the window draggable value. * - * - * @return + * @return a boolean value */ private boolean isDraggable() { return draggableProperty.get(); } /** + * Get the window resizable value. * - * - * @return + * @return a boolean value */ private boolean isResizable() { return resizableProperty.get(); } /** + * Get the window scroll left value. * - * - * @return + * @return a double value */ private double getScrollLeft() { return scrollLeftProperty.get(); } /** + * Set the window modality value. * - * - * @param inModality + * @param inModality a Modality value */ private void setModality(Modality inModality) { modalityProperty.set(inModality); } /** + * Set the window maximized value. * - * - * @param inMaximized + * @param inMaximized a boolean value */ private void setMaximized(boolean inMaximized) { maximizedProperty.set(inMaximized); } /** + * Set the window scroll left value. * - * - * @param inScrollLeft + * @param inScrollLeft a double value */ private void setScrollLeft(double inScrollLeft) { scrollLeftProperty.set(inScrollLeft); } /** + * Set the window scroll top value. * - * - * @param inScrollTop + * @param inScrollTop a double value */ private void setScrollTop(double inScrollTop) { scrollTopProperty.set(inScrollTop); } /** + * Set the window X position value. * - * - * @param inX + * @param inX a double value */ private void setX(double inX) { @@ -598,9 +808,9 @@ private void setX(double inX) getMainLayout().translateXProperty().set(inX); } /** + * Set the window Y position value. * - * - * @param inY + * @param inY a double value */ private void setY(double inY) { @@ -608,8 +818,7 @@ private void setY(double inY) getMainLayout().translateYProperty().set(inY); } /** - * - * + * Close the window. */ private void close() { @@ -618,26 +827,39 @@ private void close() windowRegistry.removeWindow(this); windowRegistry.updateDisplayLayout(); } - PhotonApp.getWorkspace().getChildren().remove(getMainLayout()); + Platform.runLater(() -> PhotonApp.getWorkspace().getChildren().remove(getMainLayout())); } + /** + * Show the window. + */ private void show() { - System.out.println("COCO: displaying " + uuidProperty + " x: " + getX() + " y: " + getY() + - " width: " + getWidth() + " height: " + getHeight() + - " minWidth: " + windowLayout.getMinWidth() + " minHeight: " + windowLayout.getMinHeight() + - " prefWidth: " + windowLayout.getPrefWidth() + " prefHeight: " + windowLayout.getPrefHeight() + - " layoutWidth: " + windowLayout.getWidth() + " layoutHeight: " + windowLayout.getHeight()); getMainLayout().translateXProperty().set(getX()); getMainLayout().translateYProperty().set(getY()); - windowLayout.setViewOrder(-1); - windowLayout.autosize(); - System.out.println("COCO: displaying " + uuidProperty + " x: " + getX() + " y: " + getY() + - " width: " + getWidth() + " height: " + getHeight() + - " minWidth: " + windowLayout.getMinWidth() + " minHeight: " + windowLayout.getMinHeight() + - " prefWidth: " + windowLayout.getPrefWidth() + " prefHeight: " + windowLayout.getPrefHeight() + - " layoutWidth: " + windowLayout.getWidth() + " layoutHeight: " + windowLayout.getHeight()); - PhotonApp.getWorkspace().getChildren().add(getMainLayout()); - requestFocus(); + setViewOrder(-1); + Platform.runLater(() -> { + windowLayout.autosize(); + PhotonApp.getWorkspace().getChildren().add(getMainLayout()); + requestFocus(); + }); + } + /** + * Get the window uuid value. + * + * @return a String value + */ + private String getUuid() + { + return uuidProperty.get(); + } + /** + * Get a storable implementation of the window properties. + * + * @return a String value + */ + private String getStorableValue() + { + return Util.propertiesToString(properties); } /** * Set the immutable properties of this window to the underlying properties storage. @@ -649,8 +871,17 @@ private void setWindowStaticProperties() properties.setProperty(windowUuidProp, uuidProperty.get()); } + /** + * holds the Content View of the window + */ private final ObjectProperty contentViewProperty = new SimpleObjectProperty<>(); + /** + * holds the initial event of the window + */ private final ObjectProperty newWindowEventProperty = new SimpleObjectProperty<>(); + /** + * holds the window view order value + */ private final DoubleProperty viewOrderProperty = new SimpleDoubleProperty(); /** * cached uuid value @@ -660,494 +891,87 @@ private void setWindowStaticProperties() * properties used to record details about this window */ private final Properties properties; + /** + * holds the window content view factory value + */ private final ObjectProperty viewFactoryProperty = new SimpleObjectProperty<>(); + /** + * holds the window height value + */ private final DoubleProperty heightProperty = new SimpleDoubleProperty(); + /** + * holds the window width value + */ private final DoubleProperty widthProperty = new SimpleDoubleProperty(); + /** + * holds the window X position value + */ private final DoubleProperty xProperty = new SimpleDoubleProperty(); + /** + * holds the window Y position value + */ private final DoubleProperty yProperty = new SimpleDoubleProperty(); + /** + * holds the window maximized property + */ private final BooleanProperty maximizedProperty = new SimpleBooleanProperty(); + /** + * holds the window draggable property + */ private final BooleanProperty draggableProperty = new SimpleBooleanProperty(); + /** + * holds the window resizable property + */ private final BooleanProperty resizableProperty = new SimpleBooleanProperty(); + /** + * holds the window scroll left property + */ private final DoubleProperty scrollLeftProperty = new SimpleDoubleProperty(); + /** + * holds the window scroll top property + */ private final DoubleProperty scrollTopProperty = new SimpleDoubleProperty(); - private final ObjectProperty modalityProperty = new SimpleObjectProperty<>(); - private final Properties windowProperties = new Properties(); - private final StringProperty windowTitleProperty = new SimpleStringProperty(); - private VBox windowLayout; - private HBox windowTitleLayout; - private HBox titleLayout; - private HBox closeButtonLayout; - private VBox contentLayout; - private Label windowTitle; - private Label closeLabel; /** - * - * - * @return + * holds the window modality property */ - private String getUuid() - { - return uuidProperty.get(); - } + private final ObjectProperty modalityProperty = new SimpleObjectProperty<>(); /** - * - * - * @return + * holds all the window's properties */ - private String getStorableValue() - { - System.out.println("Storing: " + properties); - return Util.propertiesToString(properties); - } - } - /** - * Receive logout events. - * - * @param inEvent a LogoutEvent value - */ - @Subscribe - public void onLogout(LogoutEvent inEvent) - { - SLF4JLoggerProxy.debug(this, - "onLogout: {}", - inEvent); - if(SessionUser.getCurrent() == null) { - return; - } - getCurrentUserRegistry().logout(); - SessionUser.getCurrent().setAttribute(WindowRegistry.class, - null); - } - /** - * Receive window cascade events. - * - * @param inEvent a CascadeWindowEvent inEvent - */ - @Subscribe - public void onCascade(CascadeWindowsEvent inEvent) - { - SLF4JLoggerProxy.trace(this, - "onCascade: {}", - inEvent); - getCurrentUserRegistry().cascadeWindows(); - } - /** - * Receive window tile events. - * - * @param inEvent a TileWindowsEvent value - */ - @Subscribe - public void onTile(TileWindowsEvent inEvent) - { - SLF4JLoggerProxy.trace(this, - "onTile: {}", - inEvent); - getCurrentUserRegistry().tileWindows(); - } - /** - * Receive close all windows events. - * - * @param inEvent a CloseWindowsEvent value - */ - @Subscribe - public void onCloseAllWindows(CloseWindowsEvent inEvent) - { - SLF4JLoggerProxy.trace(this, - "onCloseWindows: {}", - inEvent); - getCurrentUserRegistry().closeAllWindows(true); - } - /** - * Determine if the given window is outside the viewable desktop area or not. - * - * @param inWindow a WindowLayout value - * @return a boolean value - */ - private boolean isWindowOutsideDesktop(WindowLayout inWindow) - { - DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); - return (getWindowBottom(inWindow) > params.getBottom()) || (getWindowLeft(inWindow) < params.getLeft()) || (getWindowTop(inWindow) < params.getTop()) || (getWindowRight(inWindow) > params.getRight()); - } - /** - * Get the window top edge coordinate in pixels. - * - * @param inWindow a WindowLayout value - * @return a double value - */ - private double getWindowTop(WindowLayout inWindow) - { - return inWindow.getY(); - } - /** - * Get the window left edge coordinate in pixels. - * - * @param inWindow a WindowLayout value - * @return a double value - */ - private double getWindowLeft(WindowLayout inWindow) - { - return inWindow.getX(); - } - /** - * Get the window bottom edge coordinate in pixels. - * - * @param inWindow a WindowLayout value - * @return a double value - */ - private double getWindowBottom(WindowLayout inWindow) - { - return getWindowTop(inWindow) + getWindowHeight(inWindow); - } - /** - * Get the window right edge coordinate in pixels. - * - * @param inWindow a WindowLayout value - * @return a double value - */ - private double getWindowRight(WindowLayout inWindow) - { - return getWindowLeft(inWindow) + getWindowWidth(inWindow); - } - /** - * Get the window height in pixels. - * - * @param inWindow a WindowLayout value - * @return a double value - */ - private double getWindowHeight(WindowLayout inWindow) - { - return inWindow.getHeight(); - } - /** - * Get the window width in pixels. - * - * @param inWindow a WindowLayout value - * @return a double value - */ - private double getWindowWidth(WindowLayout inWindow) - { - return inWindow.getWidth(); - } - /** - * Get the window registry for the current user. - * - * @return a WindowRegistry value - */ - private WindowRegistry getCurrentUserRegistry() - { - WindowRegistry registry = SessionUser.getCurrent().getAttribute(WindowRegistry.class); - if(registry == null) { - registry = new WindowRegistry(); - SessionUser.getCurrent().setAttribute(WindowRegistry.class, - registry); - registry.scheduleWindowPositionMonitor(); - } - return registry; - } - private static double getDoubleValue(Properties inProperties, - String inPropertyName) - { - return getDoubleValue(inProperties, - inPropertyName, - 0.0); - } - private static double getDoubleValue(Properties inProperties, - String inPropertyName, - double inDefaultValue) - { - String rawValue = StringUtils.trimToNull(inProperties.getProperty(inPropertyName)); - double value = inDefaultValue; - if(rawValue != null) { - try { - value = Double.parseDouble(rawValue); - } catch (NumberFormatException ignored) {} - } - return value; - } - /** - * Event used to open a new window on restart. - * - * @author Colin DuPlantis - * @version $Id$ - * @since $Release$ - */ - private class RestartNewWindowEvent - implements NewWindowEvent - { - /* (non-Javadoc) - * @see org.marketcetera.ui.events.NewWindowEvent#getProperties() + private final Properties windowProperties = new Properties(); + /** + * holds the window title property */ - @Override - public Properties getProperties() - { - return properties; - } - /* (non-Javadoc) - * @see org.marketcetera.ui.events.NewWindowEvent#getWindowIcon() + private final StringProperty windowTitleProperty = new SimpleStringProperty(); + /** + * holds the overall main window layout */ - @Override - public URL getWindowIcon() - { - if(contentViewFactory instanceof MenuContent) { - return ((MenuContent)contentViewFactory).getMenuIcon(); - } - return null; - } - /* (non-Javadoc) - * @see org.marketcetera.web.events.NewWindowEvent#getWindowTitle() + private VBox windowLayout; + /** + * holds the layout for the entire title bar */ - @Override - public String getWindowTitle() - { - return windowTitle; - } - /* (non-Javadoc) - * @see org.marketcetera.web.events.NewWindowEvent#getViewFactoryType() + private HBox windowTitleLayout; + /** + * holds the layout for the window title */ - @Override - public Class getViewFactoryType() - { - return contentViewFactory.getClass(); - } + private HBox titleLayout; /** - * Create a new RestartNewWindowEvent instance. - * - * @param inContentViewFactory a ContentViewFactory value - * @param inProperties a Properties value + * holds the layout for the close button */ - private RestartNewWindowEvent(ContentViewFactory inContentViewFactory, - Properties inProperties) - { - contentViewFactory = inContentViewFactory; - properties = inProperties; - windowTitle = properties.getProperty(windowTitleProp); - } + private HBox closeButtonLayout; /** - * window properties value + * holds the layout for the window content */ - private final Properties properties; + private VBox contentLayout; /** - * content view factory value + * holds the window title node */ - private final ContentViewFactory contentViewFactory; + private Label windowTitle; /** - * window title value + * holds the window close widget */ - private final String windowTitle; + private Label closeLabel; } -// /** -// * Holds meta-data for windows. -// * -// * @author Colin DuPlantis -// * @version $Id$ -// * @since $Release$ -// */ -// private class WindowMetaData -// { -// /* (non-Javadoc) -// * @see java.lang.Object#toString() -// */ -// @Override -// public String toString() -// { -// return properties.toString(); -// } -// /** -// * Create a new WindowMetaData instance. -// * -// *

This constructor is invoked for a new window. -// * -// * @param inEvent a NewWindowEvent value -// * @param inWindow a WindowLayout value -// * @param inContentViewFactory a ContentViewFactory value -// */ -// private WindowMetaData(NewWindowEvent inEvent, -// WindowLayout inWindow, -// ContentViewFactory inContentViewFactory) -// { -// properties = inEvent.getProperties(); -// window = inWindow; -// setWindowStaticProperties(inContentViewFactory, -// UUID.randomUUID().toString()); -// updateProperties(); -// } -// /** -// * Create a new WindowMetaData instance. -// * -// *

This constructor is invoked to recreate a previously-created window. -// * -// * @param inProperties a Properties value -// * @param inWindow a WindowLayout value -// */ -// private WindowMetaData(Properties inProperties, -// WindowLayout inWindow) -// { -// // TODO need to do a permissions re-check, perhaps -// window = inWindow; -// properties = inProperties; -// try { -// ContentViewFactory contentViewFactory = (ContentViewFactory)applicationContext.getBean(Class.forName(inProperties.getProperty(windowContentViewFactoryProp))); -// ContentView contentView = contentViewFactory.create(window.getMainLayout(), -// new RestartNewWindowEvent(contentViewFactory, -// properties.getProperty(windowTitleProp)), -// properties); -// inWindow.contentViewProperty.set(contentView); -// window.setRoot(contentView.getNode()); -// } catch (ClassNotFoundException e) { -// throw new RuntimeException(e); -// } -// // update window from properties, effectively restoring it to its previous state -// updateWindow(); -// } -// /** -// * Get the storable value for this window. -// * -// * @return a String value -// */ -// private String getStorableValue() -// { -// return Util.propertiesToString(properties); -// } -// /** -// * Get the properties value. -// * -// * @return a Properties value -// */ -// private Properties getProperties() -// { -// return properties; -// } -// /** -// * Get the window value. -// * -// * @return a WindowLayout value -// */ -// private WindowLayout getWindow() -// { -// return window; -// } -// /** -// * Update the window telemetry from the underlying window object. -// */ -// private void updateProperties() -// { -// properties.setProperty(windowPosXProp, -// String.valueOf(window.getX())); -// properties.setProperty(windowPosYProp, -// String.valueOf(window.getX())); -// properties.setProperty(windowHeightProp, -// String.valueOf(window.getHeight())); -// properties.setProperty(windowWidthProp, -// String.valueOf(window.getWidth())); -// properties.setProperty(windowModeProp, -// String.valueOf(window.isMaximized())); -// if(window.getTitle() != null) { -// properties.setProperty(windowTitleProp, -// window.getTitle()); -// } -// properties.setProperty(windowDraggableProp, -// String.valueOf(window.isDraggable())); -// properties.setProperty(windowResizableProp, -// String.valueOf(window.isResizable())); -// properties.setProperty(windowScrollLeftProp, -// String.valueOf(window.getScrollLeft())); -// properties.setProperty(windowScrollTopProp, -// String.valueOf(window.getScrollLeft())); -// properties.setProperty(windowFocusProp, -// String.valueOf(hasFocus())); -// } -// /** -// * Update the window object with the stored telemetry. -// */ -// private void updateWindow() -// { -// window.setWidth(Double.parseDouble(properties.getProperty(windowWidthProp))); -// window.setHeight(Double.parseDouble(properties.getProperty(windowHeightProp))); -// window.setModality(properties.getProperty(windowModalProp) == null ? Modality.NONE:Modality.valueOf(properties.getProperty(windowModalProp))); -// Boolean isMaximized = Boolean.parseBoolean(properties.getProperty(windowModeProp)); -// window.setMaximized(isMaximized); -// window.setScrollLeft(Double.parseDouble(properties.getProperty(windowScrollLeftProp))); -// window.setScrollTop(Double.parseDouble(properties.getProperty(windowScrollTopProp))); -// window.setDraggable(Boolean.parseBoolean(properties.getProperty(windowDraggableProp))); -// window.setResizable(Boolean.parseBoolean(properties.getProperty(windowResizableProp))); -// window.setTitle(properties.getProperty(windowTitleProp)); -// window.setX(getDoubleValue(properties, -// windowPosXProp)); -// window.setY(getDoubleValue(properties, -// windowPosYProp)); -// setHasFocus(Boolean.parseBoolean(properties.getProperty(windowFocusProp))); -// if(hasFocus) { -// window.requestFocus(); -// } -// } -// /** -// * Set the immutable properties of this window to the underlying properties storage. -// * -// * @param inContentViewFactory a ContentViewFactory value -// * @param inUuid a Stringvalue -// */ -// private void setWindowStaticProperties(ContentViewFactory inContentViewFactory, -// String inUuid) -// { -// properties.setProperty(windowContentViewFactoryProp, -// inContentViewFactory.getClass().getCanonicalName()); -// properties.setProperty(windowUuidProp, -// inUuid); -// } -// /** -// * Close this window and remove it from active use. -// */ -// private void close() -// { -// getWindow().close(); -// } -// /** -// * Get the window uuid value. -// * -// * @return a String value -// */ -// private String getUuid() -// { -// if(uuid == null) { -// uuid = properties.getProperty(windowUuidProp); -// } -// return uuid; -// } -// /** -// * Get the hasFocus value. -// * -// * @return a boolean value -// */ -// private boolean hasFocus() -// { -// return hasFocus; -// } -// /** -// * Sets the hasFocus value. -// * -// * @param inHasFocus a boolean value -// */ -// private void setHasFocus(boolean inHasFocus) -// { -// hasFocus = inHasFocus; -// } -// /** -// * indicates if this window has focus or not -// */ -// private transient boolean hasFocus; -// /** -// * cached uuid value -// */ -// private transient String uuid; -// /** -// * properties used to record details about this window -// */ -// private final Properties properties; -// /** -// * underlying UI element -// */ -// private final WindowLayout window; -// } /** * Provides a registry of all windows. * @@ -1190,87 +1014,69 @@ private void closeAllWindows(boolean inUpdateDisplay) */ private void cascadeWindows() { - synchronized(windowPositionExaminerThreadPool) { - cancelWindowPositionMonitor(); - } - try { - synchronized(activeWindows) { - double xPos = desktopCascadeWindowOffset; - double yPos = desktopCascadeWindowOffset; - DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); - double maxX = params.getRight(); - double maxY = params.getBottom(); - for(WindowLayout activeWindow : activeWindows) { - double windowWidth = activeWindow.getWidth(); - double windowHeight = activeWindow.getHeight(); - double proposedX = xPos; - if(proposedX + windowWidth > maxX) { - proposedX = desktopCascadeWindowOffset; - } - double proposedY = yPos; - if(proposedY + windowHeight > maxY) { - proposedY = desktopCascadeWindowOffset; - } - activeWindow.setX(proposedX); - activeWindow.setY(proposedY); - activeWindow.requestFocus(); - xPos += desktopCascadeWindowOffset; - yPos += desktopCascadeWindowOffset; -// activeWindow.updateProperties(); + synchronized(activeWindows) { + double xPos = desktopCascadeWindowOffset; + double yPos = desktopCascadeWindowOffset; + double maxX = getWorkspaceRight(); + double maxY = getWorkspaceBottom(); + for(WindowLayout activeWindow : activeWindows) { + double windowWidth = activeWindow.getWidth(); + double windowHeight = activeWindow.getHeight(); + double proposedX = xPos; + if(proposedX + windowWidth > maxX) { + proposedX = desktopCascadeWindowOffset; } + double proposedY = yPos; + if(proposedY + windowHeight > maxY) { + proposedY = desktopCascadeWindowOffset; + } + activeWindow.setX(proposedX); + activeWindow.setY(proposedY); + activeWindow.requestFocus(); + xPos += desktopCascadeWindowOffset; + yPos += desktopCascadeWindowOffset; } - updateDisplayLayout(); - } finally { - scheduleWindowPositionMonitor(); } + updateDisplayLayout(); } /** * Rearrange the windows in this registry to a tiled pattern. */ private void tileWindows() { - synchronized(windowPositionExaminerThreadPool) { - cancelWindowPositionMonitor(); - } - try { - synchronized(activeWindows) { - DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); - int numWindows = activeWindows.size(); - if(numWindows == 0) { - return; - } - int numCols = (int)Math.floor(Math.sqrt(numWindows)); - int numRows = (int)Math.floor(numWindows / numCols); - if(!isPerfectSquare(numWindows)) { - numCols += 1; - } - double windowWidth = Math.floorDiv(((Double)params.getRight()).intValue(), - numCols); - double windowHeight = Math.floorDiv(((Double)(params.getBottom()-params.getTop())).intValue(), - numRows); - int colNum = 0; - int rowNum = 0; - double posX = params.getLeft(); - double posY = params.getTop(); - for(WindowLayout activeWindow : activeWindows) { - double suggestedX = posX + (colNum * windowWidth); - double suggestedY = posY + (rowNum * windowHeight); - activeWindow.setWidth(windowWidth); - activeWindow.setHeight(windowHeight); - activeWindow.setX(suggestedX); - activeWindow.setY(suggestedY); - colNum += 1; - if(colNum == numCols) { - colNum = 0; - rowNum += 1; - } -// activeWindow.updateProperties(); + synchronized(activeWindows) { + int numWindows = activeWindows.size(); + if(numWindows == 0) { + return; + } + int numCols = (int)Math.floor(Math.sqrt(numWindows)); + int numRows = (int)Math.floor(numWindows / numCols); + if(!isPerfectSquare(numWindows)) { + numCols += 1; + } + double windowWidth = Math.floorDiv(((Double)getWorkspaceRight()).intValue(), + numCols); + double windowHeight = Math.floorDiv(((Double)(getWorkspaceBottom()-getWorkspaceTop())).intValue(), + numRows); + int colNum = 0; + int rowNum = 0; + double posX = getWorkspaceLeft(); + double posY = getWorkspaceTop(); + for(WindowLayout activeWindow : activeWindows) { + double suggestedX = posX + (colNum * windowWidth); + double suggestedY = posY + (rowNum * windowHeight); + activeWindow.setWidth(windowWidth); + activeWindow.setHeight(windowHeight); + activeWindow.setX(suggestedX); + activeWindow.setY(suggestedY); + colNum += 1; + if(colNum == numCols) { + colNum = 0; + rowNum += 1; } } - updateDisplayLayout(); - } finally { - scheduleWindowPositionMonitor(); } + updateDisplayLayout(); /* If you can relax the requirement that all windows have a given "aspect ratio" then the problem becomes very simple. Suppose you have N "tiles" to arrange on a single screen, then these can be arranged in columns where the number of columns, NumCols is the square root of N rounded up when N is not a perfect square. All columns of tiles are of equal width. @@ -1318,13 +1124,13 @@ private void restoreLayout(Properties inDisplayLayout) newWindow.contentViewProperty.set(contentView); newWindow.setRoot(contentView.getNode()); addWindow(newWindow); - addWindowListeners(newWindow); newWindow.show(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } } + verifyAllWindowPositions(); } /** * Update the display layout for the windows in the given window registry. @@ -1344,124 +1150,6 @@ private void updateDisplayLayout() ExceptionUtils.getRootCauseMessage(e)); } } - /** - * Add the necessary window listeners to the given window meta data. - * - * @param inWindowWrapper a WindowLayout value - */ - private void addWindowListeners(WindowLayout inWindowWrapper) - { - WindowRegistry windowRegistry = this; - WindowLayout newWindow = inWindowWrapper; -// newWindow.addEventHandler(MouseEvent.MOUSE_CLICKED, -// new EventHandler() { -// @Override -// public void handle(MouseEvent inEvent) -// { -// SLF4JLoggerProxy.trace(WindowManagerService.this, -// "Click: {}", -// inEvent); -// verifyWindowLocation(newWindow); -// inWindowWrapper.updateProperties(); -// updateDisplayLayout(); -// }} -// ); -// newWindow.setOnShown(new EventHandler() { -// @Override -// public void handle(WindowEvent inEvent) -// { -// SLF4JLoggerProxy.trace(WindowManagerService.this, -// "Shown: {}", -// inEvent); -// verifyWindowLocation(newWindow); -// inWindowWrapper.updateProperties(); -// updateDisplayLayout(); -// }} -// ); -//// newWindow.addWindowModeChangeListener(inEvent -> { -//// SLF4JLoggerProxy.trace(WindowManagerService.this, -//// "Mode change: {}", -//// inEvent); -//// // TODO might want to do this, might not. a maximized window currently tromps all over the menu bar -////// verifyWindowLocation(newWindow); -//// inWindowWrapper.updateProperties(); -//// updateDisplayLayout(); -//// }); -// newWindow.widthProperty().addListener(new ChangeListener() { -// @Override -// public void changed(ObservableValue inObservable, -// Number inOldValue, -// Number inNewValue) -// { -// newWindowResize("width", -// inWindowWrapper); -// }} -// ); -// newWindow.heightProperty().addListener(new ChangeListener() { -// @Override -// public void changed(ObservableValue inObservable, -// Number inOldValue, -// Number inNewValue) -// { -// newWindowResize("height", -// inWindowWrapper); -// }} -// ); -// newWindow.addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST,new EventHandler() { -// @Override -// public void handle(WindowEvent inEvent) -// { -// SLF4JLoggerProxy.trace(WindowManagerService.this, -// "Close: {}", -// inEvent); -// // this listener will be fired during log out, but, we don't want to update the display layout in that case -// if(!windowRegistry.isLoggingOut()) { -// windowRegistry.removeWindow(inWindowWrapper); -// updateDisplayLayout(); -// } -// }} -// ); -//// newWindow.addBlurListener(inEvent -> { -//// SLF4JLoggerProxy.trace(WindowManagerService.this, -//// "Blur: {}", -//// inEvent); -//// verifyWindowLocation(newWindow); -//// inWindowWrapper.setHasFocus(false); -//// inWindowWrapper.updateProperties(); -//// updateDisplayLayout(); -//// }); -//// newWindow.addFocusListener(inEvent -> { -//// SLF4JLoggerProxy.trace(WindowManagerService.this, -//// "Focus: {}", -//// inEvent); -//// verifyWindowLocation(newWindow); -//// inWindowWrapper.setHasFocus(true); -//// inWindowWrapper.updateProperties(); -//// updateDisplayLayout(); -//// }); -// newWindow.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED,new EventHandler() { -// @Override -// public void handle(ContextMenuEvent inEvent) -// { -// SLF4JLoggerProxy.trace(WindowManagerService.this, -// "Context click: {}", -// inEvent); -// verifyWindowLocation(newWindow); -// inWindowWrapper.updateProperties(); -// updateDisplayLayout(); -// }} -// ); - } - private void newWindowResize(String inDimension, - WindowLayout inWindowLayout) - { - SLF4JLoggerProxy.trace(WindowManagerService.this, - "Verify: {}", - inDimension); - verifyWindowLocation(inWindowLayout); -// inWindowLayout.updateProperties(); - updateDisplayLayout(); - } /** * Verify that the given window is within the acceptable bounds of the desktop viewable area. * @@ -1491,50 +1179,54 @@ private void verifyWindowLocation(WindowLayout inWindow) */ private void returnWindowToDesktop(WindowLayout inWindow) { -// System.out.println("Entering returnWindowToDesktop"); -// int pad = desktopViewableAreaPad; -// DesktopParameters params = SessionUser.getCurrent().getAttribute(DesktopParameters.class); -// // the order here is important: first, resize the window, if necessary -// double maxWidth = params.getRight()-params.getLeft(); -// double windowWidth = getWindowWidth(inWindow); -// if(windowWidth > maxWidth) { -// inWindow.setWidth(maxWidth - (pad*2)); -// } -// if(windowWidth <= 10) { -// windowWidth = 100; -// inWindow.setWidth(windowWidth); -// } -// double maxHeight = params.getBottom() - params.getTop(); -// double windowHeight = getWindowHeight(inWindow); -// if(windowHeight > maxHeight) { -// inWindow.setHeight(maxHeight - (pad*2)); -// } -// // window is now no larger than desktop -// // check bottom -// double windowBottom = getWindowBottom(inWindow); -// if(windowBottom > params.getBottom()) { -// double newWindowTop = params.getBottom() - getWindowHeight(inWindow) - pad; -// inWindow.setY(newWindowTop); -// } -// // check top -// double windowTop = getWindowTop(inWindow); -// if(windowTop < params.getTop()+pad) { -// double newWindowTop = params.getTop() + pad; -// inWindow.setY(newWindowTop); -// } -// // window is now within the desktop Y range -// // check left -// double windowLeft = getWindowLeft(inWindow); -// if(windowLeft < params.getLeft()) { -// double newWindowLeft = params.getLeft() + pad; -// inWindow.setX(newWindowLeft); -// } -// // check right -// double windowRight = getWindowRight(inWindow); -// if(windowRight > params.getRight()) { -// double newWindowLeft = params.getRight() - getWindowWidth(inWindow) - pad; -// inWindow.setX(newWindowLeft); -// } + double windowTop = inWindow.getY(); + double windowLeft = inWindow.getX(); + double windowHeight = inWindow.getHeight(); + double windowWidth = inWindow.getWidth(); + double windowBottom = windowTop + windowHeight; + double windowRight = windowLeft + windowWidth; + double workspaceWidth = getWorkspaceWidth(); + double workspaceHeight = getWorkspaceHeight(); + double workspaceBottom = workspaceHeight; + double workspaceLeft = getWorkspaceLeft(); + double workspaceTop = getWorkspaceTop(); + double workspaceRight = workspaceWidth; + int pad = desktopViewableAreaPad; + // the order here is important: first, resize the window, if necessary + double maxWidth = workspaceRight; + if(windowWidth > maxWidth) { + inWindow.setWidth(maxWidth - (pad*2)); + } + if(windowWidth <= 10) { + windowWidth = 100; + inWindow.setWidth(windowWidth); + } + double maxHeight = workspaceBottom; + if(windowHeight > maxHeight) { + inWindow.setHeight(maxHeight - (pad*2)); + } + // window is now no larger than desktop + // check bottom + if(windowBottom > workspaceBottom) { + double newWindowTop = workspaceBottom - getWindowHeight(inWindow) - pad; + inWindow.setY(newWindowTop); + } + // check top + if(windowTop < workspaceTop+pad) { + double newWindowTop = workspaceTop + pad; + inWindow.setY(newWindowTop); + } + // window is now within the desktop Y range + // check left + if(windowLeft < workspaceLeft) { + double newWindowLeft = workspaceLeft + pad; + inWindow.setX(newWindowLeft); + } + // check right + if(windowRight > workspaceRight) { + double newWindowLeft = workspaceRight - getWindowWidth(inWindow) - pad; + inWindow.setX(newWindowLeft); + } } /** * Remove the given window from this registry. @@ -1562,10 +1254,6 @@ private void logout() */ private void terminateRegistry() { - synchronized(windowPositionExaminerThreadPool) { - cancelWindowPositionMonitor(); - windowPositionExaminerThreadPool.shutdownNow(); - } closeAllWindows(false); } /** @@ -1587,48 +1275,11 @@ public void run() SLF4JLoggerProxy.warn(WindowManagerService.this, ExceptionUtils.getRootCauseMessage(e)); } -// if(windowMetaData.hasFocus()) { // && windowMetaData.getWindow().isAttached()) { -// windowMetaData.getWindow().focus(); -// } } }} ); } } - /** - * Cancel the current window position monitor job, if necessary. - */ - private void cancelWindowPositionMonitor() - { - synchronized(windowPositionExaminerThreadPool) { - if(windowPositionMonitorToken != null) { - try { - windowPositionMonitorToken.cancel(true); - } catch (Exception ignored) {} - windowPositionMonitorToken = null; - } - } - } - /** - * Schedule the window position monitor job. - */ - private void scheduleWindowPositionMonitor() - { - synchronized(windowPositionExaminerThreadPool) { - cancelWindowPositionMonitor(); - windowPositionMonitorToken = windowPositionExaminerThreadPool.scheduleAtFixedRate(new Runnable() { - @Override - public void run() - { - try { - verifyAllWindowPositions(); - } catch (Exception e) { - SLF4JLoggerProxy.warn(WindowManagerService.this, - ExceptionUtils.getRootCauseMessage(e)); - } - }},desktopWindowPositionMonitorInterval,desktopWindowPositionMonitorInterval,TimeUnit.MILLISECONDS); - } - } /** * Get the isLoggingOut value. * @@ -1664,14 +1315,6 @@ private Properties getDisplayLayout() * holds all active windows */ private final Set activeWindows = Sets.newHashSet(); - /** - * holds the token for the window position monitor job, if any - */ - private Future windowPositionMonitorToken; - /** - * checks window position on a periodic basis - */ - private final ScheduledExecutorService windowPositionExaminerThreadPool = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat(SessionUser.getCurrent().getUsername() + "-WindowPositionExaminer").build()); } /** * base key for {@see UserAttributeType} display layout properties @@ -1705,14 +1348,14 @@ private Properties getDisplayLayout() * window width key name */ private static final String windowWidthProp = propId + "_width"; - /** - * window mode key name - */ - private static final String windowModeProp = propId + "_mode"; - /** - * window is modal key name - */ - private static final String windowModalProp = propId + "_modal"; +// /** +// * window mode key name +// */ +// private static final String windowModeProp = propId + "_mode"; +// /** +// * window is modal key name +// */ +// private static final String windowModalProp = propId + "_modal"; /** * window view order key name */ @@ -1751,7 +1394,7 @@ private Properties getDisplayLayout() /** * desktop viewable area pad value */ - @Value("${metc.desktop.viewable.area.pad:50}") + @Value("${metc.desktop.viewable.area.pad:2}") private int desktopViewableAreaPad; /** * desktop cascade window offset value