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/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 88% rename from photon/src/main/java/org/marketcetera/ui/App.java rename to photon/src/main/java/org/marketcetera/ui/PhotonApp.java index 65f00d2336..1792f5b3ee 100644 --- a/photon/src/main/java/org/marketcetera/ui/App.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; @@ -32,22 +33,22 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; 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) @@ -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,10 +75,9 @@ public void start(Stage inPrimaryStage) SLF4JLoggerProxy.info(this, "Starting main stage"); primaryStage = inPrimaryStage; - windowManagerService.initializeMainStage(primaryStage); root = new VBox(); menuLayout = new VBox(); - workspace = new VBox(); + workspace = new Pane(); workspace.setId(getClass().getCanonicalName() + ".workspace"); workspace.setPrefWidth(1024); workspace.setPrefHeight(768); @@ -87,8 +87,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 +125,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 +221,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 +245,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; } @@ -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,15 +302,18 @@ 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; private HBox footer; private Label clockLabel; private Label userLabel; - private static VBox workspace; + private static Pane workspace; 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/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/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/fix/view/FixSessionView.java b/photon/src/main/java/org/marketcetera/ui/fix/view/FixSessionView.java index 28cd35452a..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 @@ -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; @@ -86,7 +85,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; -import javafx.stage.WindowEvent; /* $License$ */ @@ -104,12 +102,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) @@ -124,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); @@ -171,19 +169,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 +451,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 +1697,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..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 @@ -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,8 +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,18 +79,18 @@ 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) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { SLF4JLoggerProxy.trace(this, "{} {} stop", @@ -173,7 +171,6 @@ public void start() event.consume(); } }); - scene = new Scene(rootLayout); if(marketDataInstrument != null) { doMarketDataRequest(); } @@ -181,11 +178,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 +426,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/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 998f6dc6fd..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 @@ -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,18 +77,18 @@ 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) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { SLF4JLoggerProxy.trace(this, "{} {} stop", @@ -139,28 +138,25 @@ public void start() event.consume(); } }); - scene = new Scene(rootLayout); } @PreDestroy public void stop() { - System.out.println("COCO: stopping market data list view"); } /** * 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() { @@ -168,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() { @@ -458,7 +453,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/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/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..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,19 +6,18 @@ 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; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.marketcetera.core.Pair; 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.PhotonApp; import org.marketcetera.ui.events.CascadeWindowsEvent; import org.marketcetera.ui.events.CloseWindowsEvent; import org.marketcetera.ui.events.LoginEvent; @@ -36,19 +35,23 @@ 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.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$ */ @@ -82,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); } /** @@ -93,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: {}", @@ -105,11 +103,6 @@ public void onLogin(LoginEvent inEvent) WindowRegistry windowRegistry = getCurrentUserRegistry(); windowRegistry.restoreLayout(displayLayout); } - public void initializeMainStage(Stage inMainStage) - { - mainStage = inMainStage; - } - private Stage mainStage; /** * Receive new window events. * @@ -121,37 +114,23 @@ public void onNewWindow(NewWindowEvent inEvent) SLF4JLoggerProxy.debug(this, "onWindow: {}", inEvent.getWindowTitle()); - // create the UI window element - final Stage newWindow = new Stage(); - newWindow.initOwner(App.getPrimaryStage()); - 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, + 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()); + newWindow.getProperties()); + newWindow.setContentView(contentView); // 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()); @@ -159,18 +138,12 @@ 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.setScene(rootScene); - windowRegistry.addWindowListeners(newWindowWrapper); + newWindow.setRoot(contentView.getNode()); windowRegistry.updateDisplayLayout(); - // TODO pretty sure this isn't right - newWindow.getProperties().put(WindowManagerService.windowUuidProp, - inEvent.getWindowStyleId()); - newWindow.sizeToScene(); newWindow.show(); - newWindow.requestFocus(); -// newWindow.setOnCloseRequest(null); + windowRegistry.verifyWindowLocation(newWindow); } /** * Receive logout events. @@ -232,109 +205,113 @@ 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()); + 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 top edge coordinate in pixels. + * Get the window height in pixels. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a double value */ - private double getWindowTop(Window inWindow) + private double getWindowHeight(WindowLayout inWindow) { - return inWindow.getY(); + return inWindow.getHeight(); } /** - * Get the window left edge coordinate in pixels. + * Get the window width in pixels. * - * @param inWindow a Window value + * @param inWindow a WindowLayout value * @return a double value */ - private double getWindowLeft(Window inWindow) + private double getWindowWidth(WindowLayout inWindow) { - return inWindow.getX(); + return inWindow.getWidth(); } /** - * Get the window bottom edge coordinate in pixels. + * Get the window registry for the current user. * - * @param inWindow a Window value - * @return a double value + * @return a WindowRegistry value */ - private double getWindowBottom(Window inWindow) + private WindowRegistry getCurrentUserRegistry() { - return getWindowTop(inWindow) + getWindowHeight(inWindow); + WindowRegistry registry = SessionUser.getCurrent().getAttribute(WindowRegistry.class); + if(registry == null) { + registry = new WindowRegistry(); + SessionUser.getCurrent().setAttribute(WindowRegistry.class, + registry); + } + return registry; } /** - * Get the window right edge coordinate in pixels. + * Get the main workspace width. * - * @param inWindow a Window value * @return a double value */ - private double getWindowRight(Window inWindow) + private double getWorkspaceWidth() { - return getWindowLeft(inWindow) + getWindowWidth(inWindow); + return PhotonApp.getWorkspace().getLayoutBounds().getWidth(); } /** - * Get the window height in pixels. + * Get the main workspace height. * - * @param inWindow a Window value * @return a double value */ - private double getWindowHeight(Window inWindow) + private double getWorkspaceHeight() { - return inWindow.getHeight(); + return PhotonApp.getWorkspace().getLayoutBounds().getHeight(); } /** - * Get the window width in pixels. + * Get the main workspace left. * - * @param inWindow a Window value * @return a double value */ - private double getWindowWidth(Window inWindow) + private double getWorkspaceLeft() { - return inWindow.getWidth(); + return 0.0; } /** - * Get the window registry for the current user. + * Get the main workspace top. * - * @return a WindowRegistry value + * @return a double value */ - private WindowRegistry getCurrentUserRegistry() + private double getWorkspaceTop() { - WindowRegistry registry = SessionUser.getCurrent().getAttribute(WindowRegistry.class); - if(registry == null) { - registry = new WindowRegistry(); - SessionUser.getCurrent().setAttribute(WindowRegistry.class, - registry); - registry.scheduleWindowPositionMonitor(); - } - return registry; + return 0.0; } - private static double getDoubleValue(Properties inProperties, - String inPropertyName) + /** + * Get the main workspace right. + * + * @return a double value + */ + private double getWorkspaceRight() { - return getDoubleValue(inProperties, - inPropertyName, - 0.0); + return getWorkspaceLeft() + getWorkspaceWidth(); } - private static double getDoubleValue(Properties inProperties, - String inPropertyName, - double inDefaultValue) + /** + * Get the main workspace bottom. + * + * @return a double value + */ + private double getWorkspaceBottom() { - String rawValue = StringUtils.trimToNull(inProperties.getProperty(inPropertyName)); - double value = inDefaultValue; - if(rawValue != null) { - try { - value = Double.parseDouble(rawValue); - } catch (NumberFormatException ignored) {} - } - return value; + return getWorkspaceTop() + getWorkspaceHeight(); } /** * Event used to open a new window on restart. @@ -346,6 +323,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() */ @@ -377,14 +362,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 */ @@ -395,188 +385,463 @@ private RestartNewWindowEvent(ContentViewFactory inContentViewFactory, private final String windowTitle; } /** - * Holds meta-data for windows. + * Holds the information needed for each window being displayed. * * @author Colin DuPlantis * @version $Id$ * @since $Release$ */ - private class WindowMetaData + @SuppressWarnings("unused") + private class WindowLayout { - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - return properties.toString(); - } /** - * Create a new WindowMetaData instance. + * Create a new WindowLayout instance. * - *

This constructor is invoked for a new window. - * * @param inEvent a NewWindowEvent value - * @param inWindow a Stage value - * @param inContentViewFactory a ContentViewFactory value + * @param inViewFactory a ContentViewFactory value */ - private WindowMetaData(NewWindowEvent inEvent, - Stage inWindow, - ContentViewFactory inContentViewFactory) + private WindowLayout(NewWindowEvent inEvent, + ContentViewFactory inViewFactory) { + newWindowEventProperty.set(inEvent); + viewFactoryProperty.set(inViewFactory); properties = inEvent.getProperties(); - window = inWindow; - setWindowStaticProperties(inContentViewFactory, - UUID.randomUUID().toString()); - updateProperties(); + uuidProperty.set(UUID.randomUUID().toString()); + setWindowStaticProperties(); + 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"); + 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); + DragResizeMod.makeResizable(windowLayout, + new OnDragResizeEventListener() { + @Override + public void onDrag(Node inNode, + double inX, + double inY, + double inH, + double inW) + { + setX(inX); + setY(inY); + WindowRegistry windowRegistry = getCurrentUserRegistry(); + windowRegistry.verifyWindowLocation(WindowLayout.this); + windowRegistry.updateDisplayLayout(); + } + @Override + public void onResize(Node inNode, + double inX, + double inY, + double inH, + double 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"); +// 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)); + } + 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 -> { + contentViewProperty.get().onClose(); + close(); + }); + windowLayout.setOnMouseClicked(event -> { + WindowRegistry windowRegistry = getCurrentUserRegistry(); + synchronized(windowRegistry.activeWindows) { + for(WindowLayout windowLayout : windowRegistry.activeWindows) { + windowLayout.getMainLayout().viewOrderProperty().set(0.0); + } + } + windowLayout.viewOrderProperty().set(-1.0); + }); + xProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowPosXProp, + String.valueOf(newValue)); + }); + yProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowPosYProp, + String.valueOf(newValue)); + }); + heightProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowHeightProp, + String.valueOf(newValue)); + }); + widthProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowWidthProp, + String.valueOf(newValue)); + }); + windowTitleProperty.addListener((observableValue,oldValue,newValue) -> { + if(newValue == null) { + properties.remove(windowTitleProp); + } else { + properties.setProperty(windowTitleProp, + getTitle()); + } + }); + draggableProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowDraggableProp, + String.valueOf(newValue)); + }); + resizableProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowResizableProp, + String.valueOf(newValue)); + }); + scrollLeftProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowScrollLeftProp, + String.valueOf(newValue)); + }); + scrollTopProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowScrollTopProp, + String.valueOf(newValue)); + }); + viewOrderProperty.addListener((observableValue,oldValue,newValue) -> { + properties.setProperty(windowViewOrderProp, + String.valueOf(newValue)); + }); + // TODO +// properties.setProperty(windowModeProp, +// String.valueOf(isMaximized())); } /** - * Create a new WindowMetaData instance. + * Set the view order value. * - *

This constructor is invoked to recreate a previously-created window. - * - * @param inProperties a Properties value - * @param inWindow a Stage value + * @param inViewOrder a double value */ - private WindowMetaData(Properties inProperties, - Stage inWindow) + private void setViewOrder(double inViewOrder) { - // 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, - 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); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - // update window from properties, effectively restoring it to its previous state - updateWindow(); + viewOrderProperty.set(inViewOrder); + Platform.runLater(() -> windowLayout.setViewOrder(inViewOrder)); } /** - * Get the storable value for this window. + * Set the content view value. * - * @return a String value + * @param inContentView a ContentView value */ - private String getStorableValue() + private void setContentView(ContentView inContentView) { - return Util.propertiesToString(properties); + contentViewProperty.set(inContentView); } /** - * Get the properties value. + * Request the focus for this window. + */ + private void requestFocus() + { + Platform.runLater(() -> windowLayout.requestFocus()); + } + /** + * Get the window properties. * * @return a Properties value */ private Properties getProperties() { - return properties; + return windowProperties; } /** - * Get the window value. + * Set the root content. * - * @return a Stage value + * @param inNode a Node value */ - private Stage getWindow() + private void setRoot(Node inNode) { - return window; + contentLayout.getChildren().add(inNode); } /** - * Update the window telemetry from the underlying window object. + * Set the draggable value for the window. + * + * @param inDraggable a boolean value */ - private void updateProperties() + private void setDraggable(boolean inDraggable) { - properties.setProperty(windowPosXProp, - String.valueOf(window.getX())); - properties.setProperty(windowPosYProp, - String.valueOf(window.getY())); - 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(windowModalProp, - String.valueOf(window.getModality())); - // TODO not sure what to do about dragging yet -// 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(windowFocusProp, - String.valueOf(hasFocus())); - Object windowId = window.getProperties().getOrDefault(windowStyleId, - null); - if(windowId == null) { - properties.remove(windowStyleId); - } else { - properties.setProperty(windowStyleId, - String.valueOf(windowId)); - } + draggableProperty.set(inDraggable); } /** - * Update the window object with the stored telemetry. + * Set the height value for the window. + * + * @param inHeight a double value */ - private void updateWindow() + private void setHeight(double inHeight) { - 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); - 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.setResizable(Boolean.parseBoolean(properties.getProperty(windowResizableProp))); - window.setTitle(properties.getProperty(windowTitleProp)); - window.setX(getDoubleValue(properties, - windowPosXProp)); - window.setY(getDoubleValue(properties, - windowPosYProp)); - window.getProperties().put(windowStyleId, - properties.getProperty(windowStyleId)); -// setHasFocus(Boolean.parseBoolean(properties.getProperty(windowFocusProp))); -// if(hasFocus) { -// window.requestFocus(); -// } + heightProperty.set(inHeight); + windowLayout.setPrefHeight(inHeight); + windowLayout.setMinHeight(inHeight); } /** - * Set the immutable properties of this window to the underlying properties storage. + * Set the width value for the window. * - * @param inContentViewFactory a ContentViewFactory value - * @param inUuid a Stringvalue + * @param inWidth a double value */ - private void setWindowStaticProperties(ContentViewFactory inContentViewFactory, - String inUuid) + private void setWidth(double inWidth) { - properties.setProperty(windowContentViewFactoryProp, - inContentViewFactory.getClass().getCanonicalName()); - properties.setProperty(windowUuidProp, - inUuid); + widthProperty.set(inWidth); + windowLayout.setPrefWidth(inWidth); + windowLayout.setMinWidth(inWidth); + } + /** + * Set the resizable value for the window. + * + * @param inResizable a boolean value + */ + public void setResizable(boolean inResizable) + { + resizableProperty.set(inResizable); } /** - * Close this window and remove it from active use. + * Set the window title property for the window. + * + * @param inWindowTitle a String value + */ + private void setTitle(String inWindowTitle) + { + windowTitleProperty.set(inWindowTitle); + } + /** + * Get the main layout node for the window. + * + * @return a Node value + */ + private Node getMainLayout() + { + return windowLayout; + } + /** + * Get the window X position value. + * + * @return a double value + */ + private double getX() + { + return xProperty.get(); + } + /** + * Get the window Y position value. + * + * @return a double value + */ + private double getY() + { + return yProperty.get(); + } + /** + * Get the window height value. + * + * @return a double value + */ + private double getHeight() + { + return heightProperty.get(); + } + /** + * Get the window width value. + * + * @return a double value + */ + private double getWidth() + { + return widthProperty.get(); + } + /** + * Get the window maximized value. + * + * @return a boolean value + */ + private boolean isMaximized() + { + return maximizedProperty.get(); + } + /** + * Get the window title value. + * + * @return a String value + */ + private String getTitle() + { + return windowTitleProperty.get(); + } + /** + * Get the window modality value. + * + * @return a Modality value + */ + private Modality getModality() + { + return modalityProperty.get(); + } + /** + * Get the window draggable value. + * + * @return a boolean value + */ + private boolean isDraggable() + { + return draggableProperty.get(); + } + /** + * Get the window resizable value. + * + * @return a boolean value + */ + private boolean isResizable() + { + return resizableProperty.get(); + } + /** + * Get the window scroll left value. + * + * @return a double value + */ + private double getScrollLeft() + { + return scrollLeftProperty.get(); + } + /** + * Set the window modality value. + * + * @param inModality a Modality value + */ + private void setModality(Modality inModality) + { + modalityProperty.set(inModality); + } + /** + * Set the window maximized value. + * + * @param inMaximized a boolean value + */ + private void setMaximized(boolean inMaximized) + { + maximizedProperty.set(inMaximized); + } + /** + * Set the window scroll left value. + * + * @param inScrollLeft a double value + */ + private void setScrollLeft(double inScrollLeft) + { + scrollLeftProperty.set(inScrollLeft); + } + /** + * Set the window scroll top value. + * + * @param inScrollTop a double value + */ + private void setScrollTop(double inScrollTop) + { + scrollTopProperty.set(inScrollTop); + } + /** + * Set the window X position value. + * + * @param inX a double value + */ + private void setX(double inX) + { + xProperty.set(inX); + getMainLayout().translateXProperty().set(inX); + } + /** + * Set the window Y position value. + * + * @param inY a double value + */ + private void setY(double inY) + { + yProperty.set(inY); + getMainLayout().translateYProperty().set(inY); + } + /** + * Close the window. */ private void close() { - ((Stage)getWindow().getScene().getWindow()).close(); + WindowRegistry windowRegistry = getCurrentUserRegistry(); + if(!windowRegistry.isLoggingOut()) { + windowRegistry.removeWindow(this); + windowRegistry.updateDisplayLayout(); + } + Platform.runLater(() -> PhotonApp.getWorkspace().getChildren().remove(getMainLayout())); + } + /** + * Show the window. + */ + private void show() + { + getMainLayout().translateXProperty().set(getX()); + getMainLayout().translateYProperty().set(getY()); + setViewOrder(-1); + Platform.runLater(() -> { + windowLayout.autosize(); + PhotonApp.getWorkspace().getChildren().add(getMainLayout()); + requestFocus(); + }); } /** * Get the window uuid value. @@ -585,45 +850,127 @@ private void close() */ private String getUuid() { - if(uuid == null) { - uuid = properties.getProperty(windowUuidProp); - } - return uuid; + return uuidProperty.get(); } /** - * Get the hasFocus value. + * Get a storable implementation of the window properties. * - * @return a boolean value + * @return a String value */ - private boolean hasFocus() + private String getStorableValue() { - return hasFocus; + return Util.propertiesToString(properties); } /** - * Sets the hasFocus value. - * - * @param inHasFocus a boolean value + * Set the immutable properties of this window to the underlying properties storage. */ - private void setHasFocus(boolean inHasFocus) + private void setWindowStaticProperties() { - hasFocus = inHasFocus; + properties.setProperty(windowContentViewFactoryProp, + viewFactoryProperty.get().getClass().getCanonicalName()); + properties.setProperty(windowUuidProp, + uuidProperty.get()); } /** - * indicates if this window has focus or not + * holds the Content View of the window */ - private transient boolean hasFocus; + 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 */ - private transient String uuid; + private final StringProperty uuidProperty = new SimpleStringProperty(); /** * properties used to record details about this window */ private final Properties properties; /** - * underlying UI element + * 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(); + /** + * holds the window modality property + */ + private final ObjectProperty modalityProperty = new SimpleObjectProperty<>(); + /** + * holds all the window's properties + */ + private final Properties windowProperties = new Properties(); + /** + * holds the window title property + */ + private final StringProperty windowTitleProperty = new SimpleStringProperty(); + /** + * holds the overall main window layout + */ + private VBox windowLayout; + /** + * holds the layout for the entire title bar */ - private final Stage window; + private HBox windowTitleLayout; + /** + * holds the layout for the window title + */ + private HBox titleLayout; + /** + * holds the layout for the close button + */ + private HBox closeButtonLayout; + /** + * holds the layout for the window content + */ + private VBox contentLayout; + /** + * holds the window title node + */ + private Label windowTitle; + /** + * holds the window close widget + */ + private Label closeLabel; } /** * Provides a registry of all windows. @@ -637,9 +984,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); @@ -653,8 +1000,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) { @@ -667,87 +1014,69 @@ private void closeAllWindows(boolean inUpdateDisplay) */ private void cascadeWindows() { - synchronized(windowPositionExaminerThreadPool) { - cancelWindowPositionMonitor(); - } - try { - synchronized(activeWindows) { - int xPos = desktopCascadeWindowOffset; - int 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 windowHeight = getWindowHeight(activeWindow.getWindow()); - double proposedX = xPos; - if(proposedX + windowWidth > maxX) { - proposedX = desktopCascadeWindowOffset; - } - double proposedY = yPos; - if(proposedY + windowHeight > maxY) { - proposedY = desktopCascadeWindowOffset; - } - activeWindow.getWindow().setX(proposedX); - activeWindow.getWindow().setY(proposedY); - activeWindow.getWindow().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(WindowMetaData 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); - 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. @@ -782,16 +1111,26 @@ private void restoreLayout(Properties inDisplayLayout) "Restoring {} {}", windowUid, windowProperties); - Stage newWindow = new Stage(); - newWindow.initOwner(App.getPrimaryStage()); - WindowMetaData newWindowMetaData = new WindowMetaData(windowProperties, - newWindow); - addWindow(newWindowMetaData); - addWindowListeners(newWindowMetaData); - styleService.addStyle(newWindowMetaData.getWindow().getScene()); - newWindowMetaData.getWindow().show(); + // 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); + newWindow.show(); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } } } + verifyAllWindowPositions(); } /** * Update the display layout for the windows in the given window registry. @@ -811,130 +1150,12 @@ private void updateDisplayLayout() ExceptionUtils.getRootCauseMessage(e)); } } - /** - * Add the necessary window listeners to the given window meta data. - * - * @param inWindowWrapper a WindowMetaData value - */ - 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 -//// 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, - WindowMetaData inWindowWrapper) - { - SLF4JLoggerProxy.trace(WindowManagerService.this, - "Verify: {}", - inDimension); - verifyWindowLocation(inWindowWrapper.getWindow()); - inWindowWrapper.updateProperties(); - updateDisplayLayout(); - } /** * 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,15 +1175,25 @@ 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) { + 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; - 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); + double maxWidth = workspaceRight; if(windowWidth > maxWidth) { inWindow.setWidth(maxWidth - (pad*2)); } @@ -970,47 +1201,42 @@ private void returnWindowToDesktop(Window inWindow) windowWidth = 100; inWindow.setWidth(windowWidth); } - double maxHeight = params.getBottom() - params.getTop(); - double windowHeight = getWindowHeight(inWindow); + double maxHeight = workspaceBottom; 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; + if(windowBottom > workspaceBottom) { + double newWindowTop = workspaceBottom - getWindowHeight(inWindow) - pad; inWindow.setY(newWindowTop); } // check top - double windowTop = getWindowTop(inWindow); - if(windowTop < params.getTop()+pad) { - double newWindowTop = params.getTop() + pad; + if(windowTop < workspaceTop+pad) { + double newWindowTop = workspaceTop + 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; + if(windowLeft < workspaceLeft) { + double newWindowLeft = workspaceLeft + pad; inWindow.setX(newWindowLeft); } // check right - double windowRight = getWindowRight(inWindow); - if(windowRight > params.getRight()) { - double newWindowLeft = params.getRight() - getWindowWidth(inWindow) - pad; + if(windowRight > workspaceRight) { + double newWindowLeft = workspaceRight - 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); } } /** @@ -1028,10 +1254,6 @@ private void logout() */ private void terminateRegistry() { - synchronized(windowPositionExaminerThreadPool) { - cancelWindowPositionMonitor(); - windowPositionExaminerThreadPool.shutdownNow(); - } closeAllWindows(false); } /** @@ -1044,60 +1266,20 @@ 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, 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. * @@ -1116,7 +1298,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, @@ -1132,20 +1314,12 @@ 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()); + private final Set activeWindows = Sets.newHashSet(); } /** * 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 */ @@ -1174,18 +1348,18 @@ 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 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 */ @@ -1202,15 +1376,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"; - /** - * provides access to style services - */ - @Autowired - private StyleService styleService; /** * web message service value */ @@ -1229,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 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..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 @@ -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,8 +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 +160,6 @@ public void changed(ObservableValue inObservable, eventTablePagination, new Separator(Orientation.HORIZONTAL), buttonLayout); - mainScene = new Scene(mainLayout); updateStrategies(); updateEvents(); strategyClient.addStrategyEventListener(this); @@ -179,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(); @@ -235,12 +233,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 +251,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 +308,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 +366,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 +387,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 +453,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 +772,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/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/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..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 @@ -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,8 +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 +89,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 +109,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) */ @@ -125,18 +129,10 @@ public void receiveTradeMessage(TradeMessage 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) + * @see org.marketcetera.ui.view.ContentView#onClose() */ @Override - public void onClose(WindowEvent inEvent) + public void onClose() { tradeClientService.removeTradeMessageListener(this); } @@ -489,11 +485,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 +498,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/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. 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..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 @@ -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,8 +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 +104,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) @@ -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); @@ -190,7 +189,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 +612,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 +704,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 +738,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 +930,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..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.Scene; -import javafx.stage.WindowEvent; +import javafx.scene.Node; /* $License$ */ @@ -15,11 +14,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. * @@ -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/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/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 @@ - 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