From ad64f5e4f616b35b4e134f5dff2104fe31a90ad9 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 29 May 2019 12:24:17 +0200 Subject: [PATCH 01/22] Added unknown organization --- .../database/OrganizationData.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java index c4fc4e0..52dad2d 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java @@ -63,6 +63,7 @@ public void refreshAll() { for (Vertex v : queryVertices("SELECT id FROM V_organization WHERE @RID IN (SELECT out FROM E_owns)")) { refresh(v); } + addNoOrganization(); } /** @@ -75,4 +76,16 @@ public OrganizationAttributes getAttributes(Organization org) { Vertex v = getVertexById("V_organization.id", org.getId()); return new OrganizationAttributes(v); } + + private void addNoOrganization(){ + Organization organization = new Organization("Unknown"); + //@RID IN (SELECT out FROM instance-of WHERE id = 'location') AND + //WHERE NOT @RID IN (SELECT in FROM E_owns WHERE out IN (SELECT @RID FROM V_organization WHERE @RID IN (SELECT out FROM E_owns))) + for (Vertex v : queryVertices("SELECT * FROM V_location ")) { + Place newPlace = new Location(v.getProperty("id"), v.getProperty("name")); + organization.addPlace(newPlace); + System.out.println("asdf"); + } + organizationManager.addOrganization(organization); + } } From a2e60de370d08779d6f1bc06858c5c0ae920b651 Mon Sep 17 00:00:00 2001 From: Lenovo Date: Wed, 29 May 2019 12:56:13 +0200 Subject: [PATCH 02/22] some tiny name changes and added an organization that contains all the locations --- .../controller/MainController.java | 4 ++-- .../controller/MainMenuController.java | 4 ++-- .../database/OrganizationData.java | 17 +++++++++++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java index eab228c..fe43a06 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java @@ -225,7 +225,7 @@ public void showSelectedNodeDetails(Node node) { Place nodePlace = placeManager.getPlace(node.getNodeId()); //setting the text fields on right panel - Node_Name_Text_Field.setText(nodePlace.toString()); + Node_Name_Text_Field.setText(nodePlace.getShortName()); Node_ID_Text_Field.setText(nodePlace.getId()); Node_Type_Text_Field.setText(nodePlace.getType().toString()); @@ -297,7 +297,7 @@ private TreeItem recursePopulateTreeView(Place sourcePlace, TreeItem sourceItem, */ public void populateTreeView(String searchKey) { Place rootPlace = placeManager.getRoot(); - String itemName = rootPlace.getType().toString() + ": " + rootPlace.toString(); + String itemName = rootPlace.toString(); TreeItem rootItem = new TreeItem<>(itemName); rootItem.setExpanded(true); rootItem.setGraphic(new ImageView("icons/location-icon.png")); diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java index 7430b75..e79b2fd 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java @@ -82,8 +82,8 @@ public void initialize() { * @param nodePlace Has properties to be shown. */ public void showSelectedPlaceDetails(Place nodePlace) { - Node_Name_Text_Field.setText(nodePlace.toString()); - Node_ID_Text_Field.setText(nodePlace.toString()); + Node_Name_Text_Field.setText(nodePlace.getShortName()); + Node_ID_Text_Field.setText(nodePlace.getId()); Node_Type_Text_Field.setText(nodePlace.getType().toString()); propertiesTable.clear(); nodePlace.loadAttributes(); diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java index 52dad2d..e141e15 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java @@ -16,6 +16,7 @@ public class OrganizationData extends Database { private final OrganizationManager organizationManager; + private Organization allOrganization; /** * constructor @@ -63,7 +64,8 @@ public void refreshAll() { for (Vertex v : queryVertices("SELECT id FROM V_organization WHERE @RID IN (SELECT out FROM E_owns)")) { refresh(v); } - addNoOrganization(); + addAllOrganization(); + //addNoOrganization(); } /** @@ -81,11 +83,18 @@ private void addNoOrganization(){ Organization organization = new Organization("Unknown"); //@RID IN (SELECT out FROM instance-of WHERE id = 'location') AND //WHERE NOT @RID IN (SELECT in FROM E_owns WHERE out IN (SELECT @RID FROM V_organization WHERE @RID IN (SELECT out FROM E_owns))) + for (Place p : allOrganization.getPlaces()) { + organization.addPlace(p); + } + organizationManager.addOrganization(organization); + } + + private void addAllOrganization(){ + allOrganization = new Organization("All"); for (Vertex v : queryVertices("SELECT * FROM V_location ")) { Place newPlace = new Location(v.getProperty("id"), v.getProperty("name")); - organization.addPlace(newPlace); - System.out.println("asdf"); + allOrganization.addPlace(newPlace); } - organizationManager.addOrganization(organization); + organizationManager.addOrganization(allOrganization); } } From d9e798c17052108b84a9000ea8cc405342302e36 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 31 May 2019 09:30:38 +0200 Subject: [PATCH 03/22] Refactored collapseButton --- .../CollapseButtonAction.java | 124 +++++++++++------- 1 file changed, 73 insertions(+), 51 deletions(-) diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java index 84981a3..d41afea 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java @@ -19,6 +19,7 @@ public abstract class CollapseButtonAction { /** * constructor + * * @param Collapse_Button button for collapsing pane * @param Split_Pane pane containing the pane that is to be collapsed * @param Collapse_Anchor_Pane pane to be collapsed/expanded @@ -38,58 +39,79 @@ public CollapseButtonAction(Button Collapse_Button, SplitPane Split_Pane, Anchor * Sets up the properties of panel collapse or panel contract button */ private void setPanelCollapseButtonProperty() { - if(left) { - Collapse_Button.setOnAction(event -> { - if (Split_Pane.getItems().contains(Collapse_Anchor_Pane)) { - Split_Pane.getItems().remove(Collapse_Anchor_Pane); - int splitPaneSize = Split_Pane.getItems().size(); - if (splitPaneSize == 2) { - Split_Pane.setDividerPosition(0, 0.8); - Center_Anchor_Pane.setPrefWidth(WIDTH * .80); - } else if (splitPaneSize == 1) { - Center_Anchor_Pane.setPrefWidth(WIDTH); - } - Collapse_Button.setText("▶"); - } else { - Split_Pane.getItems().add(0, Collapse_Anchor_Pane); - int splitPaneSize = Split_Pane.getItems().size(); - if (splitPaneSize == 2) { - Split_Pane.setDividerPosition(0, 0.2); - Center_Anchor_Pane.setPrefWidth(WIDTH * .80); - } else if (splitPaneSize == 3) { - Split_Pane.setDividerPosition(0, 0.2); - Split_Pane.setDividerPosition(1, 0.8); - Center_Anchor_Pane.setPrefWidth(WIDTH * .60); - } - Collapse_Button.setText("◀"); - } - }); + if (left) { + setCollapseButton("▶", "◀", 0.8); } else { - Collapse_Button.setOnAction(event -> { - if (Split_Pane.getItems().contains(Collapse_Anchor_Pane)) { - Split_Pane.getItems().remove(Collapse_Anchor_Pane); - int splitPaneSize = Split_Pane.getItems().size(); - if (splitPaneSize == 2) { - Split_Pane.setDividerPosition(0, 0.2); - Center_Anchor_Pane.setPrefWidth(WIDTH * .80); - } else if (splitPaneSize == 1) { - Center_Anchor_Pane.setPrefWidth(WIDTH); - } - Collapse_Button.setText("◀"); - } else { - Split_Pane.getItems().add(Split_Pane.getItems().size(), Collapse_Anchor_Pane); - int splitPaneSize = Split_Pane.getItems().size(); - if (splitPaneSize == 2) { - Split_Pane.setDividerPosition(0, 0.8); - Center_Anchor_Pane.setPrefWidth(WIDTH * .80); - } else if (splitPaneSize == 3) { - Split_Pane.setDividerPosition(0, 0.2); - Split_Pane.setDividerPosition(1, 0.8); - Center_Anchor_Pane.setPrefWidth(WIDTH * .60); - } - Collapse_Button.setText("▶"); - } - }); + setCollapseButton("◀", "▶", 0.2); } } + + /** + * Sets the collapse button + * + * @param collapseSymbol The symbol that represents collapsing + * @param expandSymbol The symbol that represents expanding + * @param dividerLocation The location of the divider for the menu + */ + private void setCollapseButton(String collapseSymbol, String expandSymbol, double dividerLocation) { + Collapse_Button.setOnAction(event -> { + if (Split_Pane.getItems().contains(Collapse_Anchor_Pane)) { + splitPaneRemove(collapseSymbol, dividerLocation); + } else { + splitPaneAdd(expandSymbol, 1 - dividerLocation); + } + }); + } + + /** + * Expands the menu + * + * @param textSymbol The symbol that should be printed on the footer + * @param dividerLocation The location of the divider for the menu + */ + private void splitPaneAdd(String symbol, double dividerLocation) { + addToAnchorPane(symbol); + int splitPaneSize = Split_Pane.getItems().size(); + if (splitPaneSize == 2) { + Split_Pane.setDividerPosition(0, dividerLocation); + Center_Anchor_Pane.setPrefWidth(WIDTH * .80); + } else if (splitPaneSize == 3) { + Split_Pane.setDividerPosition(0, 0.2); + Split_Pane.setDividerPosition(1, 0.8); + Center_Anchor_Pane.setPrefWidth(WIDTH * .60); + } + Collapse_Button.setText(symbol); + } + + /** + * Adds items to the anchor pane + * + * @param textSymbol The symbol that is used to determine which size to add + */ + private void addToAnchorPane(String symbol) { + if (symbol.equals("▶")) { + Split_Pane.getItems().add(Split_Pane.getItems().size(), Collapse_Anchor_Pane); + + } else { + Split_Pane.getItems().add(0, Collapse_Anchor_Pane); + } + } + + /** + * Collapses the menu + * + * @param textSymbol The symbol that should be printed on the footer + * @param dividerLocation The location of the divider for the menu + */ + private void splitPaneRemove(String symbol, double dividerLocation) { + Split_Pane.getItems().remove(Collapse_Anchor_Pane); + int splitPaneSize = Split_Pane.getItems().size(); + if (splitPaneSize == 2) { + Split_Pane.setDividerPosition(0, dividerLocation); + Center_Anchor_Pane.setPrefWidth(WIDTH * .80); + } else if (splitPaneSize == 1) { + Center_Anchor_Pane.setPrefWidth(WIDTH); + } + Collapse_Button.setText(symbol); + } } From e78ef2f1e6fc22b982bcebb65542329ba0d81f3f Mon Sep 17 00:00:00 2001 From: User Date: Fri, 31 May 2019 10:00:25 +0200 Subject: [PATCH 04/22] fixed unknown organizations --- .../database/OrganizationData.java | 29 +++++++++++++------ .../model/Organization.java | 4 +++ .../model/places/Place.java | 18 ++++++++++++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java index e141e15..d12028c 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java @@ -6,6 +6,8 @@ import com.mycompany.orientdbvisualizationtool.model.places.Place; import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.blueprints.impls.orient.OrientGraph; +import java.util.ArrayList; +import java.util.List; /** * Responsible for retrieving specific information about organizations from the @@ -65,7 +67,8 @@ public void refreshAll() { refresh(v); } addAllOrganization(); - //addNoOrganization(); + addNoOrganization(); + organizationManager.addOrganization(allOrganization); } /** @@ -78,23 +81,31 @@ public OrganizationAttributes getAttributes(Organization org) { Vertex v = getVertexById("V_organization.id", org.getId()); return new OrganizationAttributes(v); } - - private void addNoOrganization(){ + + /** + * Adds all the unconnected places + */ + private void addNoOrganization() { Organization organization = new Organization("Unknown"); - //@RID IN (SELECT out FROM instance-of WHERE id = 'location') AND - //WHERE NOT @RID IN (SELECT in FROM E_owns WHERE out IN (SELECT @RID FROM V_organization WHERE @RID IN (SELECT out FROM E_owns))) for (Place p : allOrganization.getPlaces()) { organization.addPlace(p); } - organizationManager.addOrganization(organization); + List places = new ArrayList<>(); + for (Organization o : OrganizationManager.getInstance().getOrganizations()) { + places.addAll(o.getPlaces()); + } + organization.getPlaces().removeAll(places); + organizationManager.addOrganization(organization); } - - private void addAllOrganization(){ + + /** + * Adds all the places + */ + private void addAllOrganization() { allOrganization = new Organization("All"); for (Vertex v : queryVertices("SELECT * FROM V_location ")) { Place newPlace = new Location(v.getProperty("id"), v.getProperty("name")); allOrganization.addPlace(newPlace); } - organizationManager.addOrganization(allOrganization); } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Organization.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Organization.java index 0fad0ff..eafe35c 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Organization.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Organization.java @@ -56,4 +56,8 @@ public void dereferenceAll() { public List getPlaces() { return places; } + + public void setPlaces(List newPlaces) { + this.places = newPlaces; + } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/places/Place.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/places/Place.java index 9b6f050..075499f 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/places/Place.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/places/Place.java @@ -6,6 +6,7 @@ import com.tinkerpop.blueprints.Vertex; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Super class for places Contains all the functionality for locations, @@ -216,4 +217,21 @@ public void loadAttributes() { } } + /** + * Checks if this place is equal to an object + * + * @param o The object this place is compared to + * @return Whether or not this place is equal to the object + */ + @Override + public boolean equals(Object o) { + if(o instanceof Place) { + Place p = (Place) o; + if(p.getId().equals(id) && p.getName().equals(name)) { + return true; + } + } + return false; + } + } From 6b8d21dca55bd68c6394571f3ac320c402962fa5 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 31 May 2019 10:24:32 +0200 Subject: [PATCH 05/22] Added organization attributes --- .../controller/MainMenuController.java | 11 +++++++++- .../model/Organization.java | 20 +++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java index e79b2fd..b4c7b4f 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java @@ -89,6 +89,15 @@ public void showSelectedPlaceDetails(Place nodePlace) { nodePlace.loadAttributes(); propertiesTable.addAll(nodePlace.getAttributes().getProperties()); } + + public void showSelectedPlaceDetails(Organization nodeOrganization) { + Node_Name_Text_Field.setText(nodeOrganization.getId()); + Node_ID_Text_Field.setText(nodeOrganization.getId()); + Node_Type_Text_Field.setText("Organization"); + propertiesTable.clear(); + nodeOrganization.loadAttributes(); + propertiesTable.addAll(nodeOrganization.getAttributes().getProperties()); + } /** @@ -108,6 +117,7 @@ public void populateOrganizationTreeView() { return; } populateLocationTreeView(((TreeItem) newValue).getValue()); + showSelectedPlaceDetails(currentOrganization); }); Organization_Tree_View.setShowRoot(false); @@ -139,7 +149,6 @@ private void initLocationTreeView(){ }); Location_Search.textProperty().addListener((observable, oldValue, newValue) -> { - searchLocations(newValue); }); } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Organization.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Organization.java index eafe35c..e48674e 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Organization.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Organization.java @@ -1,5 +1,7 @@ package com.mycompany.orientdbvisualizationtool.model; +import com.mycompany.orientdbvisualizationtool.database.DatabaseManager; +import com.mycompany.orientdbvisualizationtool.database.OrganizationAttributes; import com.mycompany.orientdbvisualizationtool.model.places.Place; import java.util.ArrayList; import java.util.List; @@ -14,6 +16,7 @@ public class Organization { private final String id; private List places; + private OrganizationAttributes attributes; /** * Constructor @@ -57,7 +60,20 @@ public List getPlaces() { return places; } - public void setPlaces(List newPlaces) { - this.places = newPlaces; + /** + * Loads the attributes for this place + */ + public void loadAttributes() { + if(attributes == null) { + attributes = DatabaseManager.getInstance().getOrganizationData().getAttributes(this); + } + } + + /** + * + * @return The organization attributes + */ + public OrganizationAttributes getAttributes() { + return attributes; } } From cfed9bb09ba6a55f101f95cc3f35ee6dd71c7ecf Mon Sep 17 00:00:00 2001 From: User Date: Fri, 31 May 2019 11:56:29 +0200 Subject: [PATCH 06/22] entity attributes added --- .../TableViewItemClickedAction.java | 23 ++++++++++++++---- .../database/EntityData.java | 4 +-- .../database/OrganizationData.java | 5 ++-- .../model/Entity.java | 20 +++++++++++++++ .../model/places/Place.java | 16 ++++++------ .../resources/icons/organization-icon.png | Bin 299 -> 593 bytes .../src/main/resources/icons/sensor-icon.png | Bin 0 -> 2713 bytes 7 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 OrientDBVisualizationTool/src/main/resources/icons/sensor-icon.png diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/TableViewAction/TableViewItemClickedAction.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/TableViewAction/TableViewItemClickedAction.java index 1779aaf..bc61a39 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/TableViewAction/TableViewItemClickedAction.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/TableViewAction/TableViewItemClickedAction.java @@ -9,6 +9,7 @@ import javafx.scene.input.MouseEvent; import javafx.event.EventHandler; +import javafx.stage.Stage; /** * Action performed when Table View Item is clicked @@ -34,16 +35,28 @@ public void handle(MouseEvent event) { if (event.getClickCount() == 2) { Entity entity = (Entity) Table_View.getSelectionModel().getSelectedItem(); Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.getDialogPane().setMinWidth(800); + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + stage.getIcons().add(new Image("/icons/sb-icon.png")); alert.setTitle("Entity Information"); alert.setHeaderText("Entity details"); - alert.setContentText("Entity ID:\n" + entity.getId() + "\n\nEntity Description:\n" + - "\n\n"); - ImageView imageView = new ImageView(new Image("/icons/sb-icon.png")); - imageView.setFitHeight(60); - imageView.setFitWidth(80); + alert.setContentText("Entity ID:\n" + entity.getId() + "\n\nEntity Description:" + + getEntityDescription(entity)); + ImageView imageView = new ImageView(new Image("/icons/sensor-icon.png")); + imageView.setFitHeight(64); + imageView.setFitWidth(64); alert.setGraphic(imageView); alert.showAndWait(); } } + + private String getEntityDescription(Entity entity) { + String entityDescription = ""; + entity.loadAttributes(); + for (String s : entity.getAttributes().getTypes()) { + entityDescription += "\n" + s; + } + return entityDescription; + } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/EntityData.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/EntityData.java index 35d6456..1be7a96 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/EntityData.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/EntityData.java @@ -138,8 +138,8 @@ private boolean isSensor(Vertex v) { * @param entity The place we want to retrieve the attributes from * @return A class containing all the attributes */ - public EntityAttributes getAttributes(Entity ent) { - Vertex v = getVertexById("V_instance.id", ent.getId()); + public EntityAttributes getAttributes(Entity entity) { + Vertex v = getVertexById("V_instance.id", entity.getId()); return new EntityAttributes(v); } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java index d12028c..67b6b70 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/OrganizationData.java @@ -90,11 +90,10 @@ private void addNoOrganization() { for (Place p : allOrganization.getPlaces()) { organization.addPlace(p); } - List places = new ArrayList<>(); + //list of places that have an organization for (Organization o : OrganizationManager.getInstance().getOrganizations()) { - places.addAll(o.getPlaces()); + organization.getPlaces().removeAll(o.getPlaces()); } - organization.getPlaces().removeAll(places); organizationManager.addOrganization(organization); } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Entity.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Entity.java index 3d9b97c..80e6d1e 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Entity.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/Entity.java @@ -1,5 +1,7 @@ package com.mycompany.orientdbvisualizationtool.model; +import com.mycompany.orientdbvisualizationtool.database.DatabaseManager; +import com.mycompany.orientdbvisualizationtool.database.EntityAttributes; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -11,6 +13,7 @@ public class Entity { private final StringProperty id; + private EntityAttributes attributes; /** * constructor @@ -33,4 +36,21 @@ public String getId() { public String toString(){ return id.get(); } + + /** + * Loads the attributes for this place + */ + public void loadAttributes() { + if(attributes == null) { + attributes = DatabaseManager.getInstance().getEntityData().getAttributes(this); + } + } + + /** + * + * @return The entity attributes + */ + public EntityAttributes getAttributes() { + return attributes; + } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/places/Place.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/places/Place.java index 075499f..673d62a 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/places/Place.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/places/Place.java @@ -201,37 +201,37 @@ public String getPath() { } /** - * + * * @return The attributes of a place */ public PlaceAttributes getAttributes() { return attributes; } - + /** * Loads the attributes for this place */ public void loadAttributes() { - if(attributes == null) { + if (attributes == null) { attributes = DatabaseManager.getInstance().getPlaceData().getAttributes(this); } } - + /** * Checks if this place is equal to an object - * + * * @param o The object this place is compared to * @return Whether or not this place is equal to the object */ @Override public boolean equals(Object o) { - if(o instanceof Place) { + if (o instanceof Place) { Place p = (Place) o; - if(p.getId().equals(id) && p.getName().equals(name)) { + if (p.getId().equals(id) && p.getName().equals(name)) { return true; } } return false; } - + } diff --git a/OrientDBVisualizationTool/src/main/resources/icons/organization-icon.png b/OrientDBVisualizationTool/src/main/resources/icons/organization-icon.png index e00459dbbed291b360f4d2e4a9b5164cbfd345c3..e8029856f7d8ed3961d0eeb13896cd6348ed81ae 100644 GIT binary patch literal 593 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4O z;1O92wCOqsGdgL^t^f+Mmw5WRvOi{(=TVUR#s7K&0|TSHr;B5V#`)5V`@Lo}O0<5A z|8(?1Ky%my7Eg{J>|WEkyaKIu&8T8Ms<*TC(UVut9_U(dUH5zWq-iEHC!HjGqQ9QI5c^>Is%e{; zTpZ5r3HRF9Jmo<3?Nj``?ODH6j|v!Rey?AoB8cwb$YHPyPSvCTXClhle++1*x*;aXDl|Aitp=;&4$$Ymdx zGiS+M`|S_cEi_{5mG~Eb*x%PQ+HTiNiS0_BzP)BzQ@;U2PqoA~q9i4;B-JXpC>2OC z7#SE^>Kd5p8XJZf8dw<{Ss5E>8yHy`7#M#!)P$lTH$NpatrE8er08-nxG qO3D+9QW?t2%k?tzvWt@w3sUv+i_&MmvylQSV(@hJb6Mw<&;$U4?AHGP delta 283 zcmcb}vYKgvWIY=L1B3kM|A|0~Ey>&6h2cL4F4((#GEjuGz$3Dlfq`2Xgc%uT&5-~K zvX^-Jy0SlJ73Aa9`MA<~5l~1rGbEzKIX^cyHLnE7WngeFN=+@GaYT!CNhJHxA@i6 zdbfL_3<)b&NFHEfP)brtT3fw;?!k#~%)%!3rf$0UQqEhm^_te3+#DP4FSg(R)E|DI a!z%K6LHOenAsc-`uJ&~Gb6Mw<&;$U=e{53# diff --git a/OrientDBVisualizationTool/src/main/resources/icons/sensor-icon.png b/OrientDBVisualizationTool/src/main/resources/icons/sensor-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b693c1c5e557def44169028a617d2d357079879e GIT binary patch literal 2713 zcmV;K3TE|*P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 zVoOIv0063uBQgL0010qNS#tmY4c7nw4c7reD4Tcy000McNliru;{_iLH4R9{CT#!! z31>+}K~!kot=V~SmRG$8@XwpPSs)<`ge3$BTcNeI7bw&#xp3>$rKMV}7GtZRBeYYi zb9Ki3_Re@6XPnz{nL933+hQHGQgPDaU{j%+3KUxzN=RE-6ADS#LdZf0S>E@(f8;r$JE-ZPS0pWg-0>zd))4r zDh;xfSu7+ZBuk+JWfqBw=+$VqYCE;OvjmF$!YX-wEfXObG6(xYLJYp=D|e?RFL=u9 z?*xGy-N;gE+K9%7<;z#1+-?4Dqu0hxAj4Ga)ObO z&F4)M8uj!8vWqRX-jBUs-dHq{>t^MnnzF@y2eimF-_2%&Qg@haiz-cGBP9@u4;|gw zkJ@U7Bidz~;oT~&1X(JSnCwYM(oK<0Aj=GS-WavQn?2ON_9dg!G3*x;CeNLWD z-b~$3se2&Py9Sw$4ts1>FD6f^N$Bvr%?bU}t+m1R3CA~pK*(I5R%zlG2)yXHn0yuP zcb8IJRF$;e5|uvVnqiM;l&I9{=Nf}Gkmqjq znmMNF2mE2kC1eR`f%FF2U)RxW#P_sdTO35%Eu-bVLs_-Q$ZEYSwI= zGWl|b`Eri+{RH~4$m=3vgU@BBoY0ccGVna298-K%OqcBz#FsGMx4flWOrLJOq51#6uMQB)-e9n^t7PV z;5W9a*CAx0zgll~+L?~U)6bi{*OWB>*{#MyUey6Y>YekTrGx!pWmei2#_jS`K0c?~ zW9s8?jhb|r=oaGxO)*KXkT!>1NQn5Ys=YiIeq&Dgqxq&M7&qVQegbDbouYw8+tee= zA|2{P?X%7N06#f^h^Oq(l0e|H!y>rGYOSg@Yqm>80)bpBWQXyztQ2vbnvko)eLDQW zF@0W9IShezTfLw!pr_IU+MTjfmpV-eJz+D=4&&euLdUsHC3ZNe&l#PDM!WXF>6xQM zv0`ELq>Rb7JS;bD_Y#Sp=;IFQ)*_1BVe`jWT=_Fy8$VI4cIiTu0__gCgei)XzRI*H zY?aArA)`f&2AwwR(Q21&T(88{vBEbjLChiRy@G0cbmGgMFii)2>OJd#F09M$yaRNEXsenho-*+NArULdZ4<8DY|*5hSAP#dplIyC#4 z$vz&CF$|5jJ?jE;d_vF!J{Ikf*M^TAkgeh z{lV-ZIkIiip;2>?(+{gnDVdLYU9Yf(zAWGGY(tHo8VAm58v%ic9%Pv0MwAO9=5o-` zu)TVc?k`$3BiAD9&}EzcMIF{ zH9Ty|0pq>fmu+-Zioa9}jawJct3M;-8@X_lCjFtW`K?E^1M)FhQ=F@2it_7^9_ z#6<0L$KW0gDYI(OF=cyLt9tJNmG-5TVHd2BZL-a}5=ygu-j&Grmw}bwz|-aqb8?hhYO#V*Pv2sTYIVu` zBDE-sc+=y0RiW0)Lvx~L&Fexz5ty=whZr@Pa(W0q zIOONfTI1%Vo2{{8xFb14%^%Zfqr)~>Hp;(7={RL?{2nzBLti>{+M&ieYs^t}mAmqx z*M7!Ej}Di}4tMJjb;`qDwB8D33Ps{QsWveIf5X2_N)LuUNv^+1BrkIVjPx9wgH3_}4JZRMYBwq05UK!IV~_X zEi*AxF)=zdGdeLdD=;!TFff|frppnF*z+TH7zqS zR539+H8VOfGb=DMIxsNng&!sW000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Y To9;Xs00000NkvXXu0mjfu-X?@ literal 0 HcmV?d00001 From bfe017ded950dbd0b5031ca44eb0da9dc4d55ccc Mon Sep 17 00:00:00 2001 From: User Date: Fri, 31 May 2019 12:07:43 +0200 Subject: [PATCH 07/22] Tiny refactoring in entityAttributes --- .../database/EntityAttributes.java | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/EntityAttributes.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/EntityAttributes.java index a1fb726..2179576 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/EntityAttributes.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/database/EntityAttributes.java @@ -1,5 +1,5 @@ /** - * + * */ package com.mycompany.orientdbvisualizationtool.database; @@ -13,27 +13,38 @@ * @author Carlos * */ -public class EntityAttributes{ - private ArrayList types; - - public EntityAttributes (Vertex v){ - Iterable parents; - types = new ArrayList(); - parents = v.getEdges(Direction.OUT, "instance-of"); - for(Edge e : parents) { - try { - types.add(e.getVertex(Direction.IN).getProperty("type-id")); - } catch (Exception ex) { - continue; - } - } - } - - /** - * @return the types - */ - public ArrayList getTypes() { - return types; - } +public class EntityAttributes { + + private ArrayList types; + + public EntityAttributes(Vertex v) { + Iterable parents; + types = new ArrayList(); + parents = v.getEdges(Direction.OUT, "instance-of"); + for (Edge e : parents) { + if(hasProperty(e)) { + types.add(e.getVertex(Direction.IN).getProperty("type-id")); + } + } + } + + private boolean hasProperty(Edge edge) { + try { + String value = edge.getVertex(Direction.IN).getProperty("type-id"); + if (value == null) { + return false; + } + } catch (Exception e) { + return false; + } + return true; + } + + /** + * @return the types + */ + public ArrayList getTypes() { + return types; + } } From b9f0b7055a56bc5789e28a449121c2cfbbf96979 Mon Sep 17 00:00:00 2001 From: YonaMoreda Date: Fri, 31 May 2019 16:16:43 +0200 Subject: [PATCH 08/22] refactored if else in panel collapse builder fixed some bugs and loopholes with saving or loading theme --- .../View/MainView.java | 10 +- .../View/VisApplication.java | 3 + .../CollapseButtonAction.java | 126 ++++++------- .../controller/MainController.java | 56 +++--- .../controller/MainMenuController.java | 33 ++-- .../controller/PreferencesMenuController.java | 168 ++++++++++++------ .../ThemeChoiceBoxAction.java | 2 +- 7 files changed, 223 insertions(+), 175 deletions(-) diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/MainView.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/MainView.java index 7ae26df..a565116 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/MainView.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/MainView.java @@ -12,6 +12,7 @@ public class MainView extends View { private MainController controller; + private boolean hasStarted = false; /** * Constructor @@ -27,8 +28,11 @@ public MainView() { */ @Override public void start() { - controller.setPlaceManager(PlaceManager.getInstance()); - controller.addRootNodeToPane(); - controller.populateTreeView(""); + if(!hasStarted) { + controller.setPlaceManager(PlaceManager.getInstance()); + controller.addRootNodeToPane(); + controller.populateTreeView(""); + hasStarted = true; + } } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java index 6a36d46..12af02e 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java @@ -53,6 +53,7 @@ public void changeToMain() { primaryStage.setWidth(MainView.getWIDTH()); primaryStage.setHeight(MainView.getWIDTH() * 9 / 16); primaryStage.centerOnScreen(); + primaryStage.setResizable(true); primaryStage.show(); } @@ -62,6 +63,7 @@ public void changeToMain() { public void changeToMenu() { menuView.start(); primaryStage.setScene(menuView.getScene()); + primaryStage.setResizable(true); primaryStage.show(); } @@ -74,6 +76,7 @@ public void changeToPreferences() { primaryStage.setScene(appearancePrefView.getScene()); primaryStage.setWidth(600); primaryStage.setHeight(490); + primaryStage.setResizable(false); primaryStage.show(); } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java index 84981a3..11b6ab4 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java @@ -15,81 +15,87 @@ public abstract class CollapseButtonAction { private AnchorPane Collapse_Anchor_Pane; private AnchorPane Center_Anchor_Pane; private final int WIDTH = MainView.getWIDTH(); - private boolean left; /** * constructor - * @param Collapse_Button button for collapsing pane - * @param Split_Pane pane containing the pane that is to be collapsed + * + * @param Collapse_Button button for collapsing pane + * @param Split_Pane pane containing the pane that is to be collapsed * @param Collapse_Anchor_Pane pane to be collapsed/expanded - * @param Center_Anchor_Pane pane centered within split pane - * @param left for determining if the pane is left or right sided + * @param Center_Anchor_Pane pane centered within split pane + * @param left for determining if the pane is left or right sided */ public CollapseButtonAction(Button Collapse_Button, SplitPane Split_Pane, AnchorPane Collapse_Anchor_Pane, AnchorPane Center_Anchor_Pane, boolean left) { this.Collapse_Button = Collapse_Button; this.Split_Pane = Split_Pane; this.Collapse_Anchor_Pane = Collapse_Anchor_Pane; this.Center_Anchor_Pane = Center_Anchor_Pane; - this.left = left; - setPanelCollapseButtonProperty(); + if (left) { + setLeftPanelCollapseButtonProperty(); + } else { + setRightPanelCollapseButtonProperty(); + } } /** - * Sets up the properties of panel collapse or panel contract button + * Sets up the properties of right panel for collapsing or contracting */ - private void setPanelCollapseButtonProperty() { - if(left) { - Collapse_Button.setOnAction(event -> { - if (Split_Pane.getItems().contains(Collapse_Anchor_Pane)) { - Split_Pane.getItems().remove(Collapse_Anchor_Pane); - int splitPaneSize = Split_Pane.getItems().size(); - if (splitPaneSize == 2) { - Split_Pane.setDividerPosition(0, 0.8); - Center_Anchor_Pane.setPrefWidth(WIDTH * .80); - } else if (splitPaneSize == 1) { - Center_Anchor_Pane.setPrefWidth(WIDTH); - } - Collapse_Button.setText("▶"); - } else { - Split_Pane.getItems().add(0, Collapse_Anchor_Pane); - int splitPaneSize = Split_Pane.getItems().size(); - if (splitPaneSize == 2) { - Split_Pane.setDividerPosition(0, 0.2); - Center_Anchor_Pane.setPrefWidth(WIDTH * .80); - } else if (splitPaneSize == 3) { - Split_Pane.setDividerPosition(0, 0.2); - Split_Pane.setDividerPosition(1, 0.8); - Center_Anchor_Pane.setPrefWidth(WIDTH * .60); - } - Collapse_Button.setText("◀"); + private void setRightPanelCollapseButtonProperty() { + Collapse_Button.setOnAction(event -> { + if (Split_Pane.getItems().contains(Collapse_Anchor_Pane)) { + Split_Pane.getItems().remove(Collapse_Anchor_Pane); + int splitPaneSize = Split_Pane.getItems().size(); + if (splitPaneSize == 2) { + Split_Pane.setDividerPosition(0, 0.2); + Center_Anchor_Pane.setPrefWidth(WIDTH * .80); + } else if (splitPaneSize == 1) { + Center_Anchor_Pane.setPrefWidth(WIDTH); } - }); - } else { - Collapse_Button.setOnAction(event -> { - if (Split_Pane.getItems().contains(Collapse_Anchor_Pane)) { - Split_Pane.getItems().remove(Collapse_Anchor_Pane); - int splitPaneSize = Split_Pane.getItems().size(); - if (splitPaneSize == 2) { - Split_Pane.setDividerPosition(0, 0.2); - Center_Anchor_Pane.setPrefWidth(WIDTH * .80); - } else if (splitPaneSize == 1) { - Center_Anchor_Pane.setPrefWidth(WIDTH); - } - Collapse_Button.setText("◀"); - } else { - Split_Pane.getItems().add(Split_Pane.getItems().size(), Collapse_Anchor_Pane); - int splitPaneSize = Split_Pane.getItems().size(); - if (splitPaneSize == 2) { - Split_Pane.setDividerPosition(0, 0.8); - Center_Anchor_Pane.setPrefWidth(WIDTH * .80); - } else if (splitPaneSize == 3) { - Split_Pane.setDividerPosition(0, 0.2); - Split_Pane.setDividerPosition(1, 0.8); - Center_Anchor_Pane.setPrefWidth(WIDTH * .60); - } - Collapse_Button.setText("▶"); + Collapse_Button.setText("◀"); + } else { + Split_Pane.getItems().add(Split_Pane.getItems().size(), Collapse_Anchor_Pane); + int splitPaneSize = Split_Pane.getItems().size(); + if (splitPaneSize == 2) { + Split_Pane.setDividerPosition(0, 0.8); + Center_Anchor_Pane.setPrefWidth(WIDTH * .80); + } else if (splitPaneSize == 3) { + Split_Pane.setDividerPosition(0, 0.2); + Split_Pane.setDividerPosition(1, 0.8); + Center_Anchor_Pane.setPrefWidth(WIDTH * .60); } - }); - } + Collapse_Button.setText("▶"); + } + }); + } + + /** + * Sets up the properties of left panel for collapsing or contracting + */ + private void setLeftPanelCollapseButtonProperty() { + Collapse_Button.setOnAction(event -> { + if (Split_Pane.getItems().contains(Collapse_Anchor_Pane)) { + Split_Pane.getItems().remove(Collapse_Anchor_Pane); + int splitPaneSize = Split_Pane.getItems().size(); + if (splitPaneSize == 2) { + Split_Pane.setDividerPosition(0, 0.8); + Center_Anchor_Pane.setPrefWidth(WIDTH * .80); + } else if (splitPaneSize == 1) { + Center_Anchor_Pane.setPrefWidth(WIDTH); + } + Collapse_Button.setText("▶"); + } else { + Split_Pane.getItems().add(0, Collapse_Anchor_Pane); + int splitPaneSize = Split_Pane.getItems().size(); + if (splitPaneSize == 2) { + Split_Pane.setDividerPosition(0, 0.2); + Center_Anchor_Pane.setPrefWidth(WIDTH * .80); + } else if (splitPaneSize == 3) { + Split_Pane.setDividerPosition(0, 0.2); + Split_Pane.setDividerPosition(1, 0.8); + Center_Anchor_Pane.setPrefWidth(WIDTH * .60); + } + Collapse_Button.setText("◀"); + } + }); } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java index eab228c..c78e2ec 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java @@ -35,38 +35,22 @@ */ public class MainController extends ParentController { - @FXML - private SplitPane Center_Split_Pane; - @FXML - private Button Left_Collapse_Button; - @FXML - private Button Right_Collapse_Button; - @FXML - private TextField Node_Name_Text_Field; - @FXML - private TextField Node_ID_Text_Field; - @FXML - private TextField Node_Type_Text_Field; - @FXML - private TreeView Left_Tree_View; - @FXML - private TableColumn Table_View_Entity_ID; - @FXML - private TableView Table_View; - @FXML - private Button Hide_Nodes_Button; - @FXML - private Button Show_All_Nodes_Button; - @FXML - private Label Left_Status_Label; - @FXML - private Label Right_Status_Label; - @FXML - private ChoiceBox Theme_Choice_Box; - @FXML - private AnchorPane Center_Anchor_Pane; - @FXML - private TextField Location_Search; + @FXML private SplitPane Center_Split_Pane; + @FXML private Button Left_Collapse_Button; + @FXML private Button Right_Collapse_Button; + @FXML private TextField Node_Name_Text_Field; + @FXML private TextField Node_ID_Text_Field; + @FXML private TextField Node_Type_Text_Field; + @FXML private TreeView Left_Tree_View; + @FXML private TableColumn Table_View_Entity_ID; + @FXML private TableView Table_View; + @FXML private Button Hide_Nodes_Button; + @FXML private Button Show_All_Nodes_Button; + @FXML private Label Left_Status_Label; + @FXML private Label Right_Status_Label; + @FXML private ChoiceBox Theme_Choice_Box; + @FXML private AnchorPane Center_Anchor_Pane; + @FXML private TextField Location_Search; private ArrayList nodes; private ArrayList edges; @@ -107,16 +91,16 @@ public class MainController extends ParentController { setThemeChoiceBoxProperty(); zoomFunction(); - Location_Search.textProperty().addListener((observable, oldValue, newValue) -> { - - populateTreeView(newValue); - }); + Location_Search.textProperty().addListener((observable, oldValue, newValue) -> populateTreeView(newValue)); } /** * Buttons for collapsing left and right panels are set up. */ private void setCollapseButtons() { + SplitPane.setResizableWithParent(Center_Split_Pane.getItems().get(0), Boolean.FALSE); + SplitPane.setResizableWithParent(Center_Split_Pane.getItems().get(2), Boolean.FALSE); + AnchorPane left_Anchor_Pane = (AnchorPane) Center_Split_Pane.getItems().get(0); AnchorPane right_Anchor_Pane = (AnchorPane) Center_Split_Pane.getItems().get(2); diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java index 7430b75..3b3615f 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java @@ -26,26 +26,16 @@ */ public class MainMenuController extends ParentController { - @FXML - private TextField Node_Name_Text_Field; - @FXML - private TextField Node_ID_Text_Field; - @FXML - private TextField Node_Type_Text_Field; - @FXML - private TreeView Organization_Tree_View; - @FXML - private TreeView Location_Tree_View; - @FXML - private TableColumn Table_View_PropertyKey; - @FXML - private TableColumn Table_View_PropertyValue; - @FXML - private TableView Properties_Table; - @FXML - private TextField Organization_Search; - @FXML - private TextField Location_Search; + @FXML private TextField Node_Name_Text_Field; + @FXML private TextField Node_ID_Text_Field; + @FXML private TextField Node_Type_Text_Field; + @FXML private TreeView Organization_Tree_View; + @FXML private TreeView Location_Tree_View; + @FXML private TableColumn Table_View_PropertyKey; + @FXML private TableColumn Table_View_PropertyValue; + @FXML private TableView Properties_Table; + @FXML private TextField Organization_Search; + @FXML private TextField Location_Search; private final ObservableList propertiesTable = FXCollections.observableArrayList(); private OrganizationManager organizationManager; @@ -55,8 +45,7 @@ public class MainMenuController extends ParentController { /** * The main default properties of controller are initialized */ - @FXML - public void initialize() { + @FXML public void initialize() { Node_Name_Text_Field.setDisable(true); Node_Name_Text_Field.setStyle("-fx-opacity: 1;"); diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java index 4931271..588deb7 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java @@ -6,6 +6,7 @@ import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.*; +import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.paint.Color; @@ -18,6 +19,7 @@ import java.io.FileWriter; import java.io.IOException; import java.nio.file.Paths; +import java.util.Optional; public class PreferencesMenuController { @@ -86,64 +88,129 @@ public class PreferencesMenuController { private void setButtonActions() { Save_Button.setOnAction(event -> { try { - fileChooserDialog(event, true); + saveThemeDialog(); } catch (IOException e) { e.printStackTrace(); } }); - Open_Button.setOnAction(event -> { - try { - fileChooserDialog(event, false); - } catch (IOException e) { - e.printStackTrace(); + Open_Button.setOnAction(this::loadingDialogue); + Cancel_Button.setOnAction(event -> { + Alert alert = getAlert("Return to main application without saving?", ""); + if (alert.getResult() == ButtonType.YES) { + VisApplication.getInstance().changeToMain(); } }); - Cancel_Button.setOnAction(event -> VisApplication.getInstance().changeToMain()); } /** - * opens a file choosing dialog for saving or choosing a theme css file + * dialogue for loading theme files * - * @param event button action event - * @param isSaving boolean to distinguish between a saving and a loading file chooser - * @throws IOException for bufferedWriter and creating new file + * @param event action event for getting stage window */ - private void fileChooserDialog(ActionEvent event, boolean isSaving) throws IOException { - FileChooser fileChooser = fileChooserWithInitialProperties(isSaving); - File selectedFile; + private void loadingDialogue(ActionEvent event) { + FileChooser fileChooser = fileChooserWithInitialProperties(); Window mainStage = ((Node) event.getTarget()).getScene().getWindow(); - if (isSaving) { //saving theme file - selectedFile = fileChooser.showSaveDialog(mainStage); - if (selectedFile != null) { - if (!selectedFile.exists()) { - selectedFile.createNewFile(); + File selectedFile = fileChooser.showOpenDialog(mainStage); + if (selectedFile != null) { + mainScene.getStylesheets().add("styles/" + selectedFile.getName()); + VisApplication.getInstance().changeToMain(); + } + } + + /** + * opens a file choosing dialog for saving a theme css file + * + * @throws IOException for bufferedWriter and creating new file + */ + private void saveThemeDialog() throws IOException { + TextInputDialog textInputDialog = getTextInputDialogue(); + Optional text = textInputDialog.showAndWait(); + if (text.isPresent()) { + String currentPath = Paths.get(".").toAbsolutePath().normalize().toString(); + File selectedFile = new File(currentPath + "/OrientDBVisualizationTool/src/main/resources/styles/" + text.get() + ".css"); + if (selectedFile.exists()) { + Alert alert = getAlert("Replace already existing file?", ""); + if (alert.getResult() == ButtonType.YES) { + saveToFile(selectedFile); + } else if (alert.getResult() == ButtonType.NO) { + text = textInputDialog.showAndWait(); + if (text.isPresent()) { + selectedFile = new File(currentPath + "/OrientDBVisualizationTool/src/main/resources/styles/" + text.get() + ".css"); + saveToFile(selectedFile); + } } + } else { saveToFile(selectedFile); - showConfirmationDialog(selectedFile); - } - } else { //loading or opening theme file - selectedFile = fileChooser.showOpenDialog(mainStage); - if (selectedFile != null) {//TODO:: MAKE SURE ALL CSS FILES ARE STORED IN RESOURCES/STYLES FOLDER - mainScene.getStylesheets().add("styles/" + selectedFile.getName()); - VisApplication.getInstance().changeToMain(); } } } + /** + * shows the save confirmation dialogue + * + * @param fileName file name that is saved. + */ + private void showSaveConfirmation(String fileName) { + Alert confirm = new Alert(Alert.AlertType.CONFIRMATION, fileName + " has been saved successfully.\n\n" + + "Theme file can be applied after application restart.", ButtonType.OK); + confirm.setHeaderText(""); + confirm.setGraphic(getSBIcon()); + confirm.showAndWait(); + VisApplication.getInstance().changeToMain(); + } + + /** + * gets alert dialog with given content text + * + * @param contentText displayed as content for alert + * @param headerText displayed as header text for alert + * @return alert with contentText + */ + private Alert getAlert(String contentText, String headerText) { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION, contentText, + ButtonType.YES, ButtonType.NO, ButtonType.CANCEL); + alert.setGraphic(getSBIcon()); + alert.setHeaderText(headerText); + alert.showAndWait(); + return alert; + } + + /** + * gets the text input dialogue for saving + * + * @return text input dialogue for saving + */ + private TextInputDialog getTextInputDialogue() { + TextInputDialog textInputDialog = new TextInputDialog("Untitled_Theme"); + textInputDialog.setGraphic(getSBIcon()); + textInputDialog.setTitle("Save As"); + textInputDialog.setContentText("File name: "); + textInputDialog.setHeaderText("Do you want to save changes to Untitled_Theme?"); + return textInputDialog; + } + + /** + * gets the sb icon with ImageView wrapper + * + * @return the SB-icon within image view + */ + private ImageView getSBIcon() { + ImageView imageView = new ImageView(new Image("/icons/sb-icon.png")); + imageView.setFitHeight(60); + imageView.setFitWidth(80); + return imageView; + } + /** * fileChooser is created with a starting directory and title - * @param isSaving for setting the title ("Open Theme File" or "Save Theme File") + * * @return fileChooser */ - private FileChooser fileChooserWithInitialProperties(boolean isSaving) { + private FileChooser fileChooserWithInitialProperties() { FileChooser fileChooser = new FileChooser(); String currentPath = Paths.get(".").toAbsolutePath().normalize().toString(); File initialDirectory = new File(currentPath + "/OrientDBVisualizationTool/src/main/resources/styles"); - if (isSaving) { - fileChooser.setTitle("Save Theme File"); - } else { - fileChooser.setTitle("Open Theme File"); - } + fileChooser.setTitle("Open Theme File"); if (initialDirectory.exists()) { fileChooser.setInitialDirectory(initialDirectory); } @@ -153,6 +220,7 @@ private FileChooser fileChooserWithInitialProperties(boolean isSaving) { /** * writes to selected file + * * @param selectedFile file to which contents are written in * @throws IOException for bufferedWriter */ @@ -160,25 +228,7 @@ private void saveToFile(File selectedFile) throws IOException { BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(selectedFile)); bufferedWriter.write(getNewCssContent()); bufferedWriter.close(); - } - - /** - * After saving, gives option to apply newly created theme - * @param selectedFile newly created and saved theme file. - */ - private void showConfirmationDialog(File selectedFile) { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Apply the saved theme?\nTheme file must be located under resources/styles", ButtonType.YES, ButtonType.NO, ButtonType.CANCEL); - ImageView imageView = new ImageView("icons/sb-icon.png"); - imageView.setFitHeight(60); - imageView.setFitWidth(80); - alert.setGraphic(imageView); - alert.showAndWait(); - if (alert.getResult() == ButtonType.YES) { - mainScene.getStylesheets().add("styles/" + selectedFile.getName()); - VisApplication.getInstance().changeToMain(); - } else { - VisApplication.getInstance().changeToMain(); - } + showSaveConfirmation(selectedFile.getName()); } /** @@ -224,8 +274,9 @@ private void setColorPickerActions() { /** * converts color picker hex values to web RGB color values + * * @param color colorPicker with hex value - * @return + * @return rgb code in web format */ private String toRGBCode(ColorPicker color) { Color color1 = color.getValue(); @@ -235,6 +286,7 @@ private String toRGBCode(ColorPicker color) { /** * generates a css configuration for centerPane + * * @return New css configuration for centerPane */ private String getNewCenterPaneStyle() { @@ -247,6 +299,7 @@ private String getNewCenterPaneStyle() { /** * generates a css configuration for MenuBar + * * @return New css configuration for MenuBar */ private String getNewMenuBarStyle() { @@ -255,6 +308,7 @@ private String getNewMenuBarStyle() { /** * generates a css configuration for Menu + * * @return New css configuration for Menu */ private String getNewMenuStyle() { @@ -263,6 +317,7 @@ private String getNewMenuStyle() { /** * generates a css configuration for NodeLabel + * * @return New css configuration for NodeLabel */ private String getNewNodeLabelStyle() { @@ -271,6 +326,7 @@ private String getNewNodeLabelStyle() { /** * generates a css configuration for Edge + * * @return New css configuration for Edge */ private String getNewEdgeStyle() { @@ -279,6 +335,7 @@ private String getNewEdgeStyle() { /** * generates a css configuration for Button + * * @return New css configuration for Button */ private String getNewButtonStyle() { @@ -288,6 +345,7 @@ private String getNewButtonStyle() { /** * generates a css configuration for TextFieldLabel + * * @return New css configuration for TextFieldLabel */ private String getNewTextFieldLabelStyle() { @@ -296,6 +354,7 @@ private String getNewTextFieldLabelStyle() { /** * generates a css configuration for TextField + * * @return New css configuration for TextField */ private String getNewTextFieldStyle() { @@ -305,6 +364,7 @@ private String getNewTextFieldStyle() { /** * generates a css configuration for Root + * * @return New css configuration for Root */ private String getNewRootStyle() { @@ -325,6 +385,7 @@ private String getNewRootStyle() { /** * generates a css configuration from all css components + * * @return New css configuration */ private String getNewCssContent() { @@ -356,6 +417,7 @@ private String getNewCssContent() { /** * sets the main application scene for applying the theme + * * @param scene used for applying the theme */ public void setApplicationScene(Scene scene) { diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/ThemeChoiceAction/ThemeChoiceBoxAction.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/ThemeChoiceAction/ThemeChoiceBoxAction.java index 16f741e..f36bcc0 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/ThemeChoiceAction/ThemeChoiceBoxAction.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/ThemeChoiceAction/ThemeChoiceBoxAction.java @@ -33,7 +33,7 @@ public ThemeChoiceBoxAction(AnchorPane Center_Anchor_Pane, ChoiceBox Theme_Choic * Setting the check choice box property */ private void setThemeChoiceBoxProperty() { - Theme_Choice_Box.getItems().addAll("Default Theme", "Dark Mode", "Natural Blue", "S.B. Green", "Crimson Red", "Create a custom theme"); + Theme_Choice_Box.getItems().addAll("Default Theme", "Dark Mode", "Natural Blue", "S.B. Green", "Crimson Red", "Custom Theme"); Theme_Choice_Box.getSelectionModel().selectFirst(); } From 7effd94db6f9a2717e701ef7f00abab772b36549 Mon Sep 17 00:00:00 2001 From: YonaMoreda Date: Fri, 31 May 2019 17:44:07 +0200 Subject: [PATCH 09/22] node label now has a fixed width node has a fixed width the expansion has fixed width --- .idea/vcs.xml | 6 ++++ .../orientdbvisualizationtool/View/Node.java | 30 +++++++++++++------ .../CollapseButtonAction.java | 6 ++-- 3 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Node.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Node.java index b4660b9..66af61c 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Node.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Node.java @@ -5,12 +5,14 @@ import com.mycompany.orientdbvisualizationtool.controller.NodeAction.NodeMouseEnteredAction; import com.mycompany.orientdbvisualizationtool.controller.NodeAction.NodeMouseExitedAction; import com.mycompany.orientdbvisualizationtool.controller.NodeAction.NodeMousePressedAction; +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.control.OverrunStyle; import javafx.scene.control.Tooltip; import javafx.scene.layout.*; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Font; -import javafx.scene.text.Text; /** * Node represents a vertex in view. @@ -19,7 +21,7 @@ */ public class Node extends StackPane { - private Text label; + private Label label; private String nodeName; private String nodeDisplayName; private String nodeId; @@ -53,11 +55,7 @@ public Node(String id, String nodeName, String NodeType, String displayName, Mai this.DEFAULT_SELECTED_COLOR = Color.LAVENDER; this.setId("NodeStackPane"); - - this.label = new Text(displayName); - this.label.setFont(new Font(13)); - this.label.setId("NodeLabel"); - + this.setLabelProperty(displayName); this.mainController = controller; this.setRectangleProperty(); this.setLayoutProperties(); @@ -66,6 +64,20 @@ public Node(String id, String nodeName, String NodeType, String displayName, Mai this.setMouseListenerProperties(); } + /** + * sets the property for Node label + * @param displayName is used to construct node label + */ + private void setLabelProperty(String displayName) { + this.label = new Label(); + this.label.setText(displayName); + this.label.setAlignment(Pos.CENTER); + this.label.setTextOverrun(OverrunStyle.LEADING_ELLIPSIS); + this.label.setMaxWidth(170); + this.label.setFont(new Font(13)); + this.label.setId("NodeLabel"); + } + /** * Sets up the packing layout elements such as childrenVBox and containerPane */ @@ -90,7 +102,7 @@ private void setLayoutProperties() { private void setRectangleProperty() { //rounded rectangle this.rectangle = new Rectangle(); - this.rectangle.setWidth(label.getLayoutBounds().getWidth() + 30); + this.rectangle.setWidth(label.getMaxWidth() + 30); this.rectangle.setHeight(40.0f); this.rectangle.setArcWidth(40); this.rectangle.setArcHeight(40); @@ -129,7 +141,7 @@ private void setMouseListenerProperties() { * * @return javafx label */ - public Text getLabel() { + public Label getLabel() { return label; } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java index d41afea..4ef0d63 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonAction.java @@ -66,7 +66,7 @@ private void setCollapseButton(String collapseSymbol, String expandSymbol, doubl /** * Expands the menu * - * @param textSymbol The symbol that should be printed on the footer + * @param symbol The symbol that should be printed on the footer * @param dividerLocation The location of the divider for the menu */ private void splitPaneAdd(String symbol, double dividerLocation) { @@ -86,7 +86,7 @@ private void splitPaneAdd(String symbol, double dividerLocation) { /** * Adds items to the anchor pane * - * @param textSymbol The symbol that is used to determine which size to add + * @param symbol The symbol that is used to determine which size to add */ private void addToAnchorPane(String symbol) { if (symbol.equals("▶")) { @@ -100,7 +100,7 @@ private void addToAnchorPane(String symbol) { /** * Collapses the menu * - * @param textSymbol The symbol that should be printed on the footer + * @param symbol The symbol that should be printed on the footer * @param dividerLocation The location of the divider for the menu */ private void splitPaneRemove(String symbol, double dividerLocation) { From ffa127669892c963e0c053e5a4fadcff97632e19 Mon Sep 17 00:00:00 2001 From: YonaMoreda Date: Mon, 3 Jun 2019 14:38:46 +0200 Subject: [PATCH 10/22] fixed node label discolor problem on theme selection --- .../orientdbvisualizationtool/View/Node.java | 89 ++----------------- .../View/NodeLabel.java | 27 ++++++ .../orientdbvisualizationtool/VisTool.java | 15 +++- .../controller/MainController.java | 27 +++++- .../NodeAction/NodeMouseClickedAction.java | 3 +- .../src/main/resources/fxml/MainDesign.fxml | 4 +- .../resources/styles/02_DarkModeStyle.css | 7 +- .../main/resources/styles/05_CrimsonStyle.css | 2 +- 8 files changed, 79 insertions(+), 95 deletions(-) create mode 100644 OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/NodeLabel.java diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Node.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Node.java index 66af61c..e02b915 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Node.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Node.java @@ -5,14 +5,10 @@ import com.mycompany.orientdbvisualizationtool.controller.NodeAction.NodeMouseEnteredAction; import com.mycompany.orientdbvisualizationtool.controller.NodeAction.NodeMouseExitedAction; import com.mycompany.orientdbvisualizationtool.controller.NodeAction.NodeMousePressedAction; -import javafx.geometry.Pos; -import javafx.scene.control.Label; -import javafx.scene.control.OverrunStyle; import javafx.scene.control.Tooltip; import javafx.scene.layout.*; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; -import javafx.scene.text.Font; /** * Node represents a vertex in view. @@ -21,11 +17,8 @@ */ public class Node extends StackPane { - private Label label; - private String nodeName; - private String nodeDisplayName; + private NodeLabel nodeLabel; private String nodeId; - private String nodeType; private boolean selected; private Rectangle rectangle; private Color DEFAULT_COLOR; @@ -35,27 +28,22 @@ public class Node extends StackPane { private VBox childrenVBox; private Pane containerPane; - /** * Constructor * * @param id The id of the node - * @param nodeName The name of the node * @param NodeType The type of the node * @param displayName The display name of the node */ - public Node(String id, String nodeName, String NodeType, String displayName, MainController controller) { + public Node(String id, String NodeType, String displayName, MainController controller) { this.nodeId = id; this.selected = false; this.expanded = false; - this.nodeName = nodeName; - this.nodeType = NodeType; - this.nodeDisplayName = displayName; this.DEFAULT_COLOR = Color.LIGHTGRAY; this.DEFAULT_SELECTED_COLOR = Color.LAVENDER; this.setId("NodeStackPane"); - this.setLabelProperty(displayName); + this.nodeLabel = new NodeLabel(displayName); this.mainController = controller; this.setRectangleProperty(); this.setLayoutProperties(); @@ -64,20 +52,6 @@ public Node(String id, String nodeName, String NodeType, String displayName, Mai this.setMouseListenerProperties(); } - /** - * sets the property for Node label - * @param displayName is used to construct node label - */ - private void setLabelProperty(String displayName) { - this.label = new Label(); - this.label.setText(displayName); - this.label.setAlignment(Pos.CENTER); - this.label.setTextOverrun(OverrunStyle.LEADING_ELLIPSIS); - this.label.setMaxWidth(170); - this.label.setFont(new Font(13)); - this.label.setId("NodeLabel"); - } - /** * Sets up the packing layout elements such as childrenVBox and containerPane */ @@ -93,7 +67,6 @@ private void setLayoutProperties() { this.containerPane = new Pane(); this.containerPane.getChildren().addAll(this, childrenVBox); this.containerPane.layout(); - } /** @@ -102,7 +75,7 @@ private void setLayoutProperties() { private void setRectangleProperty() { //rounded rectangle this.rectangle = new Rectangle(); - this.rectangle.setWidth(label.getMaxWidth() + 30); + this.rectangle.setWidth(nodeLabel.getMaxWidth() + 30); this.rectangle.setHeight(40.0f); this.rectangle.setArcWidth(40); this.rectangle.setArcHeight(40); @@ -111,19 +84,6 @@ private void setRectangleProperty() { this.rectangle.setId("NodeRectangle"); } - /** - * Constructor - * - * @param id The id of the node - * @param nodeName The name of the node - * @param NodeType The type of the node - */ - public Node(String id, String nodeName, String NodeType, MainController controller) { - this(id, nodeName, NodeType, nodeName, controller); - this.DEFAULT_COLOR = Color.LIGHTGRAY; - this.DEFAULT_SELECTED_COLOR = Color.LAVENDER; - } - /** * Sets properties for mouse events. Mouse pressed -> selection 2x Mouse * click -> expansion of node Mouse entered/exited -> highlight node @@ -141,17 +101,8 @@ private void setMouseListenerProperties() { * * @return javafx label */ - public Label getLabel() { - return label; - } - - /** - * Adds aa vertical box to a vertical box - * @param vBox The vertical box that needs to be added - */ - public void addToVBox(VBox vBox) { - vBox.getChildren().add(this); - vBox.layout(); + public NodeLabel getLabel() { + return nodeLabel; } /** @@ -194,13 +145,6 @@ public void setExpanded(Boolean expanded) { this.expanded = expanded; } - /** - * @param vbox The new vertical box - */ - public void setChildrenVBox(VBox vbox) { - this.childrenVBox = vbox; - } - /** * @return The node id */ @@ -208,27 +152,6 @@ public String getNodeId() { return nodeId; } - /** - * @return The node name - */ - public String getNodeName() { - return nodeName; - } - - /** - * @return The display name - */ - public String getDisplayName() { - return nodeDisplayName; - } - - /** - * @return The node type - */ - public String getNodeType() { - return nodeType; - } - /** * @return The vertical box for the children */ diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/NodeLabel.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/NodeLabel.java new file mode 100644 index 0000000..bdc480d --- /dev/null +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/NodeLabel.java @@ -0,0 +1,27 @@ +package com.mycompany.orientdbvisualizationtool.View; + +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.control.OverrunStyle; +import javafx.scene.text.Font; + +/** + * NodeLabel represents the label to display the name for node + */ +public class NodeLabel extends Label { + + /** + * constructor + * @param displayName the string that the label displays + */ + public NodeLabel(String displayName) { + super(); + this.setText(displayName); + this.setAlignment(Pos.CENTER); + this.setTextOverrun(OverrunStyle.LEADING_ELLIPSIS); + this.setMaxWidth(170); + this.setFont(new Font(13)); + this.getStyleClass().remove("label"); + this.setId("NodeLabel"); + } +} diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/VisTool.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/VisTool.java index bbdb672..921cbc9 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/VisTool.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/VisTool.java @@ -7,6 +7,8 @@ import com.mycompany.orientdbvisualizationtool.model.Entity; import com.mycompany.orientdbvisualizationtool.model.Organization; +import java.util.Arrays; +import java.util.List; import java.util.Random; import javafx.application.Application; @@ -82,7 +84,7 @@ private static void addTestPlaces(Place parent, int index) { addEntities(newPlace); //recursvily call it for all the children - int childrenAmount = 5; + int childrenAmount = 3 + (new Random()).nextInt(5); for (int i = 0; i < childrenAmount; i++) { addTestPlaces(newPlace, index + 1); } @@ -95,8 +97,17 @@ private static void addTestPlaces(Place parent, int index) { */ private static void addEntities(Place currentPlace) { Random random = new Random(); + List entities = Arrays.asList("Electricity-", "Gas-", "Light-", "Sound-", "Humidity-"); + List type = Arrays.asList("Generation", "Balance", "Consumption", "Environment", "Simulation"); + List sensor = Arrays.asList("", "", "-Sensor", "-Virtual-Sensor", "-Windowed-Data"); for (int i = 0; i < random.nextInt(100); i++) { - Entity newEntity = new Entity("long_name_for_testdata_sensor_stuff_" + i); + int j = random.nextInt(5); + String entityName = entities.get(j); + j = random.nextInt(5); + entityName += type.get(j); + j = random.nextInt(5); + entityName += sensor.get(j); + Entity newEntity = new Entity(entityName + i); currentPlace.addEntity(newEntity); } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java index 2824e99..d66ef6f 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java @@ -182,10 +182,9 @@ public void setPlaceManager(PlaceManager placeManager) { public void addRootNodeToPane() { Place rootPlace = placeManager.getRoot(); String id = rootPlace.getId(); - String name = rootPlace.getName(); String type = rootPlace.getType().toString(); String displayName = rootPlace.toString(); - Node rootNode = new Node(id, name, type, displayName, this); + Node rootNode = new Node(id, type, displayName, this); nodes.add(rootNode); VBox rootVBox = new VBox(15); @@ -334,7 +333,31 @@ public void setMouseSourceY(Double mouseSourceY) { this.mouseSourceY = mouseSourceY; } + /** + * opens the preferences window + * @param actionEvent for preferences menu item + */ public void openPreferences(ActionEvent actionEvent) { VisApplication.getInstance().changeToPreferences(); } + + /** + * select all nodes + * @param actionEvent for select all menu item + */ + public void selectAllNodes(ActionEvent actionEvent) { + for(Node node : nodes) { + node.setSelected(true); + } + } + + /** + * unselect all nodes + * @param actionEvent for un select all menu item + */ + public void unselectAllNodes(ActionEvent actionEvent) { + for(Node node : nodes) { + node.setSelected(false); + } + } } \ No newline at end of file diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/NodeAction/NodeMouseClickedAction.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/NodeAction/NodeMouseClickedAction.java index afc8788..da3cde3 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/NodeAction/NodeMouseClickedAction.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/NodeAction/NodeMouseClickedAction.java @@ -81,10 +81,9 @@ private void expandNode(Node parentNode) { if (!childrenPlaces.isEmpty()) { for (Place place : childrenPlaces) { String id = place.getId(); - String name = place.getName(); String type = place.getType().toString(); String displayName = place.toString(); - Node childNode = new Node(id, name, type, displayName, controller); + Node childNode = new Node(id, type, displayName, controller); nodes.add(childNode); childrenVBox.getChildren().add(childNode.getContainerPane()); childrenVBox.layout(); diff --git a/OrientDBVisualizationTool/src/main/resources/fxml/MainDesign.fxml b/OrientDBVisualizationTool/src/main/resources/fxml/MainDesign.fxml index 1189cc1..c46d4cf 100644 --- a/OrientDBVisualizationTool/src/main/resources/fxml/MainDesign.fxml +++ b/OrientDBVisualizationTool/src/main/resources/fxml/MainDesign.fxml @@ -56,8 +56,8 @@ --> - - + + diff --git a/OrientDBVisualizationTool/src/main/resources/styles/02_DarkModeStyle.css b/OrientDBVisualizationTool/src/main/resources/styles/02_DarkModeStyle.css index a91ffa6..6f3ad42 100644 --- a/OrientDBVisualizationTool/src/main/resources/styles/02_DarkModeStyle.css +++ b/OrientDBVisualizationTool/src/main/resources/styles/02_DarkModeStyle.css @@ -36,6 +36,10 @@ -fx-text-fill: white; } +.NodeLabel #NodeLabel { + -fx-fill: #000000; +} + .label { -fx-text-fill: whitesmoke; } @@ -53,9 +57,6 @@ -fx-stroke: darkgray; } -#NodeLabel { - -fx-fill: #000000; -} #Edge{ -fx-stroke: #a2a296; diff --git a/OrientDBVisualizationTool/src/main/resources/styles/05_CrimsonStyle.css b/OrientDBVisualizationTool/src/main/resources/styles/05_CrimsonStyle.css index 69c1a60..ed83992 100644 --- a/OrientDBVisualizationTool/src/main/resources/styles/05_CrimsonStyle.css +++ b/OrientDBVisualizationTool/src/main/resources/styles/05_CrimsonStyle.css @@ -19,7 +19,7 @@ } .label { - -fx-text-fill: #f6f1f1; + -fx-text-fill: #000000; } .text-input:focused { From 352494ca1cedf9405e4513f63e4ea83b883f6a54 Mon Sep 17 00:00:00 2001 From: YonaMoreda Date: Fri, 7 Jun 2019 10:31:17 +0200 Subject: [PATCH 11/22] refined the saving of theme 'about' dialog added A 'ShowMoreNode' is added to show nodes when the number of nodes is too large searching is now done onEnter other minor refactor --- ...ePrefView.java => AppearancePrefView.java} | 8 +- .../View/AspectRatio.java | 11 +++ .../orientdbvisualizationtool/View/Edge.java | 16 ---- .../View/NodeLabel.java | 1 + .../View/ShowMoreNode.java | 22 ++++++ .../orientdbvisualizationtool/View/View.java | 3 +- .../View/VisApplication.java | 8 +- .../orientdbvisualizationtool/VisTool.java | 4 +- .../CollapseButtonActionBuilder.java | 17 ++-- .../controller/MainController.java | 79 ++++++++++++------- .../controller/MainMenuController.java | 7 +- .../NodeAction/NodeMouseClickedAction.java | 43 +++++++--- .../controller/PreferencesMenuController.java | 35 ++++++-- .../model/managers/PlaceManager.java | 2 +- .../src/main/resources/fxml/MainDesign.fxml | 28 ++----- .../main/resources/fxml/PreferencesMenu.fxml | 2 +- 16 files changed, 183 insertions(+), 103 deletions(-) rename OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/{ApperancePrefView.java => AppearancePrefView.java} (72%) create mode 100644 OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/AspectRatio.java create mode 100644 OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/ShowMoreNode.java diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/ApperancePrefView.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/AppearancePrefView.java similarity index 72% rename from OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/ApperancePrefView.java rename to OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/AppearancePrefView.java index 52744be..5b849ea 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/ApperancePrefView.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/AppearancePrefView.java @@ -2,7 +2,7 @@ import com.mycompany.orientdbvisualizationtool.controller.PreferencesMenuController; -public class ApperancePrefView extends View { +public class AppearancePrefView extends View { private PreferencesMenuController controller; @@ -10,11 +10,15 @@ public class ApperancePrefView extends View { * Constructor * */ - public ApperancePrefView() { + public AppearancePrefView() { super("fxml/PreferencesMenu.fxml"); controller = fxmlLoader.getController(); } + /** + * sets the controller for the view + * @return controller + */ public PreferencesMenuController getController() { return controller; } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/AspectRatio.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/AspectRatio.java new file mode 100644 index 0000000..19e4056 --- /dev/null +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/AspectRatio.java @@ -0,0 +1,11 @@ +package com.mycompany.orientdbvisualizationtool.View; + +/** + * class for vertical and horizontal aspect ratio. + */ +public class AspectRatio { + + public static int Horizontal = 16; + public static int Vertical = 9; + +} diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Edge.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Edge.java index 9ccd841..8d886ca 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Edge.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/Edge.java @@ -56,20 +56,4 @@ public Node getFirstNode() { public Node getSecondNode() { return secondNode; } - - /** - * - * @param firstNode start node of edge line - */ - public void setFirstNode(Node firstNode) { - this.firstNode = firstNode; - } - - /** - * - * @param secondNode end node of edge line - */ - public void setSecondNode(Node secondNode) { - this.secondNode = secondNode; - } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/NodeLabel.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/NodeLabel.java index bdc480d..116e8ef 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/NodeLabel.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/NodeLabel.java @@ -12,6 +12,7 @@ public class NodeLabel extends Label { /** * constructor + * * @param displayName the string that the label displays */ public NodeLabel(String displayName) { diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/ShowMoreNode.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/ShowMoreNode.java new file mode 100644 index 0000000..13a7624 --- /dev/null +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/ShowMoreNode.java @@ -0,0 +1,22 @@ +package com.mycompany.orientdbvisualizationtool.View; + +import com.mycompany.orientdbvisualizationtool.controller.MainController; + +/** + * a special control node for showing more nodes + * used when the number of children nodes is too large + */ +public class ShowMoreNode extends Node { + + private int remainingNodes; + + /** + * Constructor + * + * @param controller main controller for node + */ + public ShowMoreNode(MainController controller, int remainingNodes) { + super("Show more node", "", "Show more(" + remainingNodes + ")", controller); + this.remainingNodes = remainingNodes; + } +} diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/View.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/View.java index d87a76b..7473865 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/View.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/View.java @@ -28,7 +28,7 @@ public View(String resource) { try { fxmlLoader = new FXMLLoader(getClass().getClassLoader().getResource(resource)); Parent root = fxmlLoader.load(); - scene = new Scene(root, WIDTH, WIDTH * 9 / 16); + scene = new Scene(root, WIDTH, WIDTH * AspectRatio.Vertical / AspectRatio.Horizontal); scene.getStylesheets().add("styles/01_DefaultStyle.css"); } catch (Exception e) { e.printStackTrace(); @@ -49,7 +49,6 @@ public static int getWIDTH() { public void start() { } - /** * * @return The scene diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java index 12af02e..3bd7a4d 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java @@ -13,7 +13,7 @@ public class VisApplication extends Application { private View mainView; private View menuView; - private ApperancePrefView appearancePrefView; + private AppearancePrefView appearancePrefView; private Stage primaryStage; private static VisApplication singletonInstance; @@ -40,7 +40,7 @@ public void startUp(Stage primaryStage) { primaryStage.setTitle("Sustainable Buildings orientDB Visualizing Tool"); mainView = new MainView(); menuView = new MainMenuView(); - appearancePrefView = new ApperancePrefView(); + appearancePrefView = new AppearancePrefView(); changeToMenu(); } @@ -51,7 +51,7 @@ public void changeToMain() { mainView.start(); primaryStage.setScene(mainView.getScene()); primaryStage.setWidth(MainView.getWIDTH()); - primaryStage.setHeight(MainView.getWIDTH() * 9 / 16); + primaryStage.setHeight(MainView.getWIDTH() * AspectRatio.Vertical / AspectRatio.Horizontal); primaryStage.centerOnScreen(); primaryStage.setResizable(true); primaryStage.show(); @@ -76,6 +76,8 @@ public void changeToPreferences() { primaryStage.setScene(appearancePrefView.getScene()); primaryStage.setWidth(600); primaryStage.setHeight(490); + primaryStage.centerOnScreen(); + primaryStage.setMaximized(false); primaryStage.setResizable(false); primaryStage.show(); } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/VisTool.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/VisTool.java index 921cbc9..3cb5f60 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/VisTool.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/VisTool.java @@ -83,8 +83,8 @@ private static void addTestPlaces(Place parent, int index) { Place newPlace = manager.addPlace(id, name, currentCategory, parent); addEntities(newPlace); - //recursvily call it for all the children - int childrenAmount = 3 + (new Random()).nextInt(5); + //recursively call it for all the children + int childrenAmount = 3 + (new Random()).nextInt(15); for (int i = 0; i < childrenAmount; i++) { addTestPlaces(newPlace, index + 1); } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonActionBuilder.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonActionBuilder.java index 3c5baff..e37bc66 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonActionBuilder.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/CollapseButtonsAction/CollapseButtonActionBuilder.java @@ -19,7 +19,7 @@ public class CollapseButtonActionBuilder { * setting the Collapse_Button * * @param collapse_button button that collapses panel - * @return + * @return builder with collapse_button */ public CollapseButtonActionBuilder setCollapse_Button(Button collapse_button) { this.collapse_button = collapse_button; @@ -30,7 +30,7 @@ public CollapseButtonActionBuilder setCollapse_Button(Button collapse_button) { * setting the split_pane * * @param split_pane container for the panel to be collapsed - * @return + * @return builder with split_pane set */ public CollapseButtonActionBuilder setSplit_Pane(SplitPane split_pane) { this.split_pane = split_pane; @@ -41,7 +41,7 @@ public CollapseButtonActionBuilder setSplit_Pane(SplitPane split_pane) { * setting collapse_anchor_pane * * @param collapse_anchor_pane the isLeft or right pane that is to be collapsed - * @return + * @return builder with collapse_anchor_pane set */ public CollapseButtonActionBuilder setCollapse_Anchor_Pane(AnchorPane collapse_anchor_pane) { this.collapse_anchor_pane = collapse_anchor_pane; @@ -53,7 +53,7 @@ public CollapseButtonActionBuilder setCollapse_Anchor_Pane(AnchorPane collapse_a * * @param center_anchor_pane the pane on the center that adjusts size accordingly to the * collapse or expansion of isLeft/right pane - * @return + * @return builder with Center_anchor_pane set */ public CollapseButtonActionBuilder setCenter_Anchor_Pane(AnchorPane center_anchor_pane) { this.center_anchor_pane = center_anchor_pane; @@ -63,8 +63,8 @@ public CollapseButtonActionBuilder setCenter_Anchor_Pane(AnchorPane center_ancho /** * setting the isLeft parameter * - * @param isLeft boolean to distinguish betten isLeft or right panel. - * @return + * @param isLeft boolean to distinguish between isLeft or right panel. + * @return setting isLeft */ public CollapseButtonActionBuilder setIsLeft(Boolean isLeft) { this.isLeft = isLeft; @@ -74,7 +74,7 @@ public CollapseButtonActionBuilder setIsLeft(Boolean isLeft) { /** * the creation of the CollapseButtonAction * - * @return + * @return a collapse button action for left/right */ public CollapseButtonAction createCollapseButtonAction() { if (isLeft) { @@ -86,6 +86,9 @@ public CollapseButtonAction createCollapseButtonAction() { } } + /** + * validates if the action built has all the required fields + */ private void validate() { if (isLeft == null) { throw new IllegalStateException("Parameter isLeft is not set and is required for build."); diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java index d66ef6f..2083dc0 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java @@ -20,6 +20,7 @@ import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.*; import javafx.scene.paint.Color; @@ -51,6 +52,7 @@ public class MainController extends ParentController { @FXML private ChoiceBox Theme_Choice_Box; @FXML private AnchorPane Center_Anchor_Pane; @FXML private TextField Location_Search; + @FXML private Button Search_Button; private ArrayList nodes; private ArrayList edges; @@ -81,7 +83,7 @@ public class MainController extends ParentController { Center_Anchor_Pane.layout(); Center_Anchor_Pane.setPrefWidth(WIDTH * .60); - Center_Anchor_Pane.setPrefHeight(WIDTH * 9 / 16); + Center_Anchor_Pane.setPrefHeight(WIDTH * AspectRatio.Vertical / AspectRatio.Horizontal); Center_Anchor_Pane.setId("Center_Anchor_Pane"); setCenterAnchorMouseProperties(); @@ -91,7 +93,8 @@ public class MainController extends ParentController { setThemeChoiceBoxProperty(); zoomFunction(); - Location_Search.textProperty().addListener((observable, oldValue, newValue) -> populateTreeView(newValue)); + Location_Search.setOnAction(event -> populateTreeView(Location_Search.getText())); + Search_Button.setOnAction(event -> populateTreeView(Location_Search.getText())); } /** @@ -205,25 +208,25 @@ public void addRootNodeToPane() { * @param node has properties to be shown. */ public void showSelectedNodeDetails(Node node) { - Place nodePlace = placeManager.getPlace(node.getNodeId()); - - //setting the text fields on right panel - Node_Name_Text_Field.setText(nodePlace.getShortName()); - Node_ID_Text_Field.setText(nodePlace.getId()); - Node_Type_Text_Field.setText(nodePlace.getType().toString()); - - //setting the status bar contents - Left_Status_Label.setTooltip(new Tooltip("Path to the currently selected place")); - Left_Status_Label.setGraphic(iconize(nodePlace.getType())); - Left_Status_Label.setText("/" + nodePlace.getPath()); - Right_Status_Label.setText(nodePlace.getChildren().size() + " | children "); - - tableViewObserveData.clear(); - PlaceManager placeManager = PlaceManager.getInstance(); - Place place = placeManager.getPlace(node.getNodeId()); - place.loadEntities(); - ArrayList placeEntities = place.getEntities(); - tableViewObserveData.addAll(placeEntities); + if (!node.getNodeId().equals("Show more node")) { + Place nodePlace = placeManager.getPlace(node.getNodeId()); + + //setting the text fields on right panel + Node_Name_Text_Field.setText(nodePlace.getShortName()); + Node_ID_Text_Field.setText(nodePlace.getId()); + Node_Type_Text_Field.setText(nodePlace.getType().toString()); + + //setting the status bar contents + Left_Status_Label.setTooltip(new Tooltip("Path to the currently selected place")); + Left_Status_Label.setGraphic(iconize(nodePlace.getType())); + Left_Status_Label.setText("/" + nodePlace.getPath()); + Right_Status_Label.setText(nodePlace.getChildren().size() + " | children "); + + tableViewObserveData.clear(); + nodePlace.loadEntities(); + ArrayList placeEntities = nodePlace.getEntities(); + tableViewObserveData.addAll(placeEntities); + } } /** @@ -246,14 +249,14 @@ public ArrayList getEdges() { * * @param sourcePlace source Place to create a parent treeView item * @param sourceItem a source treeView-item to which children treeView-items are added - * @param searchKey the string to search for + * @param searchKey the string to search for * @return source tree item populated with children tree items */ private TreeItem recursePopulateTreeView(Place sourcePlace, TreeItem sourceItem, String searchKey) { if (sourcePlace.getChildren().isEmpty()) { - if(sourcePlace.toString().toLowerCase().contains(searchKey.toLowerCase())){ + if (sourcePlace.toString().toLowerCase().contains(searchKey.toLowerCase())) { return sourceItem; - }else{ + } else { return null; } } @@ -263,12 +266,12 @@ private TreeItem recursePopulateTreeView(Place sourcePlace, TreeItem sourceItem, childItem.setExpanded(true); TreeItem children = recursePopulateTreeView(place, childItem, searchKey); - if(children != null || place.toString().toLowerCase().contains(searchKey.toLowerCase())){ + if (children != null || place.toString().toLowerCase().contains(searchKey.toLowerCase())) { sourceItem.getChildren().add(children); childItem.setGraphic(iconize(place.getType())); } } - if(sourcePlace.toString().toLowerCase().contains(searchKey.toLowerCase()) || !sourceItem.getChildren().isEmpty()){ + if (sourcePlace.toString().toLowerCase().contains(searchKey.toLowerCase()) || !sourceItem.getChildren().isEmpty()) { return sourceItem; } return null; @@ -276,6 +279,7 @@ private TreeItem recursePopulateTreeView(Place sourcePlace, TreeItem sourceItem, /** * populates the tree view with data from model + * * @param searchKey the string to search for */ public void populateTreeView(String searchKey) { @@ -335,6 +339,7 @@ public void setMouseSourceY(Double mouseSourceY) { /** * opens the preferences window + * * @param actionEvent for preferences menu item */ public void openPreferences(ActionEvent actionEvent) { @@ -343,21 +348,39 @@ public void openPreferences(ActionEvent actionEvent) { /** * select all nodes + * * @param actionEvent for select all menu item */ public void selectAllNodes(ActionEvent actionEvent) { - for(Node node : nodes) { + for (Node node : nodes) { node.setSelected(true); } } /** * unselect all nodes + * * @param actionEvent for un select all menu item */ public void unselectAllNodes(ActionEvent actionEvent) { - for(Node node : nodes) { + for (Node node : nodes) { node.setSelected(false); } } + + /** + * shows the about dialogue for the program. + * @param actionEvent for the 'About' menu item. + */ + public void showAboutVisTool(ActionEvent actionEvent) { + String aboutContent = "A tool to visualize the hierarchical data from Sustainable Buildings.\n\n" + + "Authors:\nNiels Bugel\nAlbert Dijkstra\nCarlos Isasa\nEmanuel Nae\nYona Moreda\n"; + Alert alert = new Alert(Alert.AlertType.CONFIRMATION, aboutContent, ButtonType.OK); + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + stage.getIcons().add(new Image("/icons/sb-icon.png")); + alert.setHeaderText("OrientDB Visualization Tool 2019\n"); + alert.setTitle("ABOUT"); + alert.setHeight(450); + alert.showAndWait(); + } } \ No newline at end of file diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java index b13acbd..e5da77d 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java @@ -88,18 +88,17 @@ public void showSelectedPlaceDetails(Organization nodeOrganization) { propertiesTable.addAll(nodeOrganization.getAttributes().getProperties()); } - /** * populates the tree view with data from model */ public void populateOrganizationTreeView() { Organization_Tree_View.setRoot(new TreeItem<>()); searchOrganization(""); + Organization_Search.textProperty().addListener((observable, oldValue, newValue) -> { - searchOrganization(newValue); }); - + Organization_Tree_View.getSelectionModel().selectedItemProperty() .addListener((v, oldValue, newValue) -> { if (newValue == null) { @@ -182,7 +181,7 @@ public void searchOrganization(String searchKey){ } /** - * Searches trough the locations + * Searches through the locations * @param searchKey string to search for */ public void searchLocations(String searchKey){ diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/NodeAction/NodeMouseClickedAction.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/NodeAction/NodeMouseClickedAction.java index da3cde3..30873ae 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/NodeAction/NodeMouseClickedAction.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/NodeAction/NodeMouseClickedAction.java @@ -2,6 +2,7 @@ import com.mycompany.orientdbvisualizationtool.View.Edge; import com.mycompany.orientdbvisualizationtool.View.Node; +import com.mycompany.orientdbvisualizationtool.View.ShowMoreNode; import com.mycompany.orientdbvisualizationtool.controller.MainController; import com.mycompany.orientdbvisualizationtool.model.managers.PlaceManager; import com.mycompany.orientdbvisualizationtool.model.places.Place; @@ -44,17 +45,23 @@ public NodeMouseClickedAction(Node node, MainController controller, ArrayList childrenPlaces = sourcePlace.getChildren(); + int i = 0; if (!childrenPlaces.isEmpty()) { for (Place place : childrenPlaces) { String id = place.getId(); @@ -87,6 +96,14 @@ private void expandNode(Node parentNode) { nodes.add(childNode); childrenVBox.getChildren().add(childNode.getContainerPane()); childrenVBox.layout(); + if (limit != -1 && i > limit) { + ShowMoreNode showMoreNode = new ShowMoreNode(controller, childrenPlaces.size() - i); + nodes.add(showMoreNode); + childrenVBox.getChildren().add(showMoreNode.getContainerPane()); + childrenVBox.layout(); + break; + } + i++; } } redrawEdges(parentNode); @@ -178,16 +195,22 @@ private void removeNodeAndChildren(Node node) { } /** - * Mouse click event handle for expanding/contracting node + * Mouse click event handle for expanding/contracting node to a certain expansion point * * @param event for mouse clicked */ @Override public void handle(MouseEvent event) { if (event.getButton().equals(MouseButton.PRIMARY)) { - //Double click - if (event.getClickCount() == 2) { - expandContractNode(node); + //ShowMore node is clicked + if (node.getNodeId().equals("Show more node")) { + VBox childrenVBox =(VBox) node.getContainerPane().getParent(); + Pane containerPane = (Pane) childrenVBox.getParent(); + Node showMoreParentNode = (Node) containerPane.getChildren().get(0); + expandContractNode(showMoreParentNode, -1); + } else if (event.getClickCount() == 2) { //Double click -> expand to a integer limit + int expansionLimit = 10; + expandContractNode(node, expansionLimit); } } } diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java index 588deb7..31255e7 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java @@ -12,6 +12,7 @@ import javafx.scene.paint.Color; import javafx.scene.shape.Line; import javafx.stage.FileChooser; +import javafx.stage.Stage; import javafx.stage.Window; import java.io.BufferedWriter; @@ -98,6 +99,12 @@ private void setButtonActions() { Alert alert = getAlert("Return to main application without saving?", ""); if (alert.getResult() == ButtonType.YES) { VisApplication.getInstance().changeToMain(); + } else if (alert.getResult() == ButtonType.NO) { + try { + saveThemeDialog(); + } catch (IOException e) { + e.printStackTrace(); + } } }); } @@ -148,11 +155,15 @@ private void saveThemeDialog() throws IOException { /** * shows the save confirmation dialogue * - * @param fileName file name that is saved. + * @param selectedFile file that is saved. */ - private void showSaveConfirmation(String fileName) { - Alert confirm = new Alert(Alert.AlertType.CONFIRMATION, fileName + " has been saved successfully.\n\n" + - "Theme file can be applied after application restart.", ButtonType.OK); + private void showSaveConfirmation(File selectedFile) { + Alert confirm = new Alert(Alert.AlertType.CONFIRMATION, selectedFile.getName() + " has been saved successfully.\n\n" + + selectedFile.getPath() + + "\n\nTheme file can be applied after the application is restarted.\n" + + "Program will now return to the Main Tree View.", ButtonType.OK); + confirm.setHeight(300); + setStageIcon(confirm); confirm.setHeaderText(""); confirm.setGraphic(getSBIcon()); confirm.showAndWait(); @@ -169,12 +180,22 @@ private void showSaveConfirmation(String fileName) { private Alert getAlert(String contentText, String headerText) { Alert alert = new Alert(Alert.AlertType.CONFIRMATION, contentText, ButtonType.YES, ButtonType.NO, ButtonType.CANCEL); + setStageIcon(alert); alert.setGraphic(getSBIcon()); alert.setHeaderText(headerText); alert.showAndWait(); return alert; } + /** + * sets the stage icon for an alert + * @param alert which is needs an icon + */ + private void setStageIcon(Dialog alert) { + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + stage.getIcons().add(new Image("/icons/sb-icon.png")); + } + /** * gets the text input dialogue for saving * @@ -186,6 +207,9 @@ private TextInputDialog getTextInputDialogue() { textInputDialog.setTitle("Save As"); textInputDialog.setContentText("File name: "); textInputDialog.setHeaderText("Do you want to save changes to Untitled_Theme?"); + setStageIcon(textInputDialog); + Stage stage = (Stage) textInputDialog.getDialogPane().getScene().getWindow(); + stage.getIcons().add(new Image("/icons/sb-icon.png")); return textInputDialog; } @@ -228,7 +252,8 @@ private void saveToFile(File selectedFile) throws IOException { BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(selectedFile)); bufferedWriter.write(getNewCssContent()); bufferedWriter.close(); - showSaveConfirmation(selectedFile.getName()); + showSaveConfirmation(selectedFile); + VisApplication.getInstance().changeToMain(); } /** diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/managers/PlaceManager.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/managers/PlaceManager.java index 885c109..6282db2 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/managers/PlaceManager.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/model/managers/PlaceManager.java @@ -35,7 +35,7 @@ public static PlaceManager getInstance() { } /** - * Links a child and a parent to eachother if they exist + * Links a child and a parent to each other if they exist * * @param child The child we want to link the parent to * @param parent The parent we want to link a child to diff --git a/OrientDBVisualizationTool/src/main/resources/fxml/MainDesign.fxml b/OrientDBVisualizationTool/src/main/resources/fxml/MainDesign.fxml index c46d4cf..9da2215 100644 --- a/OrientDBVisualizationTool/src/main/resources/fxml/MainDesign.fxml +++ b/OrientDBVisualizationTool/src/main/resources/fxml/MainDesign.fxml @@ -29,17 +29,7 @@ - - + @@ -49,20 +39,14 @@ - - - + + - + @@ -82,7 +66,7 @@ - - - - diff --git a/OrientDBVisualizationTool/src/main/resources/fxml/MainMenu.fxml b/OrientDBVisualizationTool/src/main/resources/fxml/MainMenu.fxml index be4240e..a7d661c 100644 --- a/OrientDBVisualizationTool/src/main/resources/fxml/MainMenu.fxml +++ b/OrientDBVisualizationTool/src/main/resources/fxml/MainMenu.fxml @@ -2,6 +2,7 @@ + @@ -107,16 +108,8 @@ - - From 25797d92bd5f2929c8d1985a387b84086ee1f47c Mon Sep 17 00:00:00 2001 From: User Date: Tue, 11 Jun 2019 18:31:11 +0200 Subject: [PATCH 17/22] updated style and added javadoc --- .../model/EntityTest.java | 31 ++- .../model/OrganizationManagerTest.java | 189 +++++++++--------- .../model/OrganizationTest.java | 99 ++++----- .../model/PlaceManagerTest.java | 29 +-- 4 files changed, 174 insertions(+), 174 deletions(-) diff --git a/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/EntityTest.java b/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/EntityTest.java index 49e4114..b58d644 100644 --- a/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/EntityTest.java +++ b/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/EntityTest.java @@ -3,17 +3,26 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; -import com.mycompany.orientdbvisualizationtool.model.Entity; +/** + * Tests the entities + * + * @author Carlos + */ public class EntityTest { - private Entity ent; - - /** - * Test for the class entity - */ - @Test - public void testEntity() { - ent = new Entity("test"); - assertEquals(ent.getId(), "test"); - } + + private Entity ent; + + /** + * Test for the class entity + */ + @Test + public void testEntity() { + ent = new Entity("test"); + assertEquals(ent.getId(), "test"); + ent = new Entity(""); + assertEquals(ent.getId(), ""); + ent = new Entity("very-long-name-let's-hope-this-also-works-with-special-characters124234534645634563456"); + assertEquals(ent.getId(), "very-long-name-let's-hope-this-also-works-with-special-characters124234534645634563456"); + } } diff --git a/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/OrganizationManagerTest.java b/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/OrganizationManagerTest.java index 6157381..78fb2b3 100644 --- a/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/OrganizationManagerTest.java +++ b/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/OrganizationManagerTest.java @@ -9,104 +9,105 @@ import org.junit.Before; import org.junit.Test; -import com.mycompany.orientdbvisualizationtool.model.Organization; import com.mycompany.orientdbvisualizationtool.model.managers.OrganizationManager; import com.mycompany.orientdbvisualizationtool.model.places.Location; public class OrganizationManagerTest { - private Organization org1; - private Organization org2; - private OrganizationManager manager; + + private Organization org1; + private Organization org2; + private OrganizationManager manager; private Location location; - - @Before - public void setUp() { - - Field instance; - try { - instance = OrganizationManager.class.getDeclaredField("singletonInstance"); - instance.setAccessible(true); - instance.set(null, null); - } catch (Exception ex) { - ex.printStackTrace(); - } - - manager = OrganizationManager.getInstance(); - - org1 = new Organization("test1"); - org2 = new Organization("test2"); - location = new Location ("L", "L"); - org1.addPlace(location); - } - - public void addAll() { - manager.addOrganization(org1); - manager.addOrganization(org2); - manager.addOrganization("test3"); - - } - /** - * Test of getInstance method, of class OrganizationManager. - */ - @Test - public void testGetInstance() { - OrganizationManager expResult = OrganizationManager.getInstance(); - OrganizationManager result = OrganizationManager.getInstance(); - assertEquals(expResult, result); - } - /** - * Test of addOrganization method, of class OrganizationManager. - */ - @Test - public void testGetOrganization() { - addAll(); - assertEquals(manager.getOrganization("test1"), org1); - } - - /** - * Test of addOrganization with Organization argument of class OrganizationManager - */ - @Test - public void testAddOrganizationOrg() { - addAll(); - assertEquals(manager.getOrganization("test2"), org2); - } - - /** - * Test of addOrganization with String argument of class OrganizationManager - */ - @Test - public void testAddOrganizationString() { - addAll(); - assertEquals(manager.getOrganization("test3").getId(), "test3"); - } - - /** - * Test of getOrganizations of class OrganizationManager - */ - @Test - public void testGetOrganizations() { - addAll(); - - List list = new ArrayList<>(); - list.add(org1); - list.add(org2); - list.add(manager.getOrganization("test3")); - - assertEquals(manager.getOrganizations(), list); - } - - /** - * Test of emptyOrganizations of class OrganizationManager - */ - @Test - public void testEmptyOrganizations() { - addAll(); - manager.emptyOrganizations(); - List emptylist = new ArrayList<>(); - assertEquals(manager.getOrganizations(), emptylist); - } - -} + @Before + public void setUp() { + + Field instance; + try { + instance = OrganizationManager.class.getDeclaredField("singletonInstance"); + instance.setAccessible(true); + instance.set(null, null); + } catch (Exception ex) { + ex.printStackTrace(); + } + + manager = OrganizationManager.getInstance(); + + org1 = new Organization("test1"); + org2 = new Organization("test2"); + location = new Location("L", "L"); + org1.addPlace(location); + } + + public void addAll() { + manager.addOrganization(org1); + manager.addOrganization(org2); + manager.addOrganization("test3"); + + } + + /** + * Test of getInstance method, of class OrganizationManager. + */ + @Test + public void testGetInstance() { + OrganizationManager expResult = OrganizationManager.getInstance(); + OrganizationManager result = OrganizationManager.getInstance(); + assertEquals(expResult, result); + } + /** + * Test of addOrganization method, of class OrganizationManager. + */ + @Test + public void testGetOrganization() { + addAll(); + assertEquals(manager.getOrganization("test1"), org1); + } + + /** + * Test of addOrganization with Organization argument of class + * OrganizationManager + */ + @Test + public void testAddOrganizationOrg() { + addAll(); + assertEquals(manager.getOrganization("test2"), org2); + } + + /** + * Test of addOrganization with String argument of class OrganizationManager + */ + @Test + public void testAddOrganizationString() { + addAll(); + assertEquals(manager.getOrganization("test3").getId(), "test3"); + } + + /** + * Test of getOrganizations of class OrganizationManager + */ + @Test + public void testGetOrganizations() { + addAll(); + + List list = new ArrayList<>(); + list.add(org1); + list.add(org2); + list.add(manager.getOrganization("test3")); + + assertEquals(manager.getOrganizations(), list); + } + + /** + * Test of emptyOrganizations of class OrganizationManager + */ + @Test + public void testEmptyOrganizations() { + addAll(); + manager.emptyOrganizations(); + List emptylist = new ArrayList<>(); + assertEquals(manager.getOrganizations(), emptylist); + } + +} diff --git a/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/OrganizationTest.java b/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/OrganizationTest.java index 3a1411f..76d41eb 100644 --- a/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/OrganizationTest.java +++ b/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/OrganizationTest.java @@ -11,52 +11,57 @@ import com.mycompany.orientdbvisualizationtool.model.places.Location; import com.mycompany.orientdbvisualizationtool.model.places.Place; +/** + * Tests for the organization + * + * @author Carlos + */ public class OrganizationTest { - private Organization org; - private Location test1; - private Location test2; - private List list; - - - @Before - public void setUp() { - org = new Organization("test"); - test1 = new Location("L", "L"); - test2 = new Location("L2", "L2"); - list = new ArrayList<>(); - } - - public void addAll() { - org.addPlace(test1); - org.addPlace(test2); - list.add(test1); - list.add(test2); - } - - /** - * Test for the getId method of class Organization - */ - @Test - public void testGetId() { - assertEquals(org.getId(), "test"); - } - - /** - * Test for the addPlace and getPlaces methods of class Organization - */ - @Test - public void testAddGetPlace() { - addAll(); - assertEquals(org.getPlaces(),list); - } - - /** - * Test for the dereferenceAll method of class Organization - */ - @Test - public void testDereferenceAll() { - addAll(); - org.dereferenceAll(); - assertEquals(org.getPlaces(), null); - } + + private Organization org; + private Location test1; + private Location test2; + private List list; + + @Before + public void setUp() { + org = new Organization("test"); + test1 = new Location("L", "L"); + test2 = new Location("L2", "L2"); + list = new ArrayList<>(); + } + + public void addAll() { + org.addPlace(test1); + org.addPlace(test2); + list.add(test1); + list.add(test2); + } + + /** + * Test for the getId method of class Organization + */ + @Test + public void testGetId() { + assertEquals(org.getId(), "test"); + } + + /** + * Test for the addPlace and getPlaces methods of class Organization + */ + @Test + public void testAddGetPlace() { + addAll(); + assertEquals(org.getPlaces(), list); + } + + /** + * Test for the dereferenceAll method of class Organization + */ + @Test + public void testDereferenceAll() { + addAll(); + org.dereferenceAll(); + assertEquals(org.getPlaces(), null); + } } diff --git a/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/PlaceManagerTest.java b/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/PlaceManagerTest.java index bf2eaaa..7b1073b 100644 --- a/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/PlaceManagerTest.java +++ b/OrientDBVisualizationTool/src/test/java/com/mycompany/orientdbvisualizationtool/model/PlaceManagerTest.java @@ -3,15 +3,13 @@ import com.mycompany.orientdbvisualizationtool.model.managers.PlaceManager; import com.mycompany.orientdbvisualizationtool.model.places.*; import java.lang.reflect.Field; -import org.junit.After; -import org.junit.AfterClass; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** - * + * Tests for placeManager + * * @author Niels */ public class PlaceManagerTest { @@ -34,18 +32,9 @@ public class PlaceManagerTest { private Room roomBBA; private Room roomBBB; - public PlaceManagerTest() { - } - - @BeforeClass - public static void setUpClass() { - - } - - @AfterClass - public static void tearDownClass() { - } - + /** + * Initialises all the fields + */ @Before public void setUp() { @@ -56,7 +45,7 @@ public void setUp() { instance.set(null, null); } catch (Exception ex) { ex.printStackTrace(); - } + } manager = PlaceManager.getInstance(); @@ -77,10 +66,6 @@ public void setUp() { roomBBB = new Room("L.B.B.B", "BBB"); } - @After - public void tearDown() { - } - /** * links all the test classes */ @@ -157,7 +142,7 @@ public void testAddPlace_Place_Place() { assertEquals(manager.getPlace(buildingA.getId()), buildingA); assertNull(buildingA.getParent()); - + manager.addPlace(floorAA, null); manager.addPlace(roomAAB, floorAA); assertEquals(manager.getPlace(floorAA.getId()), floorAA); From 1a121c3adb0bb9e76a067a5355aba06b5c0ef266 Mon Sep 17 00:00:00 2001 From: User Date: Tue, 11 Jun 2019 19:06:32 +0200 Subject: [PATCH 18/22] fixed stylesheets changing fixed bug, where cancelling custom css theme would crash the program --- .../View/VisApplication.java | 5 +++++ .../controller/MainController.java | 2 +- .../controller/MainMenuController.java | 4 ++-- .../controller/PreferencesMenuController.java | 2 +- .../ThemeChoiceAction/ThemeChoiceBoxAction.java | 13 ++++++------- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java index 3bd7a4d..2430b64 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/View/VisApplication.java @@ -1,6 +1,7 @@ package com.mycompany.orientdbvisualizationtool.View; import javafx.application.Application; +import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; @@ -66,6 +67,10 @@ public void changeToMenu() { primaryStage.setResizable(true); primaryStage.show(); } + + public Scene getScene() { + return primaryStage.getScene(); + } /** * switches to preferences diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java index c21ab5b..7ad4bd9 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainController.java @@ -149,7 +149,7 @@ private void setCollapseButtons() { * Setting the check choice box property to enable different themes */ private void setThemeChoiceBoxProperty() { - Theme_Choice_Box.getSelectionModel().selectedIndexProperty().addListener(new ThemeChoiceBoxAction(Center_Anchor_Pane, Theme_Choice_Box)); + Theme_Choice_Box.getSelectionModel().selectedIndexProperty().addListener(new ThemeChoiceBoxAction(Theme_Choice_Box)); } /** diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java index d2776e1..32cc33b 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/MainMenuController.java @@ -76,13 +76,13 @@ public void initialize() { organizationManager = OrganizationManager.getInstance(); initLocationTreeView(); populateOrganizationTreeView(); + setThemeChoiceBoxProperty(); Properties_Table.setPrefWidth(240); Properties_Table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); Table_View_PropertyKey.setCellValueFactory(new PropertyValueFactory("key")); Table_View_PropertyValue.setCellValueFactory(new PropertyValueFactory("value")); Properties_Table.setItems(propertiesTable); - setThemeChoiceBoxProperty(); } /** @@ -119,7 +119,7 @@ public void showSelectedPlaceDetails(Organization nodeOrganization) { * Setting the check choice box property to enable different themes */ private void setThemeChoiceBoxProperty() { - Theme_Choice_Box.getSelectionModel().selectedIndexProperty().addListener(new ThemeChoiceBoxAction(null, Theme_Choice_Box)); + Theme_Choice_Box.getSelectionModel().selectedIndexProperty().addListener(new ThemeChoiceBoxAction(Theme_Choice_Box)); } /** diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java index 9f4e514..c82cfdd 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/PreferencesMenuController.java @@ -137,7 +137,7 @@ private void setButtonActions() { Cancel_Button.setOnAction(event -> { Alert alert = getAlert("Return to main application without saving?", ""); if (alert.getResult() == ButtonType.YES) { - VisApplication.getInstance().changeToMain(); + VisApplication.getInstance().changeToMenu(); } else if (alert.getResult() == ButtonType.NO) { try { saveThemeDialog(); diff --git a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/ThemeChoiceAction/ThemeChoiceBoxAction.java b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/ThemeChoiceAction/ThemeChoiceBoxAction.java index f36bcc0..6a0c9f0 100644 --- a/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/ThemeChoiceAction/ThemeChoiceBoxAction.java +++ b/OrientDBVisualizationTool/src/main/java/com/mycompany/orientdbvisualizationtool/controller/ThemeChoiceAction/ThemeChoiceBoxAction.java @@ -1,30 +1,28 @@ package com.mycompany.orientdbvisualizationtool.controller.ThemeChoiceAction; +import com.mycompany.orientdbvisualizationtool.View.View; import com.mycompany.orientdbvisualizationtool.View.VisApplication; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.scene.control.ChoiceBox; -import javafx.scene.layout.AnchorPane; import java.io.File; import java.util.Objects; +import javafx.scene.Scene; /** * Action taken when theme choice box is used/clicked. */ public class ThemeChoiceBoxAction implements ChangeListener { - private AnchorPane Center_Anchor_Pane; private ChoiceBox Theme_Choice_Box; /** * constructor * - * @param Center_Anchor_Pane anchor pane to which theme adjustments are made to. * @param Theme_Choice_Box choice box that contains options for different themes. */ - public ThemeChoiceBoxAction(AnchorPane Center_Anchor_Pane, ChoiceBox Theme_Choice_Box) { - this.Center_Anchor_Pane = Center_Anchor_Pane; + public ThemeChoiceBoxAction(ChoiceBox Theme_Choice_Box) { this.Theme_Choice_Box = Theme_Choice_Box; setThemeChoiceBoxProperty(); } @@ -48,8 +46,9 @@ private void setThemeChoiceBoxProperty() { public void changed(ObservableValue observable, Number oldValue, Number newValue) { if (newValue.intValue() != 5) { File folder = new File(getClass().getResource("/styles").getPath()); - Center_Anchor_Pane.getScene().getStylesheets().remove("styles/" + Objects.requireNonNull(folder.listFiles())[oldValue.intValue()].getName()); - Center_Anchor_Pane.getScene().getStylesheets().add("styles/" + Objects.requireNonNull(folder.listFiles())[newValue.intValue()].getName()); + Scene currentScene = VisApplication.getInstance().getScene(); + currentScene.getStylesheets().remove("styles/" + Objects.requireNonNull(folder.listFiles())[oldValue.intValue()].getName()); + currentScene.getStylesheets().add("styles/" + Objects.requireNonNull(folder.listFiles())[newValue.intValue()].getName()); } else { VisApplication.getInstance().changeToPreferences(); } From 9686990aacf3fd14c56965637af7bfdea5cebf71 Mon Sep 17 00:00:00 2001 From: YonaBMoreda <38438356+YonaBMoreda@users.noreply.github.com> Date: Tue, 11 Jun 2019 21:01:49 +0200 Subject: [PATCH 19/22] Delete vcs.xml --- .idea/vcs.xml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 00baef96169ea92a97ad2267c808f234e97d2eb2 Mon Sep 17 00:00:00 2001 From: Emanuel Nae Date: Tue, 11 Jun 2019 22:22:35 +0200 Subject: [PATCH 20/22] Update EmanuelNae.txt --- TimeTracking/EmanuelNae.txt | 78 +++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/TimeTracking/EmanuelNae.txt b/TimeTracking/EmanuelNae.txt index 94301bc..ad38df1 100644 --- a/TimeTracking/EmanuelNae.txt +++ b/TimeTracking/EmanuelNae.txt @@ -80,3 +80,81 @@ 01/04 - slides presentation 01/04 - try solve issues 01/04 - hand in +02/04 - presentation preparation +02/04 - presentation preparation +02/04 - presentation preparation +02/04 - presentation preparation +03/04 - presentation preparation +03/04 - presentation preparation +03/04 - presentation +03/04 - presentation +07/04 - tree view bugs +07/04 - tree view bugs +07/04 - tree view bugs +07/04 - tree view bugs +07/04 - tree view bugs +07/04 - tree view bugs +12/04 - meeting +12/04 - meeting +14/04 - client +14/04 - client +18/04 - meeting +18/04 - meeting +20/04 - dependencies +20/04 - dependencies +20/04 - dependencies +20/04 - dependencies +22/04 - fix Intellij +22/04 - fix Intellij +22/04 - fix Intellij +22/04 - fix Intellij +22/04 - fix Intellij +22/04 - fix Intellij +25/04 - meeting +25/04 - meeting +26/04 - docs +26/04 - docs +02/05 - layout +02/05 - layout +02/05 - layout +02/05 - layout +02/05 - layout +02/05 - layout +06/05 - client +06/05 - client +14/05 - docs +14/05 - docs +14/05 - docs +14/05 - docs +18/05 - refactoring +18/05 - refactoring +18/05 - refactoring +18/05 - refactoring +18/05 - refactoring +18/05 - refactoring +24/05 - docs +24/05 - docs +24/05 - docs +24/05 - docs +25/05 - diagrams +25/05 - diagrams +25/05 - diagrams +25/05 - diagrams +25/05 - diagrams +25/05 - diagrams +01/06 - slides +01/06 - slides +01/06 - slides +01/06 - slides +01/06 - slides +01/06 - slides +03/06 - slides +03/06 - slides +04/06 - presentation doc +04/06 - presentation doc +04/06 - presentation meeting +04/06 - presentation meeting +05/06 - presentations +05/06 - presentations +05/06 - presentations +05/06 - presentations From 8b489b13b8ccc6dd5b742aaca507d61c27b9ecc7 Mon Sep 17 00:00:00 2001 From: YonaBMoreda <38438356+YonaBMoreda@users.noreply.github.com> Date: Wed, 12 Jun 2019 12:48:50 +0200 Subject: [PATCH 21/22] Add files via upload --- Architecture_Document.pdf | Bin 1727685 -> 1754916 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Architecture_Document.pdf b/Architecture_Document.pdf index a26b8ca80386f6b77e19eb948883992660cb993e..12cee9f0e68134625b2491f766e4c2985bef2f2a 100644 GIT binary patch delta 70754 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 z zp%bYpGyK==Z-o+vx{;T+#3*kB7l~dxj+*MALz?3iTb?|hzr-p{?6knnk7M?a6&wlG z_7T9~)2RsVdcN3ss`*)fH-UCYk>%JqaUv?@q20Umio4eKl`f40&+aJhR zMX5$=`xQ--1e?~obMVh|3okGnXdn1yHrGfQ2j$$eF&|GJZewcAz z`L4q3(1}BeqlrxbeuFwPLGB^EpCpAf=TTg^W1f2IV-wbS*O zUF*INO^H#XP936Tiji1LWZlCSLI9dwOO6MYoMTK~1*>zBI`a;TmGSvBCi`o+X{Ms3E`;^Q0KqN}JO8&aXsuav=gSD(wfuSVOi&UEtW z7h6&@{8;V`R>za--Ssbh+w!&|kTWq?@TBJx@QufBFZ$dGv$<7DIeX zXT@mOaI&84TEVdR+sqktlUl{+%$(2ZXAC=Y~_Jr z^1oHjFWc@BGWjX1Re^ea9pL`fxmv1!WyEOOJLlo!!)paK!|ZZ0lAZJzj1gqQ*6$7O zpEP&|0{akvkH;nMe{bp=={YU#YnT4D|FWy_HY~AXrd3IV5hv`0*{zRXt91$;jO+*#E#5>d&dFuS4 zFlFldk(WvGqx_d0hn0es-oa0ICQem7TPK(X>*h-|j!?n(e{b<|x#v#^*;Wc=RIU_{ zTVKhU**)}Zjb}}f!m#efo{^!W%phJ&E(m1H#CB z@ode$4NJp!r6L_9b1ZiYD5j8Orn7?eYW7Z3CBGKX;D%W#_EMm6v2V;vazN$jbM8=x zW`IqQ5UDffe_ss$NPD0;95Y(c5k5#lpF|KCh%+hDcWXEk`c^ZcyWLo-2le%a3p0(4 z{=h7eCLpq13evR_p1Ui5cX{kg!%Jyz%w%AP%e!*?!12IR^%29JxKxKC#9rV@fZCX7 z?cOtH=5~TIPwZN}tG`1KvIQQ++9KWCeIIzT7~YpJe}Bv0v$`df6**ymoM?#? zj*@ReuGAy>q#MM`CPYf$*b=_VAoyiGN?mFoC#vhd#{$Hb-=bs}zE3clpvmtq(W3{c z^m4>we?K<3jK%v<2{eHhihNkhNm4UF=g{4>NY5&{k>dGohyW|snLvGoun;AV-}$Xz zeZez5Zn}psRJGvEaI|7AZy#}}*mBxuBc6TIG>sin3x;`Nt$sW^hLA{e-C6ZIZPT(< z!IO+iZQuu@)p_$=StbE0Dj#{PKJ4Ci%xkIWe;$XFz%K;(BQ?dw`g1wok!KZf@=gKMo`3OSx`g?xRd>L8@|@(PG!eXlQ*$m*v{K; zf4W9JZ?FNu33I;cnj)oJ2wo_E8HwH@60y|Pg&Of%Y@oB_5^SDW1HP@o2v)beeuK_w z^bB{A4Y!XsMCV#lz@XgD;N{JzSq?$2JTRJ3vkue|}txn7kYkEe3z5kJQI==FW-?j9;Z~%%W=J z!-2h1P?d(DtaW&!)348ZWCFNIikt-3F5)aE1ir64t#C$#P(PL}hiza+ahsT5;Nw*{ zu5O$<**8-}W+TXO`!rN;D3q=v2XM_NL9%UTnFwS{t-WMkztVu5$8*cS)-#Ogf87ZN z>`i4)MeksMU<|STh^{M>f<+7zhL0E-BrVg>pQ)0-fDwxIF=51%R7}9R;$7u|N`7+o z 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�p~^9?@U_ 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

YV4j-H5^%s?S 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 WoQN>{Z~zL!R1VlqDAoum!T$hv=`H^N From 86f22512f383ee1d62ce1b94ea743458ca50fa0e Mon Sep 17 00:00:00 2001 From: YonaBMoreda <38438356+YonaBMoreda@users.noreply.github.com> Date: Wed, 12 Jun 2019 12:50:59 +0200 Subject: [PATCH 22/22] Add files via upload --- Requirements_document.pdf | Bin 105242 -> 105354 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Requirements_document.pdf b/Requirements_document.pdf index c3850039ae25eb0a96afdefed541a48c1d3d0970..eac5636ebcaca4658d1a1e0b5c849488249b7a8f 100644 GIT binary patch delta 2764 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