├── .gitignore ├── LICENSE.md ├── README.md ├── ea └── ObjectGraphVisualization.eap ├── examples ├── ClubSchool.ogv ├── Inheritance.ogv ├── SkipList.ogv ├── WebShop.eap ├── WebShop.xml ├── WeltraumStaffel.eap ├── WeltraumStaffel.ogv └── WeltraumStaffel.xml ├── lib ├── fxyzlib-0.3.0-patched.jar └── objmodelimporterjfx-0.8.jar ├── pom.xml └── src ├── main ├── java │ └── ch │ │ └── hsr │ │ └── ogv │ │ ├── Main.java │ │ ├── MainApp.java │ │ ├── StageBuilder.java │ │ ├── controller │ │ ├── CameraBase.java │ │ ├── CameraController.java │ │ ├── ContextMenuController.java │ │ ├── DragController.java │ │ ├── DragMoveController.java │ │ ├── DragResizeController.java │ │ ├── ModelController.java │ │ ├── ModelViewConnector.java │ │ ├── MouseMoveController.java │ │ ├── ObjectGraph.java │ │ ├── ObjectGraphCollector.java │ │ ├── QuickCreationController.java │ │ ├── RelationCreationController.java │ │ ├── RotationCamera.java │ │ ├── SelectionController.java │ │ ├── TextFieldController.java │ │ └── ViewController.java │ │ ├── dataaccess │ │ ├── ColorAdapter.java │ │ ├── ImportCallback.java │ │ ├── LoadCallback.java │ │ ├── OGVPoint3D.java │ │ ├── OGVSerialization.java │ │ ├── Persistence.java │ │ ├── PersistenceCallback.java │ │ ├── Point3DAdapter.java │ │ ├── SaveCallback.java │ │ ├── SerializationStrategy.java │ │ ├── UserPreferences.java │ │ ├── VersionHandler.java │ │ ├── XMIHandler.java │ │ ├── XMIRelation.java │ │ ├── XMISerialization.java │ │ └── XMI_1_1.java │ │ ├── model │ │ ├── Attribute.java │ │ ├── Endpoint.java │ │ ├── EndpointType.java │ │ ├── LineType.java │ │ ├── ModelBox.java │ │ ├── ModelClass.java │ │ ├── ModelManager.java │ │ ├── ModelObject.java │ │ ├── Relation.java │ │ └── RelationType.java │ │ ├── util │ │ ├── ColorUtil.java │ │ ├── FXMLResourceUtil.java │ │ ├── GeometryUtil.java │ │ ├── MessageBar.java │ │ ├── MultiplicityParser.java │ │ ├── ObjModelLoader.java │ │ ├── ResourceLocator.java │ │ └── TextUtil.java │ │ └── view │ │ ├── Arrow.java │ │ ├── ArrowEdge.java │ │ ├── ArrowLabel.java │ │ ├── ArrowSelection.java │ │ ├── Axis.java │ │ ├── BoxSelection.java │ │ ├── ConnectorBox.java │ │ ├── Cuboid.java │ │ ├── CylinderAdapter.java │ │ ├── DashedArrow.java │ │ ├── Floor.java │ │ ├── PaneBox.java │ │ ├── ReflexiveArrow.java │ │ ├── Selectable.java │ │ ├── SphereAdapter.java │ │ ├── SubSceneAdapter.java │ │ ├── SubSceneCamera.java │ │ ├── TSplitMenuButton.java │ │ ├── VerticalHelper.java │ │ └── Xform.java └── resources │ ├── META-INF │ └── MANIFEST.MF │ ├── css │ ├── Scene.css │ ├── TSplitMenuButton.css │ ├── TextInput.css │ └── TextInputSmall.css │ ├── fonts │ ├── LUCIDASANSREGULAR.TTF │ └── SEGOEUI.TTF │ ├── images │ ├── OGV.gif │ ├── OGV.hqx │ ├── OGV.icns │ ├── OGV.ico │ ├── OGV.png │ ├── OGV.xcf │ ├── OGV.zip │ └── menu │ │ ├── ActivityClassDiagram.gif │ │ ├── ColRole.gif │ │ ├── aggregation.gif │ │ ├── aggregationToNavi.gif │ │ ├── application-import.png │ │ ├── artifactPrj.gif │ │ ├── assoNavToNav.gif │ │ ├── assoWithNav.gif │ │ ├── assoc.gif │ │ ├── associationClass.gif │ │ ├── bullet_arrow_down.png │ │ ├── bullet_arrow_up.png │ │ ├── close.png │ │ ├── composite.gif │ │ ├── compositeToNavi.gif │ │ ├── depend.gif │ │ ├── error.png │ │ ├── general.gif │ │ ├── help.png │ │ ├── info.png │ │ ├── instance.gif │ │ ├── message_default.png │ │ ├── message_error.png │ │ ├── message_info.png │ │ ├── message_warn.png │ │ ├── mm_pc_fd.gif │ │ ├── multiplicity.gif │ │ ├── new.gif │ │ ├── open.gif │ │ ├── relation.gif │ │ ├── rightAngleOff.gif │ │ ├── structureclass.gif │ │ ├── synchronize_dgm_tab.gif │ │ ├── testcase.gif │ │ ├── text_box2.gif │ │ ├── trash.png │ │ └── unused │ │ ├── add.gif │ │ ├── arrow-down-01-16.png │ │ ├── arrow-up-01-16.png │ │ ├── artifact.gif │ │ ├── close_button.gif │ │ ├── close_button.png │ │ ├── close_button_rollover.gif │ │ ├── delSelect.gif │ │ ├── mm_arrow_triangle_down.png │ │ ├── mm_arrow_triangle_up.png │ │ ├── setcolor.gif │ │ └── warn.png │ ├── log4j2.properties │ ├── models │ ├── arc.mtl │ ├── arc.obj │ ├── empty_arrow.mtl │ ├── empty_arrow.obj │ ├── empty_diamond.mtl │ ├── empty_diamond.obj │ ├── filled_arrow.mtl │ ├── filled_arrow.obj │ ├── filled_diamond.mtl │ ├── filled_diamond.obj │ ├── open_arrow.mtl │ └── open_arrow.obj │ └── templates │ ├── ArrowTextField.fxml │ ├── CenterTextField.fxml │ ├── PanePreset.fxml │ ├── RootLayout.fxml │ └── TopTextField.fxml └── test └── java └── ch └── hsr └── ogv ├── model ├── EndpointTest.java ├── ModelBoxTest.java ├── ModelClassTest.java ├── ModelManagerTest.java ├── ModelObjectTest.java └── RelationTest.java └── util ├── GeometryUtilTest.java ├── MultiplicityParserTest.java └── TextUtilTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | !*.obj 2 | 3 | *.class 4 | 5 | # Mobile Tools for Java (J2ME) 6 | .mtj.tmp/ 7 | 8 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 9 | hs_err_pid* 10 | 11 | .metadata 12 | .gradle 13 | bin/ 14 | logs/ 15 | target/ 16 | tmp/ 17 | *.tmp 18 | *.bak 19 | *.swp 20 | *~.nib 21 | local.properties 22 | .settings/ 23 | .loadpath 24 | 25 | # Eclipse Core 26 | .project 27 | 28 | # External tool builders 29 | .externalToolBuilders/ 30 | 31 | # Locally stored "Eclipse launch configurations" 32 | *.launch 33 | 34 | # CDT-specific 35 | .cproject 36 | 37 | # JDT-specific (Eclipse Java Development Tools) 38 | .classpath 39 | 40 | # PDT-specific 41 | .buildpath 42 | 43 | # sbteclipse plugin 44 | .target 45 | 46 | # TeXlipse plugin 47 | .texlipse 48 | 49 | *.DS_Store 50 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Simon Gwerder, Adrian Rieser, Thomas Letsch 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Object Graph Visualizer v.3.1 2 | 3 | ![alt tag](https://github.com/Nurtak/ObjectGraphVisualization/blob/master/src/main/resources/images/OGV.png?raw=true) 4 | 5 | ## Description 6 | Object Graph Visualizer is a tool primarily meant to be used in CS courses to help new students understand the Object Oriented paradigm and patterns. Classes and objects - that can be part of a software project - are visualised in 3D: The classes stay In the xz-plane in form of an UML class diagram. Directly above in the y-axis objects can be instantiated as an object diagram. Classes can be connected with all sorts of relations (Associations, Compositions, Generalization, etc.), objects with object relations. 7 | Following additional functionality is provided: Attributes, Mulitplicities, Roles, Object Graph Mode, Coloring, Save and Load, XMI 1.1 Import from Enterprise Architect, Associations (undirected, directed, bidirected), Aggregations, Compositions, Dependency, Generalization, Multiple Virtual Inheritance 8 | 9 | Developer Addendum: It shouldn't be too difficult to add an API for remote application control, e.g. visualize and debug a running programm. See class "ModelViewConnector". Any Contribution is welcome. 10 | 11 | ## Features 12 | * Use Case: Educational, Software Engineering, UML 13 | * 3D Visualization 14 | * Save / Load Project 15 | * XMI Import (Enterprise Architect XMI v.1.1) 16 | * Create Class Diagramm 17 | * Create Object Diagramm 18 | * View Object Graph 19 | * Add / Edit / Remove Classes, Objects, Relations, Attributes, Values, Multiplicities, Roles, ... 20 | * Simulate Inheritance (virtual multiple) 21 | * Free camera placement (rotational) 22 | * Choose color for Classes, Objects, Relations, Background 23 | * OS: Windows, Mac, Linux 24 | * Runtime: Java 8u45 25 | * Paradigm: Object Oriented Programming 26 | 27 | ## Release 28 | [Object Graph Visualizer Version 3.1](https://github.com/Nurtak/ObjectGraphVisualization/releases) 29 | 30 | The Java Runnable requires [Java 8u45]( https://www.java.com/de/download/). 31 | The Windows Installer and Standalone come prepacked with the runtime. 32 | More information and installation can be found in the [Instruction Manual](https://github.com/Nurtak/ObjectGraphVisualization/releases/download/v3.1/Instruction.Manual.pdf). 33 | 34 | In depth thesis is available in German: http://eprints.hsr.ch/459/ 35 | 36 | ## Screenshots 37 | ![alt tag](https://a.fsdn.com/con/app/proj/ogvisualizer/screenshots/screenshot1.PNG) 38 | 39 | ![alt tag](https://a.fsdn.com/con/app/proj/ogvisualizer/screenshots/screenshot2.PNG) 40 | 41 | ![alt tag](https://a.fsdn.com/con/app/proj/ogvisualizer/screenshots/screenshot3.PNG) 42 | -------------------------------------------------------------------------------- /ea/ObjectGraphVisualization.eap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/ea/ObjectGraphVisualization.eap -------------------------------------------------------------------------------- /examples/WebShop.eap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/examples/WebShop.eap -------------------------------------------------------------------------------- /examples/WeltraumStaffel.eap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/examples/WeltraumStaffel.eap -------------------------------------------------------------------------------- /lib/fxyzlib-0.3.0-patched.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/lib/fxyzlib-0.3.0-patched.jar -------------------------------------------------------------------------------- /lib/objmodelimporterjfx-0.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/lib/objmodelimporterjfx-0.8.jar -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/Main.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv; 2 | 3 | /** 4 | * Starts the application. 5 | */ 6 | public class Main { 7 | 8 | public static void main(String[] args) { 9 | MainApp.main(args); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/MainApp.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv; 2 | 3 | import ch.hsr.ogv.util.ResourceLocator; 4 | import ch.hsr.ogv.util.ResourceLocator.Resource; 5 | import javafx.application.Application; 6 | import javafx.scene.text.Font; 7 | import javafx.stage.Stage; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.lang.Thread.UncaughtExceptionHandler; 12 | import java.util.Locale; 13 | 14 | /** 15 | * Starts the FX application. 16 | */ 17 | public class MainApp extends Application { 18 | 19 | private final static Logger logger = LoggerFactory.getLogger(MainApp.class); 20 | 21 | private final static UncaughtExceptionHandler ueHandler = (thread, throwable) -> { 22 | logger.debug("Error in thread " + thread + ": " + throwable.getMessage()); 23 | throwable.printStackTrace(); 24 | }; 25 | 26 | public static void main(String[] args) { 27 | // System.setProperty("prism.lcdtext", "false"); 28 | // System.setProperty("prism.text", "t2k"); 29 | // System.setProperty("prism.marlin", "true"); 30 | Locale.setDefault(new Locale("en", "EN")); // set to English 31 | Font.loadFont(ResourceLocator.getResourcePath(Resource.SEGOEUI_TTF).toExternalForm(), Font.getDefault().getSize()); 32 | Font.loadFont(ResourceLocator.getResourcePath(Resource.LUCIDASANS_TTF).toExternalForm(), Font.getDefault().getSize()); 33 | Thread.setDefaultUncaughtExceptionHandler(ueHandler); 34 | launch(args); 35 | } 36 | 37 | @Override 38 | public void start(Stage primaryStage) { 39 | Thread.currentThread().setUncaughtExceptionHandler(ueHandler); 40 | new StageBuilder(primaryStage); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/controller/CameraBase.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.controller; 2 | 3 | import ch.hsr.ogv.view.SubSceneAdapter; 4 | 5 | public abstract class CameraBase { 6 | 7 | protected static final double MODIFIER = 2; 8 | protected static final double MODIFIER_FACTOR = 0.1; 9 | protected static final double CONTROL_MULTIPLIER = 1; 10 | protected static final double SHIFT_MULTIPLIER = 10; 11 | protected double mousePosX; 12 | protected double mousePosY; 13 | protected double mouseOldX; 14 | protected double mouseOldY; 15 | protected double mouseDeltaX; 16 | protected double mouseDeltaY; 17 | 18 | protected volatile boolean moveCamera = true; 19 | protected volatile boolean lockedTopView = false; 20 | 21 | public void setMoveCamera(boolean moveCamera) { 22 | this.moveCamera = moveCamera; 23 | } 24 | 25 | public void setLockedTopView(boolean lockedTopView) { 26 | this.lockedTopView = lockedTopView; 27 | } 28 | 29 | protected abstract void handleMouse(SubSceneAdapter subSceneAdapter); 30 | 31 | protected abstract void handleKeyboard(SubSceneAdapter subSceneAdapter); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/controller/CameraController.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.controller; 2 | 3 | import ch.hsr.ogv.view.SubSceneAdapter; 4 | import ch.hsr.ogv.view.SubSceneCamera; 5 | import ch.hsr.ogv.view.Xform; 6 | 7 | import java.util.Observable; 8 | import java.util.Observer; 9 | 10 | public class CameraController implements Observer { 11 | 12 | private RotationCamera rotationCamera = new RotationCamera(); 13 | 14 | private CameraBase baseCamera = rotationCamera; 15 | 16 | public void setLockedTopView(boolean lockedTopView) { 17 | this.rotationCamera.setLockedTopView(lockedTopView); 18 | } 19 | 20 | public void setMoveCamera(boolean moveCamera) { 21 | this.rotationCamera.setMoveCamera(moveCamera); 22 | } 23 | 24 | public CameraBase getBaseCamera() { 25 | return baseCamera; 26 | } 27 | 28 | public void handleCenterView(SubSceneCamera ssCamera) { 29 | Xform cameraXform = ssCamera.getCameraXform(); 30 | Xform cameraXform2 = ssCamera.getCameraXform2(); 31 | cameraXform.ry.setAngle(0.0); 32 | cameraXform.rx.setAngle(90.0); 33 | cameraXform2.t.setX(0.0); 34 | cameraXform2.t.setY(0.0); 35 | ssCamera.get().setTranslateZ(-SubSceneCamera.CAMERA_DISTANCE); 36 | } 37 | 38 | public void handleLockedTopView(SubSceneCamera ssCamera, boolean isLockedTopView) { 39 | Xform cameraXform = ssCamera.getCameraXform(); 40 | if (isLockedTopView) { 41 | cameraXform.ry.setAngle(0.0); 42 | cameraXform.rx.setAngle(90.0); 43 | } 44 | else { 45 | cameraXform.ry.setAngle(320.0); 46 | cameraXform.rx.setAngle(40.0); 47 | } 48 | setLockedTopView(isLockedTopView); 49 | } 50 | 51 | public void enableCamera(SubSceneAdapter subSceneAdapter) { 52 | baseCamera.handleMouse(subSceneAdapter); 53 | baseCamera.handleKeyboard(subSceneAdapter); 54 | } 55 | 56 | @Override 57 | public void update(Observable o, Object arg) { 58 | if (o instanceof DragController) { 59 | DragController dragController = (DragController) o; 60 | setMoveCamera(!dragController.isDragInProgress()); 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/controller/DragController.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.controller; 2 | 3 | import ch.hsr.ogv.view.PaneBox; 4 | import ch.hsr.ogv.view.SubSceneAdapter; 5 | import javafx.scene.Cursor; 6 | import javafx.scene.Group; 7 | import javafx.scene.input.MouseEvent; 8 | 9 | import java.util.Observable; 10 | 11 | public abstract class DragController extends Observable { 12 | 13 | private volatile PaneBox selected = null; 14 | private volatile boolean dragInProgress = false; 15 | 16 | protected void endOnMouseReleased(Group g, PaneBox paneBox, SubSceneAdapter subSceneAdapter) { 17 | g.setOnMouseReleased((MouseEvent me) -> { 18 | setDragInProgress(subSceneAdapter, false); 19 | subSceneAdapter.getVerticalHelper().setVisible(false); 20 | paneBox.get().toBack(); 21 | subSceneAdapter.getSubScene().setCursor(Cursor.DEFAULT); 22 | }); 23 | } 24 | 25 | protected void setDragInProgress(SubSceneAdapter subSceneAdapter, boolean value) { 26 | this.dragInProgress = value; 27 | if (value) { 28 | subSceneAdapter.worldRestrictMouseEvents(); 29 | subSceneAdapter.receiveMouseEvents(subSceneAdapter.getFloor(), subSceneAdapter.getVerticalHelper()); 30 | } 31 | else { 32 | subSceneAdapter.worldReceiveMouseEvents(); 33 | subSceneAdapter.restrictMouseEvents(subSceneAdapter.getVerticalHelper()); 34 | } 35 | setChanged(); 36 | notifyObservers(this.selected); 37 | } 38 | 39 | public boolean isDragInProgress() { 40 | return this.dragInProgress; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/controller/DragMoveController.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.controller; 2 | 3 | import ch.hsr.ogv.model.ModelBox; 4 | import ch.hsr.ogv.model.ModelClass; 5 | import ch.hsr.ogv.model.ModelObject; 6 | import ch.hsr.ogv.view.Floor; 7 | import ch.hsr.ogv.view.PaneBox; 8 | import ch.hsr.ogv.view.SubSceneAdapter; 9 | import ch.hsr.ogv.view.VerticalHelper; 10 | import javafx.geometry.Point3D; 11 | import javafx.scene.Cursor; 12 | import javafx.scene.input.MouseButton; 13 | import javafx.scene.input.MouseEvent; 14 | import javafx.scene.input.PickResult; 15 | 16 | public class DragMoveController extends DragController { 17 | 18 | protected volatile double origRelMouseX; 19 | protected volatile double origRelMouseY; 20 | protected volatile double origRelMouseZ; 21 | 22 | public void enableDragMove(ModelBox modelBox, PaneBox paneBox, SubSceneAdapter subSceneAdapter) { 23 | startOnMouseMoved(modelBox, paneBox, subSceneAdapter); 24 | moveOnMouseDragged(modelBox, paneBox, subSceneAdapter); 25 | endOnMouseReleased(paneBox.get(), paneBox, subSceneAdapter); 26 | } 27 | 28 | private void startOnMouseMoved(ModelBox modelBox, PaneBox paneBox, SubSceneAdapter subSceneAdapter) { 29 | paneBox.get().addEventHandler(MouseEvent.MOUSE_MOVED, (MouseEvent me) -> { 30 | origRelMouseX = me.getX(); 31 | origRelMouseY = me.getY(); 32 | origRelMouseZ = me.getZ(); 33 | }); 34 | } 35 | 36 | private void moveOnMouseDragged(ModelBox modelBox, PaneBox paneBox, SubSceneAdapter subSceneAdapter) { 37 | paneBox.get().addEventHandler(MouseEvent.MOUSE_DRAGGED, (MouseEvent me) -> { 38 | setDragInProgress(subSceneAdapter, true); 39 | if (MouseButton.PRIMARY.equals(me.getButton()) && paneBox.isSelected()) { 40 | if (modelBox instanceof ModelClass) { 41 | Floor floor = subSceneAdapter.getFloor(); 42 | subSceneAdapter.getSubScene().setCursor(Cursor.MOVE); 43 | PickResult pick = me.getPickResult(); 44 | if (pick != null && pick.getIntersectedNode() != null && floor.hasTile(pick.getIntersectedNode())) { 45 | Point3D coords = pick.getIntersectedNode().localToParent(pick.getIntersectedPoint()); 46 | Point3D classCoordinates = new Point3D(coords.getX() - origRelMouseX, modelBox.getY(), coords.getZ() - origRelMouseZ); 47 | modelBox.setCoordinates(classCoordinates); 48 | } 49 | } 50 | else if (modelBox instanceof ModelObject) { 51 | VerticalHelper verticalHelper = subSceneAdapter.getVerticalHelper(); 52 | if (verticalHelper == null) 53 | return; 54 | verticalHelper.setDimension(paneBox); 55 | verticalHelper.setVisible(true); 56 | verticalHelper.toFront(); 57 | subSceneAdapter.getSubScene().setCursor(Cursor.MOVE); 58 | PickResult pick = me.getPickResult(); 59 | if (pick != null && pick.getIntersectedNode() != null && verticalHelper.isVerticalHelper(pick.getIntersectedNode())) { 60 | Point3D coords = pick.getIntersectedNode().localToParent(pick.getIntersectedPoint()); 61 | double newY = coords.getY() - origRelMouseY; 62 | if (newY < ModelClass.OBJECT_LEVEL_DIFF) { 63 | newY = ModelClass.OBJECT_LEVEL_DIFF; 64 | } 65 | Point3D objectCoordinates = new Point3D(modelBox.getX(), newY, modelBox.getZ()); 66 | modelBox.setCoordinates(objectCoordinates); 67 | verticalHelper.setDimension(paneBox); 68 | } 69 | } 70 | } 71 | }); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/controller/DragResizeController.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.controller; 2 | 3 | import ch.hsr.ogv.model.ModelBox; 4 | import ch.hsr.ogv.view.Floor; 5 | import ch.hsr.ogv.view.PaneBox; 6 | import ch.hsr.ogv.view.SubSceneAdapter; 7 | import javafx.geometry.Point3D; 8 | import javafx.scene.Cursor; 9 | import javafx.scene.Group; 10 | import javafx.scene.input.MouseButton; 11 | import javafx.scene.input.MouseEvent; 12 | import javafx.scene.input.PickResult; 13 | 14 | public class DragResizeController extends DragController { 15 | 16 | protected volatile double origTranslateX; 17 | protected volatile double origTranslateY; 18 | protected volatile double origTranslateZ; 19 | 20 | protected volatile double origWidth; 21 | protected volatile double origHeight; 22 | 23 | public void enableDragResize(ModelBox modelBox, PaneBox paneBox, SubSceneAdapter subSceneAdapter) { 24 | enableDirection(paneBox.getSelection().getLineN(), Cursor.N_RESIZE, modelBox, paneBox, subSceneAdapter); 25 | enableDirection(paneBox.getSelection().getPointNE(), Cursor.NE_RESIZE, modelBox, paneBox, subSceneAdapter); 26 | enableDirection(paneBox.getSelection().getLineE(), Cursor.E_RESIZE, modelBox, paneBox, subSceneAdapter); 27 | enableDirection(paneBox.getSelection().getPointSE(), Cursor.SE_RESIZE, modelBox, paneBox, subSceneAdapter); 28 | enableDirection(paneBox.getSelection().getLineS(), Cursor.S_RESIZE, modelBox, paneBox, subSceneAdapter); 29 | enableDirection(paneBox.getSelection().getPointSW(), Cursor.SW_RESIZE, modelBox, paneBox, subSceneAdapter); 30 | enableDirection(paneBox.getSelection().getLineW(), Cursor.W_RESIZE, modelBox, paneBox, subSceneAdapter); 31 | enableDirection(paneBox.getSelection().getPointNW(), Cursor.NW_RESIZE, modelBox, paneBox, subSceneAdapter); 32 | } 33 | 34 | private void enableDirection(Group g, Cursor direction, ModelBox modelBox, PaneBox paneBox, SubSceneAdapter subSceneAdapter) { 35 | g.addEventHandler(MouseEvent.MOUSE_ENTERED, (MouseEvent me) -> { 36 | subSceneAdapter.getSubScene().setCursor(direction); 37 | }); 38 | 39 | g.addEventHandler(MouseEvent.MOUSE_EXITED, (MouseEvent me) -> { 40 | subSceneAdapter.getSubScene().setCursor(Cursor.DEFAULT); 41 | }); 42 | 43 | resizeOnMouseDragged(g, modelBox, paneBox, subSceneAdapter, direction); 44 | endOnMouseReleased(g, paneBox, subSceneAdapter); 45 | } 46 | 47 | private void setOriginals(ModelBox modelBox) { 48 | Point3D origCoords = modelBox.getCoordinates(); 49 | origTranslateX = origCoords.getX(); 50 | origTranslateY = origCoords.getY(); 51 | origTranslateZ = origCoords.getZ(); 52 | origWidth = modelBox.getWidth(); 53 | origHeight = modelBox.getHeight(); 54 | } 55 | 56 | private void resizeOnMouseDragged(Group g, ModelBox modelBox, PaneBox paneBox, SubSceneAdapter subSceneAdapter, Cursor direction) { 57 | Floor floor = subSceneAdapter.getFloor(); 58 | g.addEventHandler(MouseEvent.MOUSE_DRAGGED, (MouseEvent me) -> { 59 | setOriginals(modelBox); 60 | setDragInProgress(subSceneAdapter, true); 61 | if (MouseButton.PRIMARY.equals(me.getButton())) { 62 | subSceneAdapter.getSubScene().setCursor(direction); 63 | PickResult pick = me.getPickResult(); 64 | if (pick != null && pick.getIntersectedNode() != null && floor.hasTile(pick.getIntersectedNode())) { 65 | Point3D coords = pick.getIntersectedNode().localToParent(pick.getIntersectedPoint()); 66 | if (Cursor.N_RESIZE.equals(direction)) { 67 | northResize(modelBox, paneBox, coords); 68 | } 69 | else if (Cursor.NE_RESIZE.equals(direction)) { 70 | northResize(modelBox, paneBox, coords); 71 | eastResize(modelBox, paneBox, coords); 72 | } 73 | else if (Cursor.E_RESIZE.equals(direction)) { 74 | eastResize(modelBox, paneBox, coords); 75 | } 76 | else if (Cursor.SE_RESIZE.equals(direction)) { 77 | southResize(modelBox, paneBox, coords); 78 | eastResize(modelBox, paneBox, coords); 79 | } 80 | else if (Cursor.S_RESIZE.equals(direction)) { 81 | southResize(modelBox, paneBox, coords); 82 | } 83 | else if (Cursor.SW_RESIZE.equals(direction)) { 84 | southResize(modelBox, paneBox, coords); 85 | westResize(modelBox, paneBox, coords); 86 | } 87 | else if (Cursor.W_RESIZE.equals(direction)) { 88 | westResize(modelBox, paneBox, coords); 89 | } 90 | else if (Cursor.NW_RESIZE.equals(direction)) { 91 | northResize(modelBox, paneBox, coords); 92 | westResize(modelBox, paneBox, coords); 93 | } 94 | } 95 | } 96 | }); 97 | } 98 | 99 | protected void northResize(ModelBox modelBox, PaneBox paneBox, Point3D coords) { 100 | double newHeight = modelBox.getHeight() / 2 - modelBox.getZ() + coords.getZ(); 101 | newHeight = restrictedHeight(paneBox, newHeight); 102 | modelBox.setHeight(newHeight); 103 | modelBox.setZ(origTranslateZ - origHeight / 2 + newHeight / 2); 104 | } 105 | 106 | protected void eastResize(ModelBox modelBox, PaneBox paneBox, Point3D coords) { 107 | double newWidth = modelBox.getWidth() / 2 + modelBox.getX() - coords.getX(); 108 | newWidth = restrictedWidth(paneBox, newWidth); 109 | modelBox.setWidth(newWidth); 110 | modelBox.setX(origTranslateX + origWidth / 2 - newWidth / 2); 111 | } 112 | 113 | protected void southResize(ModelBox modelBox, PaneBox paneBox, Point3D coords) { 114 | double newHeight = modelBox.getHeight() / 2 + modelBox.getZ() - coords.getZ(); 115 | newHeight = restrictedHeight(paneBox, newHeight); 116 | modelBox.setHeight(newHeight); 117 | modelBox.setZ(origTranslateZ + origHeight / 2 - newHeight / 2); 118 | } 119 | 120 | protected void westResize(ModelBox modelBox, PaneBox paneBox, Point3D coords) { 121 | double newWidth = modelBox.getWidth() / 2 - modelBox.getX() + coords.getX(); 122 | newWidth = restrictedWidth(paneBox, newWidth); 123 | modelBox.setWidth(newWidth); 124 | modelBox.setX(origTranslateX - origWidth / 2 + newWidth / 2); 125 | } 126 | 127 | private double restrictedWidth(PaneBox paneBox, double newWidth) { 128 | double retWidth = newWidth; 129 | if (newWidth <= paneBox.getMinWidth()) { 130 | retWidth = paneBox.getMinWidth(); 131 | } 132 | else if (newWidth >= paneBox.getMaxWidth()) { 133 | retWidth = paneBox.getMaxWidth(); 134 | } 135 | return retWidth; 136 | } 137 | 138 | private double restrictedHeight(PaneBox paneBox, double newHeight) { 139 | double retHeight = newHeight; 140 | if (newHeight <= paneBox.getMinHeight()) { 141 | retHeight = paneBox.getMinHeight(); 142 | } 143 | else if (newHeight >= paneBox.getMaxHeight()) { 144 | retHeight = paneBox.getMaxHeight(); 145 | } 146 | return retHeight; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/controller/MouseMoveController.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.controller; 2 | 3 | import ch.hsr.ogv.view.Floor; 4 | import ch.hsr.ogv.view.PaneBox; 5 | import ch.hsr.ogv.view.VerticalHelper; 6 | import javafx.geometry.Point3D; 7 | import javafx.scene.input.MouseEvent; 8 | import javafx.scene.input.PickResult; 9 | 10 | import java.util.Observable; 11 | 12 | public class MouseMoveController extends Observable { 13 | 14 | public void enableMouseMove(Floor floor) { 15 | 16 | floor.addEventHandler(MouseEvent.MOUSE_MOVED, (MouseEvent me) -> { 17 | PickResult pick = me.getPickResult(); 18 | Point3D movePoint = pick.getIntersectedNode().localToParent(pick.getIntersectedPoint()); 19 | setChanged(); 20 | notifyObservers(movePoint); 21 | }); 22 | 23 | } 24 | 25 | public void enableMouseMove(VerticalHelper verticalHelper) { 26 | verticalHelper.addEventHandler(MouseEvent.MOUSE_MOVED, (MouseEvent me) -> { 27 | PickResult pick = me.getPickResult(); 28 | Point3D movePoint = pick.getIntersectedNode().localToParent(pick.getIntersectedPoint()); 29 | setChanged(); 30 | notifyObservers(movePoint); 31 | }); 32 | } 33 | 34 | public void enableMouseMove(PaneBox paneBox) { 35 | paneBox.get().addEventHandler(MouseEvent.MOUSE_MOVED, (MouseEvent me) -> { 36 | setChanged(); 37 | notifyObservers(paneBox); 38 | }); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/controller/QuickCreationController.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.controller; 2 | 3 | import ch.hsr.ogv.model.Attribute; 4 | import ch.hsr.ogv.model.ModelBox; 5 | import ch.hsr.ogv.model.ModelClass; 6 | import ch.hsr.ogv.model.ModelObject; 7 | import ch.hsr.ogv.view.PaneBox; 8 | import javafx.beans.value.ChangeListener; 9 | import javafx.beans.value.ObservableValue; 10 | import javafx.event.EventHandler; 11 | import javafx.scene.control.Label; 12 | import javafx.scene.control.TextField; 13 | import javafx.scene.input.KeyCode; 14 | import javafx.scene.input.KeyEvent; 15 | 16 | public class QuickCreationController { 17 | 18 | private ModelViewConnector mvConnector; 19 | private TextField textField; 20 | private PaneBox paneBox; 21 | 22 | private EventHandler classKeyEvent; 23 | private ChangeListener classFocusChange; 24 | private EventHandler objectKeyEvent; 25 | private ChangeListener objectFocusChange; 26 | 27 | private volatile boolean disableSpeedCreation = false; 28 | 29 | public QuickCreationController(PaneBox paneBox, ModelViewConnector mvConnector) { 30 | this(paneBox.getTopTextField(), paneBox, mvConnector); // starting with topTextField 31 | } 32 | 33 | private QuickCreationController(TextField textField, PaneBox paneBox, ModelViewConnector mvConnector) { 34 | this.textField = textField; 35 | this.paneBox = paneBox; 36 | this.mvConnector = mvConnector; 37 | ModelBox modelBox = this.mvConnector.getModelBox(this.paneBox); 38 | if (modelBox instanceof ModelClass) { 39 | enableClassSpeedCreation(); 40 | } 41 | else if (modelBox instanceof ModelObject) { 42 | enableObjectSpeedCreation(); 43 | } 44 | } 45 | 46 | private void enableClassSpeedCreation() { 47 | this.classKeyEvent = (KeyEvent ke) -> { 48 | if (ke.getCode() == KeyCode.ENTER && !ke.isControlDown()) { // continue 49 | disableClassSpeedCreation(); 50 | Attribute newAttribute = this.mvConnector.handleCreateNewAttribute(this.paneBox); 51 | for (TextField centerTextField : this.paneBox.getCenterTextFields()) { 52 | if (centerTextField.getText().equals(newAttribute.getName())) { 53 | new QuickCreationController(centerTextField, this.paneBox, this.mvConnector); 54 | } 55 | } 56 | } 57 | else if ((ke.getCode() == KeyCode.ENTER && ke.isControlDown()) || ke.getCode() == KeyCode.ESCAPE) { // finish 58 | disableClassSpeedCreation(); 59 | } 60 | }; 61 | 62 | this.classFocusChange = new ChangeListener() { 63 | @Override 64 | public void changed(ObservableValue focusProperty, Boolean oldHasFocus, Boolean newHasFocus) { 65 | if (!newHasFocus && !disableSpeedCreation) { 66 | disableSpeedCreation = true; 67 | } 68 | else if (!newHasFocus && disableSpeedCreation) { 69 | disableClassSpeedCreation(); 70 | } 71 | } 72 | }; 73 | this.textField.addEventHandler(KeyEvent.KEY_PRESSED, this.classKeyEvent); 74 | this.textField.focusedProperty().addListener(this.classFocusChange); 75 | } 76 | 77 | private void disableClassSpeedCreation() { 78 | if (this.classKeyEvent != null) { 79 | this.textField.removeEventHandler(KeyEvent.KEY_PRESSED, this.classKeyEvent); 80 | } 81 | if (this.classFocusChange != null) { 82 | this.textField.focusedProperty().removeListener(this.classFocusChange); 83 | } 84 | } 85 | 86 | private void enableObjectSpeedCreation() { 87 | this.objectKeyEvent = (KeyEvent ke) -> { 88 | if (ke.getCode() == KeyCode.ENTER && !ke.isControlDown()) { // continue 89 | disableObjectSpeedCreation(); 90 | Label selectedLabel = this.paneBox.getSelectedLabel(); 91 | if (selectedLabel != null && selectedLabel.equals(this.paneBox.getTopLabel()) && !this.paneBox.getCenterLabels().isEmpty()) { 92 | Label firstCenterLabel = this.paneBox.getCenterLabels().get(0); 93 | this.paneBox.allowCenterFieldTextInput(firstCenterLabel, true); 94 | new QuickCreationController(this.paneBox.getCenterTextFields().get(0), paneBox, mvConnector); 95 | } 96 | else if (selectedLabel != null && this.paneBox.getCenterLabels().contains(selectedLabel)) { 97 | int rowIndex = this.paneBox.getCenterLabels().indexOf(selectedLabel); 98 | if (rowIndex + 1 > 0 && rowIndex + 1 < this.paneBox.getCenterLabels().size()) { 99 | Label nextCenterLabel = this.paneBox.getCenterLabels().get(rowIndex + 1); 100 | this.paneBox.allowCenterFieldTextInput(nextCenterLabel, true); 101 | new QuickCreationController(this.paneBox.getCenterTextFields().get(rowIndex + 1), paneBox, mvConnector); 102 | } 103 | } 104 | } 105 | else if ((ke.getCode() == KeyCode.ENTER && ke.isControlDown()) || ke.getCode() == KeyCode.ESCAPE) { // finish 106 | disableObjectSpeedCreation(); 107 | } 108 | }; 109 | 110 | this.objectFocusChange = new ChangeListener() { 111 | @Override 112 | public void changed(ObservableValue focusProperty, Boolean oldHasFocus, Boolean newHasFocus) { 113 | if (!newHasFocus && !disableSpeedCreation) { 114 | disableSpeedCreation = true; 115 | } 116 | else if (!newHasFocus && disableSpeedCreation) { 117 | disableObjectSpeedCreation(); 118 | } 119 | } 120 | }; 121 | this.textField.addEventHandler(KeyEvent.KEY_PRESSED, this.objectKeyEvent); 122 | this.textField.focusedProperty().addListener(this.objectFocusChange); 123 | } 124 | 125 | private void disableObjectSpeedCreation() { 126 | if (this.objectKeyEvent != null) { 127 | this.textField.removeEventHandler(KeyEvent.KEY_PRESSED, this.objectKeyEvent); 128 | } 129 | if (this.objectFocusChange != null) { 130 | this.textField.focusedProperty().removeListener(this.objectFocusChange); 131 | } 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/controller/RotationCamera.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.controller; 2 | 3 | import ch.hsr.ogv.view.SubSceneAdapter; 4 | import ch.hsr.ogv.view.SubSceneCamera; 5 | import ch.hsr.ogv.view.Xform; 6 | import javafx.scene.SubScene; 7 | import javafx.scene.input.KeyEvent; 8 | import javafx.scene.input.MouseEvent; 9 | import javafx.scene.input.ScrollEvent; 10 | 11 | public class RotationCamera extends CameraBase { 12 | 13 | @Override 14 | public void handleMouse(SubSceneAdapter subSceneAdapter) { 15 | SubScene subScene = subSceneAdapter.getSubScene(); 16 | SubSceneCamera ssCamera = subSceneAdapter.getSubSceneCamera(); 17 | 18 | subScene.setOnMousePressed((MouseEvent me) -> { 19 | if (!moveCamera) { 20 | return; 21 | } 22 | 23 | mousePosX = me.getSceneX(); 24 | mousePosY = me.getSceneY(); 25 | mouseOldX = me.getSceneX(); 26 | mouseOldY = me.getSceneY(); 27 | }); 28 | 29 | subScene.setOnMouseDragged((MouseEvent me) -> { 30 | if (!moveCamera) { 31 | return; 32 | } 33 | mouseOldX = mousePosX; 34 | mouseOldY = mousePosY; 35 | mousePosX = me.getSceneX(); 36 | mousePosY = me.getSceneY(); 37 | mouseDeltaX = (mousePosX - mouseOldX); 38 | mouseDeltaY = (mousePosY - mouseOldY); 39 | Xform cameraXform = ssCamera.getCameraXform(); 40 | Xform cameraXform2 = ssCamera.getCameraXform2(); 41 | 42 | double modifier = MODIFIER; 43 | 44 | if (me.isControlDown()) { 45 | modifier = CONTROL_MULTIPLIER; 46 | } 47 | if (me.isShiftDown()) { 48 | modifier = SHIFT_MULTIPLIER; 49 | } 50 | if (me.isPrimaryButtonDown()) { 51 | cameraXform2.t.setX(cameraXform2.t.getX() + mouseDeltaX * MODIFIER_FACTOR * modifier * 3.0); 52 | cameraXform2.t.setY(cameraXform2.t.getY() + mouseDeltaY * MODIFIER_FACTOR * modifier * 3.0); 53 | } 54 | else if (me.isSecondaryButtonDown() && !lockedTopView) { 55 | cameraXform.ry.setAngle(cameraXform.ry.getAngle() - mouseDeltaX * MODIFIER_FACTOR * modifier); 56 | cameraXform.rx.setAngle(cameraXform.rx.getAngle() + mouseDeltaY * MODIFIER_FACTOR * modifier); 57 | } 58 | else if (me.isMiddleButtonDown()) { 59 | double z = ssCamera.get().getTranslateZ(); 60 | double newZ = z - mouseDeltaY * 2 * modifier; 61 | ssCamera.get().setTranslateZ(newZ); 62 | } 63 | }); 64 | 65 | subScene.setOnScroll((ScrollEvent se) -> { 66 | if (!moveCamera) { 67 | return; 68 | } 69 | double z = ssCamera.get().getTranslateZ(); 70 | double newZ = z; 71 | double modifier = MODIFIER; 72 | if (se.isControlDown()) { 73 | modifier = CONTROL_MULTIPLIER; 74 | newZ += se.getDeltaY() * modifier * 0.5; 75 | } 76 | else if (se.isShiftDown()) { 77 | modifier = SHIFT_MULTIPLIER; 78 | newZ += se.getDeltaX() * modifier; 79 | } 80 | else { 81 | newZ += se.getDeltaY() * MODIFIER; 82 | } 83 | ssCamera.get().setTranslateZ(newZ); 84 | }); 85 | 86 | } 87 | 88 | @Override 89 | public void handleKeyboard(SubSceneAdapter subSceneAdapter) { 90 | SubScene subScene = subSceneAdapter.getSubScene(); 91 | SubSceneCamera ssCamera = subSceneAdapter.getSubSceneCamera(); 92 | 93 | subScene.setOnKeyPressed((KeyEvent ke) -> { 94 | if (!moveCamera) { 95 | return; 96 | } 97 | switch (ke.getCode()) { 98 | case UP: 99 | double oldY_UP = ssCamera.get().getTranslateY(); 100 | double newY_UP = oldY_UP - MODIFIER * 8; 101 | ssCamera.get().setTranslateY(newY_UP); 102 | break; 103 | case DOWN: 104 | double oldY_DOWN = ssCamera.get().getTranslateY(); 105 | double newY_DOWN = oldY_DOWN + MODIFIER * 8; 106 | ssCamera.get().setTranslateY(newY_DOWN); 107 | break; 108 | case RIGHT: 109 | double oldX_RIGHT = ssCamera.get().getTranslateX(); 110 | double newX_RIGHT = oldX_RIGHT + MODIFIER * 8; 111 | ssCamera.get().setTranslateX(newX_RIGHT); 112 | break; 113 | case LEFT: 114 | double oldX_LEFT = ssCamera.get().getTranslateX(); 115 | double newX_LEFT = oldX_LEFT - MODIFIER * 8; 116 | ssCamera.get().setTranslateX(newX_LEFT); 117 | break; 118 | default: 119 | break; 120 | } 121 | }); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/ColorAdapter.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.util.ColorUtil; 4 | import javafx.scene.paint.Color; 5 | 6 | import javax.xml.bind.annotation.adapters.XmlAdapter; 7 | 8 | public class ColorAdapter extends XmlAdapter { 9 | 10 | /* 11 | * Java => XML 12 | */ 13 | @Override 14 | public String marshal(Color val) throws Exception { 15 | return ColorUtil.colorToWebColor(val); 16 | } 17 | 18 | /* 19 | * XML => Java 20 | */ 21 | @Override 22 | public Color unmarshal(String val) throws Exception { 23 | return ColorUtil.webColorToColor(val); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/ImportCallback.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.util.MessageBar; 4 | import ch.hsr.ogv.util.MessageBar.MessageLevel; 5 | import javafx.stage.Stage; 6 | 7 | import java.io.File; 8 | 9 | public class ImportCallback implements PersistenceCallback { 10 | 11 | private Stage primaryStage; 12 | private String appTitle; 13 | private File file; 14 | 15 | public ImportCallback(Stage primaryStage, String appTitle, File file) { 16 | this.primaryStage = primaryStage; 17 | this.appTitle = appTitle; 18 | this.file = file; 19 | } 20 | 21 | @Override 22 | public void completed(boolean success) { 23 | if (success) { 24 | this.primaryStage.setTitle(this.appTitle + " - " + file.getName()); // set new app title 25 | MessageBar.setText("Imported file: \"" + file.getPath() + "\".", MessageLevel.INFO); 26 | } 27 | else { 28 | MessageBar.setText("Could not import data from file: \"" + file.getPath() + "\".", MessageLevel.ALERT); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/LoadCallback.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.util.MessageBar; 4 | import ch.hsr.ogv.util.MessageBar.MessageLevel; 5 | import javafx.stage.Stage; 6 | 7 | import java.io.File; 8 | 9 | public class LoadCallback implements PersistenceCallback { 10 | 11 | private Stage primaryStage; 12 | private String appTitle; 13 | private File file; 14 | 15 | public LoadCallback(Stage primaryStage, String appTitle, File file) { 16 | this.primaryStage = primaryStage; 17 | this.appTitle = appTitle; 18 | this.file = file; 19 | } 20 | 21 | @Override 22 | public void completed(boolean success) { 23 | if (success) { 24 | this.primaryStage.setTitle(this.appTitle + " - " + file.getName()); // set new app title 25 | MessageBar.setText("Loaded file: \"" + file.getPath() + "\".", MessageLevel.INFO); 26 | } 27 | else { 28 | MessageBar.setText("Could not load data from file: \"" + file.getPath() + "\".", MessageLevel.ALERT); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/OGVPoint3D.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import javax.xml.bind.annotation.XmlType; 4 | 5 | @XmlType(propOrder = {"x", "y", "z"}) 6 | public class OGVPoint3D { 7 | 8 | private double x = 0.0; 9 | private double y = 0.0; 10 | private double z = 0.0; 11 | 12 | public OGVPoint3D(double x, double y, double z) { 13 | this.x = x; 14 | this.y = y; 15 | this.z = z; 16 | } 17 | 18 | public OGVPoint3D() { 19 | 20 | } 21 | 22 | public double getX() { 23 | return x; 24 | } 25 | 26 | public void setX(double x) { 27 | this.x = x; 28 | } 29 | 30 | public double getY() { 31 | return y; 32 | } 33 | 34 | public void setY(double y) { 35 | this.y = y; 36 | } 37 | 38 | public double getZ() { 39 | return z; 40 | } 41 | 42 | public void setZ(double z) { 43 | this.z = z; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/OGVSerialization.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.model.ModelClass; 4 | import ch.hsr.ogv.model.Relation; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.xml.bind.JAXBContext; 9 | import javax.xml.bind.JAXBException; 10 | import javax.xml.bind.Marshaller; 11 | import javax.xml.bind.Unmarshaller; 12 | import javax.xml.bind.annotation.XmlElement; 13 | import javax.xml.bind.annotation.XmlElementWrapper; 14 | import javax.xml.bind.annotation.XmlRootElement; 15 | import javax.xml.bind.annotation.XmlType; 16 | import java.io.File; 17 | import java.util.LinkedHashSet; 18 | import java.util.Set; 19 | 20 | @XmlRootElement(name = "model") 21 | @XmlType(propOrder = {"classes", "relations"}) 22 | public class OGVSerialization implements SerializationStrategy { 23 | 24 | private final static Logger logger = LoggerFactory.getLogger(OGVSerialization.class); 25 | 26 | private Set classes = new LinkedHashSet(); 27 | private Set relations = new LinkedHashSet(); 28 | 29 | @XmlElementWrapper(name = "classes") 30 | @XmlElement(name = "class") 31 | @Override 32 | public Set getClasses() { 33 | return this.classes; 34 | } 35 | 36 | @Override 37 | public void setClasses(Set classes) { 38 | this.classes = classes; 39 | } 40 | 41 | @XmlElementWrapper(name = "relations") 42 | @XmlElement(name = "relation") 43 | @Override 44 | public Set getRelations() { 45 | return this.relations; 46 | } 47 | 48 | @Override 49 | public void setRelations(Set relations) { 50 | this.relations = relations; 51 | } 52 | 53 | @Override 54 | public boolean parse(File file) { 55 | JAXBContext context = null; 56 | Unmarshaller um; 57 | try { 58 | context = JAXBContext.newInstance(OGVSerialization.class); 59 | um = context.createUnmarshaller(); 60 | OGVSerialization ogvUnmarshalled = (OGVSerialization) um.unmarshal(file); // Reading XML from the file and unmarshalling. 61 | setClasses(ogvUnmarshalled.getClasses()); 62 | setRelations(ogvUnmarshalled.getRelations()); 63 | return true; 64 | } 65 | catch (JAXBException e) { 66 | e.printStackTrace(); 67 | logger.debug(e.getMessage()); 68 | } 69 | return false; 70 | } 71 | 72 | @Override 73 | public boolean serialize(File file) { 74 | try { 75 | JAXBContext context = JAXBContext.newInstance(OGVSerialization.class); 76 | Marshaller m = context.createMarshaller(); 77 | m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 78 | m.marshal(this, file); 79 | return true; 80 | } 81 | catch (JAXBException e) { 82 | e.printStackTrace(); 83 | logger.debug(e.getMessage()); 84 | } 85 | return false; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/PersistenceCallback.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | @FunctionalInterface 4 | public interface PersistenceCallback { 5 | void completed(boolean success); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/Point3DAdapter.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import javafx.geometry.Point3D; 4 | 5 | import javax.xml.bind.annotation.adapters.XmlAdapter; 6 | 7 | public class Point3DAdapter extends XmlAdapter { 8 | 9 | /* 10 | * Java => XML 11 | */ 12 | @Override 13 | public OGVPoint3D marshal(Point3D val) throws Exception { 14 | return new OGVPoint3D(val.getX(), val.getY(), val.getZ()); 15 | } 16 | 17 | /* 18 | * XML => Java 19 | */ 20 | @Override 21 | public Point3D unmarshal(OGVPoint3D val) throws Exception { 22 | return new Point3D(val.getX(), val.getY(), val.getZ()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/SaveCallback.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.util.MessageBar; 4 | import ch.hsr.ogv.util.MessageBar.MessageLevel; 5 | import javafx.stage.Stage; 6 | 7 | import java.io.File; 8 | 9 | public class SaveCallback implements PersistenceCallback { 10 | 11 | private Stage primaryStage; 12 | private String appTitle; 13 | private File file; 14 | 15 | public SaveCallback(Stage primaryStage, String appTitle, File file) { 16 | this.primaryStage = primaryStage; 17 | this.appTitle = appTitle; 18 | this.file = file; 19 | } 20 | 21 | @Override 22 | public void completed(boolean success) { 23 | if (success) { 24 | this.primaryStage.setTitle(this.appTitle + " - " + file.getName()); // set new app title 25 | MessageBar.setText("Saved file: \"" + file.getPath() + "\".", MessageLevel.INFO); 26 | } 27 | else { 28 | MessageBar.setText("Could not save data to file: \"" + file.getPath() + "\".", MessageLevel.ALERT); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/SerializationStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.model.ModelClass; 4 | import ch.hsr.ogv.model.Relation; 5 | 6 | import java.io.File; 7 | import java.util.Set; 8 | 9 | public interface SerializationStrategy { 10 | 11 | public boolean parse(File file); 12 | 13 | public boolean serialize(File file); 14 | 15 | public Set getClasses(); 16 | 17 | public Set getRelations(); 18 | 19 | public void setClasses(Set modelClasses); 20 | 21 | public void setRelations(Set relations); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/UserPreferences.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import java.io.File; 4 | import java.util.prefs.Preferences; 5 | 6 | public class UserPreferences { 7 | 8 | private static final String OGV_FILE_PREFKEY = "ogvFilePath"; 9 | private static final String XMI_FILE_PREFKEY = "xmiFilePath"; 10 | 11 | private static void setPrefFilePath(String prefKey, File file) { 12 | Preferences prefs = Preferences.userNodeForPackage(UserPreferences.class); 13 | if (file != null) { 14 | prefs.put(prefKey, file.getPath()); 15 | } 16 | else { 17 | prefs.remove(prefKey); 18 | } 19 | } 20 | 21 | private static File getPrefFilePath(String prefKey) { 22 | Preferences prefs = Preferences.userNodeForPackage(UserPreferences.class); 23 | String filePath = prefs.get(prefKey, null); 24 | if (filePath != null) { 25 | return new File(filePath); 26 | } 27 | else { 28 | return null; 29 | } 30 | } 31 | 32 | /** 33 | * Returns the ogv file preference, i.e. the file that was last opened. The preference is read from the OS specific 34 | * registry. If no such preference can be found, null is returned. 35 | * 36 | * @return the last used file or null. 37 | */ 38 | public static File getOGVFilePath() { 39 | return getPrefFilePath(OGV_FILE_PREFKEY); 40 | } 41 | 42 | /** 43 | * Returns the xmi file preference, i.e. the file that was last opened. The preference is read from the OS specific 44 | * registry. If no such preference can be found, null is returned. 45 | * 46 | * @return the last used file or null. 47 | */ 48 | public static File getXMIFilePath() { 49 | return getPrefFilePath(XMI_FILE_PREFKEY); 50 | } 51 | 52 | /** 53 | * Sets the ogv file path of the currently loaded file. The path is persisted in the OS specific registry. 54 | * 55 | * @param file the file or null to remove the path 56 | */ 57 | public static void setOGVFilePath(File file) { 58 | setPrefFilePath(OGV_FILE_PREFKEY, file); 59 | } 60 | 61 | /** 62 | * Sets the ogv file path of the currently loaded file. The path is persisted in the OS specific registry. 63 | * 64 | * @param file the file or null to remove the path 65 | */ 66 | public static void setXMIFilePath(File file) { 67 | setPrefFilePath(XMI_FILE_PREFKEY, file); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/VersionHandler.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import org.xml.sax.Attributes; 4 | import org.xml.sax.helpers.DefaultHandler; 5 | 6 | /** 7 | * This class read the XMI Version of a File. 8 | * 9 | * @author Dario Vonaesch 10 | * @version 3.0, May 2007 11 | */ 12 | public class VersionHandler extends DefaultHandler { 13 | private StringBuffer mChars; 14 | private String mVersion; 15 | 16 | /** 17 | * Constructor - initialises variables. 18 | */ 19 | public VersionHandler() { 20 | mChars = new StringBuffer(); 21 | } 22 | 23 | /* 24 | * (non-Javadoc) 25 | * 26 | * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int) 27 | */ 28 | public void characters(char[] pCH, int pStart, int pLength) { 29 | mChars.append(pCH, pStart, pLength); 30 | } 31 | 32 | /* 33 | * (non-Javadoc) 34 | * 35 | * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) 36 | */ 37 | public void endElement(String pUri, String pLName, String pQName) { 38 | if (pQName.equals("XMI")) { 39 | mChars.delete(0, mChars.length()); 40 | } 41 | 42 | } 43 | 44 | /** 45 | * Returns the Version read or null if no Version is recognised. 46 | * 47 | * @return the Version or null if no Version is recognised 48 | */ 49 | public String getVersion() { 50 | return mVersion; 51 | } 52 | 53 | /* 54 | * (non-Javadoc) 55 | * 56 | * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) 57 | */ 58 | public void startElement(String pUri, String pLName, String pQName, Attributes pAtts) { 59 | mChars.delete(0, mChars.length()); 60 | 61 | if (pQName.equals("XMI")) { 62 | mVersion = pAtts.getValue("xmi.version"); 63 | } 64 | 65 | else if (pQName.equals("xmi:XMI")) { 66 | mVersion = pAtts.getValue("xmi:version"); 67 | 68 | } 69 | 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/XMIHandler.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.model.ModelClass; 4 | import ch.hsr.ogv.model.Relation; 5 | import org.xml.sax.helpers.DefaultHandler; 6 | 7 | import java.util.ArrayList; 8 | import java.util.LinkedHashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * This class is the Definition for a XMI Handler. 13 | * 14 | * @author Dario Vonaesch, Simon Gwerder 15 | * @version 3DCOV 3.0, May 2007 / OGV 3.1, May 2015 16 | */ 17 | public class XMIHandler extends DefaultHandler { 18 | 19 | protected ArrayList xmiRelations = new ArrayList(); 20 | protected StringBuffer characters = new StringBuffer(); 21 | protected Map idClassMap = new LinkedHashMap(); 22 | 23 | /* 24 | * (non-Javadoc) 25 | * 26 | * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int) 27 | */ 28 | public void characters(char[] pCH, int pStart, int pLength) { 29 | characters.append(pCH, pStart, pLength); 30 | } 31 | 32 | /** 33 | * Calls the mapping method and returns the class associations 34 | * 35 | * @return the read class associations 36 | */ 37 | public ArrayList getRelations() { 38 | return finalizeXMIRelations(); 39 | } 40 | 41 | /** 42 | * Returns the read classes 43 | * 44 | * @return read classes 45 | */ 46 | public ArrayList getClasses() { 47 | return new ArrayList(idClassMap.values()); 48 | } 49 | 50 | /** 51 | * Maps the read classes to the class relations using the class id's 52 | */ 53 | private ArrayList finalizeXMIRelations() { 54 | ArrayList relations = new ArrayList(); 55 | for (XMIRelation xmiRelation : xmiRelations) { 56 | ModelClass sourceClass = idClassMap.get(xmiRelation.getSourceID()); 57 | ModelClass targetClass = idClassMap.get(xmiRelation.getTargetID()); 58 | if (sourceClass != null && targetClass != null) { 59 | Relation relation = new Relation(sourceClass, targetClass, xmiRelation.getType()); 60 | relations.add(relation); 61 | relation.setName(xmiRelation.getName()); 62 | relation.getStart().setRoleName(xmiRelation.getSourceRoleName()); 63 | relation.getStart().setMultiplicity(xmiRelation.getSourceMultiplicity()); 64 | relation.getEnd().setRoleName(xmiRelation.getTargetRoleName()); 65 | relation.getEnd().setMultiplicity(xmiRelation.getTargetMultiplicity()); 66 | } 67 | } 68 | return relations; 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/XMIRelation.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.model.RelationType; 4 | 5 | public class XMIRelation { 6 | 7 | private String name = ""; 8 | private RelationType type = RelationType.UNDIRECTED_ASSOCIATION; 9 | private String sourceID; 10 | private String targetID; 11 | private String sourceRoleName; 12 | private String targetRoleName; 13 | private String sourceMultiplicity; 14 | private String targetMultiplicity; 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | public RelationType getType() { 25 | return type; 26 | } 27 | 28 | public void setType(RelationType type) { 29 | this.type = type; 30 | } 31 | 32 | public String getSourceID() { 33 | return sourceID; 34 | } 35 | 36 | public void setSourceID(String sourceID) { 37 | this.sourceID = sourceID; 38 | } 39 | 40 | public String getTargetID() { 41 | return targetID; 42 | } 43 | 44 | public void setTargetID(String targetID) { 45 | this.targetID = targetID; 46 | } 47 | 48 | public String getSourceRoleName() { 49 | return sourceRoleName; 50 | } 51 | 52 | public void setSourceRoleName(String sourceRoleName) { 53 | this.sourceRoleName = sourceRoleName; 54 | } 55 | 56 | public String getTargetRoleName() { 57 | return targetRoleName; 58 | } 59 | 60 | public void setTargetRoleName(String targetRoleName) { 61 | this.targetRoleName = targetRoleName; 62 | } 63 | 64 | public String getSourceMultiplicity() { 65 | return sourceMultiplicity; 66 | } 67 | 68 | public void setSourceMultiplicity(String sourceMultiplicity) { 69 | this.sourceMultiplicity = sourceMultiplicity; 70 | } 71 | 72 | public String getTargetMultiplicity() { 73 | return targetMultiplicity; 74 | } 75 | 76 | public void setTargetMultiplicity(String targetMultiplicity) { 77 | this.targetMultiplicity = targetMultiplicity; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/dataaccess/XMISerialization.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.dataaccess; 2 | 3 | import ch.hsr.ogv.model.ModelClass; 4 | import ch.hsr.ogv.model.Relation; 5 | import ch.hsr.ogv.util.MessageBar; 6 | import ch.hsr.ogv.util.MessageBar.MessageLevel; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.xml.sax.SAXException; 10 | 11 | import javax.xml.parsers.ParserConfigurationException; 12 | import javax.xml.parsers.SAXParser; 13 | import javax.xml.parsers.SAXParserFactory; 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.Arrays; 18 | import java.util.LinkedHashSet; 19 | import java.util.Set; 20 | 21 | /** 22 | * This class represents a XMI Parser. It reads the Version of the XMI File and use an according handler. If no handler 23 | * for the version exists or the version is not supported an Error Message is created. 24 | * 25 | * @author Dario Vonaesch, Simon Gwerder 26 | * @version 3DCOV 3.0, May 2007 / OGV 3.1, May 2015 27 | */ 28 | public class XMISerialization implements SerializationStrategy { 29 | 30 | private final static Logger logger = LoggerFactory.getLogger(SerializationStrategy.class); 31 | 32 | private static final String[] SUPPORTED_VERSIONS = {"1.1"}; 33 | 34 | private SAXParser mParser; 35 | private VersionHandler mVersionHandler; 36 | private XMIHandler xmiHandler; 37 | 38 | /** 39 | * Constructor - initialises variables. 40 | */ 41 | public XMISerialization() { 42 | xmiHandler = new XMIHandler(); 43 | } 44 | 45 | /** 46 | * @return the read class associations 47 | */ 48 | @Override 49 | public Set getRelations() { 50 | return new LinkedHashSet(xmiHandler.getRelations()); 51 | } 52 | 53 | /** 54 | * @return the read classes 55 | */ 56 | @Override 57 | public Set getClasses() { 58 | return new LinkedHashSet(xmiHandler.getClasses()); 59 | } 60 | 61 | @Override 62 | public boolean parse(File file) { 63 | try { 64 | return parseXMI(file); 65 | } 66 | catch (SAXException | IOException | ParserConfigurationException e) { 67 | logger.debug(e.getMessage()); 68 | MessageBar.setText("Unable to read XMI file: \"" + file.getPath() + "\".", MessageLevel.ALERT); 69 | } 70 | return false; 71 | } 72 | 73 | public boolean parseXMI(File xmiFile) throws SAXException, IOException, ParserConfigurationException { 74 | mParser = SAXParserFactory.newInstance().newSAXParser(); 75 | mVersionHandler = new VersionHandler(); 76 | try { 77 | mParser.parse(xmiFile, mVersionHandler); 78 | } 79 | catch (org.xml.sax.SAXParseException e) { 80 | logger.debug(e.getMessage()); 81 | } 82 | String version = mVersionHandler.getVersion(); 83 | ArrayList supportedVersions = new ArrayList(Arrays.asList(SUPPORTED_VERSIONS)); 84 | // version not recognised 85 | if (version == null) { 86 | MessageBar.setText("Unable to read XMI file: \"" + xmiFile.getPath() + "\".", MessageLevel.ALERT); 87 | } 88 | else if (supportedVersions.contains(version)) { // parsing file 89 | xmiHandler = new XMI_1_1(); 90 | try { 91 | mParser.parse(xmiFile, xmiHandler); 92 | return true; 93 | } 94 | catch (org.xml.sax.SAXParseException e) { 95 | logger.debug(e.getMessage()); 96 | MessageBar.setText("Unable to read XMI file: \"" + xmiFile.getPath() + "\".", MessageLevel.ALERT); 97 | } 98 | } 99 | // version not supported 100 | else { 101 | xmiHandler = new XMIHandler(); 102 | MessageBar.setText("The XMI version " + version + " is not supported. Supported XMI versions: " + String.join(",", SUPPORTED_VERSIONS), MessageLevel.ALERT); 103 | } 104 | return false; 105 | } 106 | 107 | @Override 108 | public boolean serialize(File file) { 109 | return false; // not supported (XMI export) 110 | } 111 | 112 | @Override 113 | public void setClasses(Set modelClasses) { 114 | return; // not supported (XMI export) 115 | } 116 | 117 | @Override 118 | public void setRelations(Set relations) { 119 | return; // not supported (XMI export) 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/model/Attribute.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | public class Attribute { 4 | 5 | private String name; 6 | 7 | public Attribute() { 8 | } 9 | 10 | public Attribute(String name) { 11 | this.name = name; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/model/Endpoint.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | import javax.xml.bind.annotation.XmlTransient; 4 | import java.util.UUID; 5 | 6 | public class Endpoint { 7 | 8 | // for un/marshaling only 9 | private String uniqueID = UUID.randomUUID().toString(); 10 | 11 | private EndpointType endpointType; 12 | private String roleName; 13 | private String multiplicity; 14 | private Relation relation; 15 | private ModelBox appendant; 16 | 17 | // for un/marshaling only 18 | public Endpoint() { 19 | } 20 | 21 | public Endpoint(EndpointType type, ModelBox appendant) { 22 | this.endpointType = type; 23 | this.appendant = appendant; 24 | } 25 | 26 | public String getUniqueID() { 27 | return uniqueID; 28 | } 29 | 30 | public void setUniqueID(String uniqueID) { 31 | this.uniqueID = uniqueID; 32 | } 33 | 34 | public EndpointType getEndpointType() { 35 | return endpointType; 36 | } 37 | 38 | public void setEndpointType(EndpointType endpointType) { 39 | this.endpointType = endpointType; 40 | } 41 | 42 | public String getRoleName() { 43 | return roleName; 44 | } 45 | 46 | public void setRoleName(String roleName) { 47 | this.roleName = roleName; 48 | } 49 | 50 | public String getMultiplicity() { 51 | return multiplicity; 52 | } 53 | 54 | public void setMultiplicity(String multiplicity) { 55 | this.multiplicity = multiplicity; 56 | } 57 | 58 | @XmlTransient 59 | public Relation getRelation() { 60 | return relation; 61 | } 62 | 63 | public void setRelation(Relation relation) { 64 | this.relation = relation; 65 | } 66 | 67 | @XmlTransient 68 | public ModelBox getAppendant() { 69 | return appendant; 70 | } 71 | 72 | public void setAppendant(ModelBox appendant) { 73 | this.appendant = appendant; 74 | } 75 | 76 | @XmlTransient 77 | public Endpoint getFriend() { 78 | if (relation != null) { 79 | return relation.getFriend(this); 80 | } 81 | return null; 82 | } 83 | 84 | public boolean isStart() { 85 | if (relation != null) { 86 | return relation.isStart(this); 87 | } 88 | return false; 89 | } 90 | 91 | public boolean isEnd() { 92 | if (relation != null) { 93 | return relation.isEnd(this); 94 | } 95 | return false; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/model/EndpointType.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | public enum EndpointType { 4 | OPEN_ARROW, EMPTY_ARROW, FILLED_ARROW, EMPTY_DIAMOND, FILLED_DIAMOND, ARC, NONE; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/model/LineType.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | public enum LineType { 4 | CONTINUOUS_LINE, DASHED_LINE; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/model/ModelBox.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | import ch.hsr.ogv.dataaccess.ColorAdapter; 4 | import ch.hsr.ogv.dataaccess.Point3DAdapter; 5 | import javafx.geometry.Point3D; 6 | import javafx.scene.paint.Color; 7 | 8 | import javax.xml.bind.annotation.XmlElement; 9 | import javax.xml.bind.annotation.XmlElementWrapper; 10 | import javax.xml.bind.annotation.XmlTransient; 11 | import javax.xml.bind.annotation.XmlType; 12 | import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 13 | import java.util.*; 14 | 15 | @XmlType(propOrder = {"name", "coordinates", "width", "height", "color", "endpoints"}) 16 | public abstract class ModelBox extends Observable { 17 | 18 | protected String name = ""; 19 | protected Point3D coordinates = new Point3D(0, 0, 0); 20 | protected double width = 100.0; 21 | protected double height = 100.0; 22 | protected Color color = Color.CORNSILK; 23 | protected List endpoints = new ArrayList(); 24 | 25 | // for un/marshaling only 26 | public ModelBox() { 27 | } 28 | 29 | public ModelBox(String name, Point3D coordinates, double width, double height, Color color) { 30 | this.name = name; 31 | this.coordinates = coordinates; 32 | this.width = width; 33 | this.height = height; 34 | this.color = color; 35 | } 36 | 37 | public String getName() { 38 | return name; 39 | } 40 | 41 | public void setName(String name) { 42 | // not doing the equals check here for when ModelObject needs a name change event 43 | if (this.name != null) { 44 | this.name = name; 45 | setChanged(); 46 | notifyObservers(ModelBoxChange.NAME); 47 | } 48 | } 49 | 50 | @XmlJavaTypeAdapter(Point3DAdapter.class) 51 | public Point3D getCoordinates() { 52 | return coordinates; 53 | } 54 | 55 | public void setCoordinates(Point3D coordinates) { 56 | if (this.coordinates != null) { 57 | this.coordinates = coordinates; 58 | setChanged(); 59 | notifyObservers(ModelBoxChange.COORDINATES); 60 | } 61 | } 62 | 63 | public void setX(double x) { 64 | Point3D coords = new Point3D(x, 0, 0); 65 | if (coordinates != null) { 66 | coords = new Point3D(x, this.coordinates.getY(), this.coordinates.getZ()); 67 | } 68 | setCoordinates(coords); 69 | } 70 | 71 | public void setY(double y) { 72 | Point3D coords = new Point3D(0, y, 0); 73 | if (coordinates != null) { 74 | coords = new Point3D(this.coordinates.getX(), y, this.coordinates.getZ()); 75 | } 76 | setCoordinates(coords); 77 | } 78 | 79 | public void setZ(double z) { 80 | Point3D coords = new Point3D(0, 0, z); 81 | if (coordinates != null) { 82 | coords = new Point3D(this.coordinates.getX(), this.coordinates.getY(), z); 83 | } 84 | setCoordinates(coords); 85 | } 86 | 87 | @XmlTransient 88 | public double getX() { 89 | return this.coordinates.getX(); 90 | } 91 | 92 | @XmlTransient 93 | public double getY() { 94 | return this.coordinates.getY(); 95 | } 96 | 97 | @XmlTransient 98 | public double getZ() { 99 | return this.coordinates.getZ(); 100 | } 101 | 102 | public double getWidth() { 103 | return width; 104 | } 105 | 106 | public void setWidth(double width) { 107 | if (this.width != width) { 108 | this.width = width; 109 | setChanged(); 110 | notifyObservers(ModelBoxChange.WIDTH); 111 | } 112 | } 113 | 114 | public double getHeight() { 115 | return height; 116 | } 117 | 118 | public void setHeight(double height) { 119 | if (this.height != height) { 120 | this.height = height; 121 | setChanged(); 122 | notifyObservers(ModelBoxChange.HEIGHT); 123 | } 124 | } 125 | 126 | @XmlJavaTypeAdapter(ColorAdapter.class) 127 | public Color getColor() { 128 | return color; 129 | } 130 | 131 | public void setColor(Color color) { 132 | if (this.color != null && !this.color.equals(color)) { 133 | this.color = color; 134 | setChanged(); 135 | notifyObservers(ModelBoxChange.COLOR); 136 | } 137 | } 138 | 139 | @XmlElementWrapper(name = "endpoints") 140 | @XmlElement(name = "endpoint") 141 | public List getEndpoints() { 142 | return endpoints; 143 | } 144 | 145 | public void setEndpoints(List endpoints) { 146 | this.endpoints = endpoints; 147 | } 148 | 149 | @XmlTransient 150 | public Map getFriends() { 151 | Map result = new LinkedHashMap(endpoints.size()); 152 | for (Endpoint endpoint : endpoints) { 153 | Endpoint friend = endpoint.getFriend(); 154 | if (friend != null) { 155 | result.put(endpoint, endpoint.getFriend()); 156 | } 157 | } 158 | return result; 159 | } 160 | 161 | public boolean replaceEndpoint(Endpoint toReplace, Endpoint replacement) { 162 | int index = this.endpoints.indexOf(toReplace); 163 | if (index >= 0) { 164 | this.endpoints.set(index, replacement); 165 | return true; 166 | } 167 | return false; 168 | } 169 | 170 | public enum ModelBoxChange { 171 | COORDINATES, HEIGHT, WIDTH, NAME, COLOR; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/model/ModelObject.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | import javafx.geometry.Point3D; 4 | import javafx.scene.paint.Color; 5 | 6 | import javax.xml.bind.annotation.XmlTransient; 7 | import javax.xml.bind.annotation.XmlType; 8 | import java.util.*; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | 11 | @XmlType(propOrder = {"uniqueID", "attributeValues"}) 12 | public class ModelObject extends ModelBox { 13 | 14 | // for un/marshaling only 15 | private String uniqueID = UUID.randomUUID().toString(); 16 | 17 | private Map attributeValues = new LinkedHashMap(); 18 | private ModelClass modelClass; 19 | 20 | public static volatile AtomicInteger modelObjectCounter = new AtomicInteger(0); 21 | 22 | public String getUniqueID() { 23 | return uniqueID; 24 | } 25 | 26 | public void setUniqueID(String uniqueID) { 27 | this.uniqueID = uniqueID; 28 | } 29 | 30 | public Map getAttributeValues() { 31 | return attributeValues; 32 | } 33 | 34 | public void setAttributeValues(Map attributeValues) { 35 | this.attributeValues = attributeValues; 36 | } 37 | 38 | public String getAttributeValue(String attributeName) { 39 | for (Attribute attribute : attributeValues.keySet()) { 40 | if (attribute.getName().equals(attributeName)) { 41 | return attributeValues.get(attribute); 42 | } 43 | } 44 | return null; 45 | } 46 | 47 | @XmlTransient 48 | public ModelClass getModelClass() { 49 | return modelClass; 50 | } 51 | 52 | public void setModelClass(ModelClass modelClass) { 53 | this.modelClass = modelClass; 54 | } 55 | 56 | @XmlTransient 57 | public List getSuperObjects() { 58 | if (this.modelClass == null) 59 | return new ArrayList(); 60 | return this.modelClass.getSuperObjects(this); 61 | } 62 | 63 | public void addSuperObject(ModelObject superObject) { 64 | if (this.modelClass == null) 65 | return; 66 | this.modelClass.addSuperObject(this, superObject); 67 | } 68 | 69 | public boolean isSuperObject() { 70 | if (this.modelClass == null) 71 | return false; 72 | return !this.modelClass.getModelObjects().contains(this); 73 | } 74 | 75 | // for un/marshaling only 76 | public ModelObject() { 77 | } 78 | 79 | public ModelObject(String name, ModelClass modelClass, Point3D coordinates, double width, double heigth, Color color) { 80 | super(name, coordinates, width, heigth, color); 81 | this.modelClass = modelClass; 82 | } 83 | 84 | public void changeAttributeName(Attribute attribute, String name) { 85 | attribute.setName(name); 86 | setChanged(); 87 | notifyObservers(attribute); 88 | } 89 | 90 | public void changeAttributeValue(Attribute attribute, String value) { 91 | String oldValue = this.attributeValues.put(attribute, value); 92 | if (oldValue != null) { 93 | setChanged(); 94 | notifyObservers(attribute); 95 | } 96 | } 97 | 98 | public void changeAttributeValue(String attributeName, String value) { 99 | for (Attribute attribute : attributeValues.keySet()) { 100 | if (attribute.getName().equals(attributeName)) { 101 | changeAttributeValue(attribute, value); 102 | } 103 | } 104 | } 105 | 106 | public boolean addAttributeValue(Attribute attribute, String attributeValue) { 107 | if (attributeValues.containsKey(attribute)) { 108 | return false; 109 | } 110 | attributeValues.put(attribute, attributeValue); 111 | setChanged(); 112 | notifyObservers(attribute); 113 | return true; 114 | } 115 | 116 | public String deleteAttributeValue(Attribute attribute) { 117 | String deleted = attributeValues.remove(attribute); 118 | if (deleted != null) { 119 | setChanged(); 120 | notifyObservers(attribute); 121 | } 122 | return deleted; 123 | } 124 | 125 | public void updateAttribute(Attribute attribute, String value) { 126 | attributeValues.replace(attribute, value); 127 | } 128 | 129 | @Override 130 | public String toString() { 131 | return super.toString() + " - " + name; 132 | } 133 | 134 | } -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/model/Relation.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | import ch.hsr.ogv.dataaccess.ColorAdapter; 4 | import javafx.scene.paint.Color; 5 | 6 | import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 7 | import java.util.Observable; 8 | 9 | public class Relation extends Observable { 10 | 11 | private String name = ""; 12 | private Endpoint start; 13 | private Endpoint end; 14 | private RelationType relationType = RelationType.UNDIRECTED_ASSOCIATION; 15 | private Color color = Color.BLACK; 16 | 17 | // for un/marshaling only 18 | public Relation() { 19 | } 20 | 21 | public Relation(ModelBox startBox, ModelBox endBox, RelationType relationType) { 22 | this(startBox, endBox, relationType, Color.BLACK); 23 | } 24 | 25 | public Relation(ModelBox startBox, ModelBox endBox, RelationType relationType, Color color) { 26 | this.start = new Endpoint(relationType.getStartType(), startBox); 27 | this.end = new Endpoint(relationType.getEndType(), endBox); 28 | this.relationType = relationType; 29 | this.start.setRelation(this); 30 | this.end.setRelation(this); 31 | this.color = color; 32 | } 33 | 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | public void setName(String name) { 39 | // setChanged(); 40 | // notifyObservers(RelationChange.NAME); 41 | this.name = name; 42 | } 43 | 44 | public Endpoint getStart() { 45 | return start; 46 | } 47 | 48 | public void setStart(Endpoint start) { 49 | this.start = start; 50 | } 51 | 52 | public Endpoint getEnd() { 53 | return end; 54 | } 55 | 56 | public void setEnd(Endpoint end) { 57 | this.end = end; 58 | } 59 | 60 | public RelationType getRelationType() { 61 | return relationType; 62 | } 63 | 64 | public void setRelationType(RelationType type) { 65 | this.relationType = type; 66 | } 67 | 68 | @XmlJavaTypeAdapter(ColorAdapter.class) 69 | public Color getColor() { 70 | return color; 71 | } 72 | 73 | public void setColor(Color color) { 74 | this.color = color; 75 | setChanged(); 76 | notifyObservers(RelationChange.COLOR); 77 | } 78 | 79 | public Endpoint getFriend(Endpoint endpoint) { 80 | if (endpoint.equals(start)) { 81 | return end; 82 | } 83 | return start; 84 | } 85 | 86 | public boolean isStart(Endpoint endpoint) { 87 | if (start != null && start.equals(endpoint)) { 88 | return true; 89 | } 90 | return false; 91 | } 92 | 93 | public boolean isEnd(Endpoint endpoint) { 94 | if (end != null && end.equals(endpoint)) { 95 | return true; 96 | } 97 | return false; 98 | } 99 | 100 | public boolean isReflexive() { 101 | if (start != null && end != null && start.getAppendant() != null && start.getAppendant().equals(end.getAppendant())) { 102 | return true; 103 | } 104 | return false; 105 | } 106 | 107 | public void changeDirection() { 108 | if (this.start == null || this.end == null) 109 | return; 110 | this.start.getAppendant().replaceEndpoint(this.start, this.end); 111 | this.end.getAppendant().replaceEndpoint(this.end, this.start); 112 | ModelBox tempModelBox = this.end.getAppendant(); 113 | this.end.setAppendant(this.start.getAppendant()); 114 | this.start.setAppendant(tempModelBox); 115 | setChanged(); 116 | notifyObservers(RelationChange.DIRECTION); 117 | } 118 | 119 | public void setStartMultiplicity(String multiplicity) { 120 | if (this.start == null) 121 | return; 122 | this.start.setMultiplicity(multiplicity); 123 | setChanged(); 124 | notifyObservers(RelationChange.MULTIPLCITY_ROLE); 125 | } 126 | 127 | public void setEndMultiplicity(String multiplicity) { 128 | if (this.end == null) 129 | return; 130 | this.end.setMultiplicity(multiplicity); 131 | setChanged(); 132 | notifyObservers(RelationChange.MULTIPLCITY_ROLE); 133 | } 134 | 135 | public void setStartRoleName(String roleName) { 136 | if (this.start == null) 137 | return; 138 | this.start.setRoleName(roleName); 139 | setChanged(); 140 | notifyObservers(RelationChange.MULTIPLCITY_ROLE); 141 | } 142 | 143 | public void setEndRoleName(String roleName) { 144 | if (this.end == null) 145 | return; 146 | this.end.setRoleName(roleName); 147 | setChanged(); 148 | notifyObservers(RelationChange.MULTIPLCITY_ROLE); 149 | } 150 | 151 | public enum RelationChange { 152 | COLOR, DIRECTION, MULTIPLCITY_ROLE; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/model/RelationType.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | public enum RelationType { 4 | 5 | UNDIRECTED_ASSOCIATION(EndpointType.NONE, EndpointType.NONE, LineType.CONTINUOUS_LINE), 6 | DIRECTED_ASSOCIATION(EndpointType.NONE, EndpointType.OPEN_ARROW, LineType.CONTINUOUS_LINE), 7 | BIDIRECTED_ASSOCIATION(EndpointType.OPEN_ARROW, EndpointType.OPEN_ARROW, LineType.CONTINUOUS_LINE), 8 | 9 | UNDIRECTED_AGGREGATION(EndpointType.EMPTY_DIAMOND, EndpointType.NONE, LineType.CONTINUOUS_LINE), 10 | DIRECTED_AGGREGATION(EndpointType.EMPTY_DIAMOND, EndpointType.OPEN_ARROW, LineType.CONTINUOUS_LINE), 11 | UNDIRECTED_COMPOSITION(EndpointType.FILLED_DIAMOND, EndpointType.NONE, LineType.CONTINUOUS_LINE), 12 | DIRECTED_COMPOSITION(EndpointType.FILLED_DIAMOND, EndpointType.OPEN_ARROW, LineType.CONTINUOUS_LINE), 13 | 14 | GENERALIZATION(EndpointType.NONE, EndpointType.EMPTY_ARROW, LineType.CONTINUOUS_LINE), 15 | DEPENDENCY(EndpointType.NONE, EndpointType.OPEN_ARROW, LineType.DASHED_LINE), 16 | ASSOZIATION_CLASS(EndpointType.NONE, EndpointType.NONE, LineType.DASHED_LINE), 17 | OBJDIAGRAM(EndpointType.NONE, EndpointType.NONE, LineType.CONTINUOUS_LINE), 18 | OBJGRAPH(EndpointType.NONE, EndpointType.FILLED_ARROW, LineType.CONTINUOUS_LINE); 19 | 20 | private final EndpointType startType; 21 | private final EndpointType endType; 22 | private final LineType lineType; 23 | 24 | RelationType(EndpointType startType, EndpointType endType, LineType lineType) { 25 | this.startType = startType; 26 | this.endType = endType; 27 | this.lineType = lineType; 28 | } 29 | 30 | public EndpointType getStartType() { 31 | return startType; 32 | } 33 | 34 | public EndpointType getEndType() { 35 | return endType; 36 | } 37 | 38 | public LineType getLineType() { 39 | return lineType; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/util/ColorUtil.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import javafx.scene.paint.Color; 4 | 5 | /** 6 | * Util.java 7 | *

8 | * Copyright (c) 2011-2015, JFXtras All rights reserved. 9 | *

10 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 11 | * following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of 12 | * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the 14 | * distribution. * Neither the name of the organization nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | *

17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 20 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 23 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | public class ColorUtil { 26 | 27 | public static double clamp(final double MIN, final double MAX, final double VALUE) { 28 | if (VALUE < MIN) return MIN; 29 | if (VALUE > MAX) return MAX; 30 | return VALUE; 31 | } 32 | 33 | public static Color brighter(final Color COLOR, final double FRACTION) { 34 | double red = clamp(0, 1, COLOR.getRed() * (1.0 + FRACTION)); 35 | double green = clamp(0, 1, COLOR.getGreen() * (1.0 + FRACTION)); 36 | double blue = clamp(0, 1, COLOR.getBlue() * (1.0 + FRACTION)); 37 | return new Color(red, green, blue, COLOR.getOpacity()); 38 | } 39 | 40 | public static Color darker(final Color COLOR, final double FRACTION) { 41 | double red = clamp(0, 1, COLOR.getRed() * (1.0 - FRACTION)); 42 | double green = clamp(0, 1, COLOR.getGreen() * (1.0 - FRACTION)); 43 | double blue = clamp(0, 1, COLOR.getBlue() * (1.0 - FRACTION)); 44 | return new Color(red, green, blue, COLOR.getOpacity()); 45 | } 46 | 47 | public static String colorToCssColor(final Color COLOR) { 48 | final StringBuilder CSS_COLOR = new StringBuilder(19); 49 | CSS_COLOR.append("rgba("); 50 | CSS_COLOR.append((int) (COLOR.getRed() * 255)).append(", "); 51 | CSS_COLOR.append((int) (COLOR.getGreen() * 255)).append(", "); 52 | CSS_COLOR.append((int) (COLOR.getBlue() * 255)).append(", "); 53 | CSS_COLOR.append(COLOR.getOpacity()).append(");"); 54 | return CSS_COLOR.toString(); 55 | } 56 | 57 | public static String colorToWebColor(final Color COLOR) { 58 | String red = Integer.toHexString((int) (COLOR.getRed() * 255)); 59 | if (red.length() == 1) red = "0" + red; 60 | String green = Integer.toHexString((int) (COLOR.getGreen() * 255)); 61 | if (green.length() == 1) green = "0" + green; 62 | String blue = Integer.toHexString((int) (COLOR.getBlue() * 255)); 63 | if (blue.length() == 1) blue = "0" + blue; 64 | return "#" + red + green + blue; 65 | } 66 | 67 | /** 68 | * Converts hex color string to color supported formats 0xRRGGBB 0xRRGGBBAA #RRGGBB #RRGGBBAA RRGGBB RRGGBBAA 69 | * 70 | * @param COLOR 71 | * @return color given by hex string 72 | */ 73 | public static Color webColorToColor(final String COLOR) { 74 | int red; 75 | int green; 76 | int blue; 77 | double alpha = 1.0; 78 | if (COLOR.startsWith("0x")) { 79 | red = Integer.valueOf(COLOR.substring(2, 4), 16); 80 | green = Integer.valueOf(COLOR.substring(4, 6), 16); 81 | blue = Integer.valueOf(COLOR.substring(6, 8), 16); 82 | if (COLOR.length() > 8) { 83 | alpha = 1.0 / 255.0 * (double) (Integer.valueOf(COLOR.substring(8, 10), 16)); 84 | } 85 | } 86 | else if (COLOR.startsWith("#")) { 87 | red = Integer.valueOf(COLOR.substring(1, 3), 16); 88 | green = Integer.valueOf(COLOR.substring(3, 5), 16); 89 | blue = Integer.valueOf(COLOR.substring(5, 7), 16); 90 | if (COLOR.length() > 7) { 91 | alpha = 1.0 / 255.0 * (double) (Integer.valueOf(COLOR.substring(7, 9), 16)); 92 | } 93 | } 94 | else { 95 | red = Integer.valueOf(COLOR.substring(0, 2), 16); 96 | green = Integer.valueOf(COLOR.substring(2, 4), 16); 97 | blue = Integer.valueOf(COLOR.substring(4, 6), 16); 98 | if (COLOR.length() > 6) { 99 | alpha = 1.0 / 255.0 * (double) (Integer.valueOf(COLOR.substring(6, 8), 16)); 100 | } 101 | } 102 | return Color.rgb(red, green, blue, alpha); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/util/FXMLResourceUtil.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import ch.hsr.ogv.util.ResourceLocator.Resource; 4 | import javafx.fxml.FXMLLoader; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.io.IOException; 9 | 10 | public class FXMLResourceUtil { 11 | 12 | private final static Logger logger = LoggerFactory.getLogger(FXMLResourceUtil.class); 13 | 14 | public static Object loadPreset(Resource resource) { 15 | FXMLLoader loader = new FXMLLoader(); 16 | loader.setLocation(ResourceLocator.getResourcePath(resource)); 17 | try { 18 | return loader.load(); 19 | } 20 | catch (IOException e) { 21 | logger.debug(e.getMessage()); 22 | } 23 | return null; 24 | } 25 | 26 | public static FXMLLoader prepareLoader(Resource resource) { 27 | FXMLLoader loader = new FXMLLoader(); 28 | loader.setLocation(ResourceLocator.getResourcePath(resource)); 29 | return loader; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/util/GeometryUtil.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import javafx.geometry.Point2D; 4 | import javafx.geometry.Point3D; 5 | 6 | public class GeometryUtil { 7 | 8 | public static Point2D lineIntersect(Point2D firstLineStart, Point2D firstLineEnd, Point2D secondLineStart, Point2D secondLineEnd) { 9 | double x1 = firstLineStart.getX(), y1 = firstLineStart.getY(), x2 = firstLineEnd.getX(), y2 = firstLineEnd.getY(), x3 = secondLineStart.getX(), y3 = secondLineStart.getY(), x4 = secondLineEnd 10 | .getX(), y4 = secondLineEnd.getY(); 11 | return GeometryUtil.lineIntersect(x1, y1, x2, y2, x3, y3, x4, y4); 12 | } 13 | 14 | public static Point2D lineIntersect(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { 15 | double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); 16 | if (denom == 0.0) { // Lines are parallel. 17 | return null; 18 | } 19 | double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom; 20 | double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom; 21 | if (ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0) { 22 | // Get the intersection point. 23 | return new Point2D(x1 + ua * (x2 - x1), y1 + ua * (y2 - y1)); 24 | } 25 | return null; 26 | } 27 | 28 | public static double rotateYAngle(Point3D p1, Point3D p2) { 29 | double xDiff = p2.getX() - p1.getX(); 30 | double zDiff = p2.getZ() - p1.getZ(); 31 | return Math.toDegrees(Math.atan2(xDiff, zDiff)); 32 | } 33 | 34 | public static double rotateXAngle(Point3D p1, Point3D p2) { 35 | double height = p2.getY() - p1.getY(); 36 | double hypothenuse = p1.distance(p2); 37 | if (hypothenuse == 0.0) { 38 | return 0.0; 39 | } 40 | return Math.toDegrees(Math.asin(height / hypothenuse)); 41 | } 42 | 43 | public static Point2D divideLineFraction(Point2D start, Point2D end, double fraction) { 44 | double x = start.getX() + fraction * (end.getX() - start.getX()); 45 | double y = start.getY() + fraction * (end.getY() - start.getY()); 46 | return new Point2D(x, y); 47 | } 48 | 49 | public static Point3D divideLineFraction(Point3D start, Point3D end, double fraction) { 50 | double x = start.getX() + fraction * (end.getX() - start.getX()); 51 | double y = start.getY() + fraction * (end.getY() - start.getY()); 52 | double z = start.getZ() + fraction * (end.getZ() - start.getZ()); 53 | return new Point3D(x, y, z); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/util/MessageBar.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import ch.hsr.ogv.util.ResourceLocator.Resource; 4 | import javafx.concurrent.Task; 5 | import javafx.geometry.Insets; 6 | import javafx.scene.control.TextField; 7 | import javafx.scene.layout.HBox; 8 | import javafx.scene.layout.Priority; 9 | 10 | import java.util.concurrent.atomic.AtomicBoolean; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | public class MessageBar { 14 | 15 | private static int CLEAR_TIME_SECOND = 5; 16 | private static TextField messageBar; 17 | private final static String defaultStyle; 18 | 19 | private static AtomicInteger countDown = new AtomicInteger(0); 20 | private static AtomicBoolean taskRunning = new AtomicBoolean(false); 21 | 22 | public static TextField getTextField() { 23 | synchronized (messageBar) { 24 | return messageBar; 25 | } 26 | } 27 | 28 | static { 29 | messageBar = new TextField(); 30 | defaultStyle = messageBar.getStyle(); 31 | messageBar.setEditable(false); 32 | messageBar.setFocusTraversable(false); 33 | messageBar.setDisable(true); 34 | messageBar.setMinHeight(28); 35 | HBox.setHgrow(messageBar, Priority.ALWAYS); 36 | HBox.setMargin(messageBar, new Insets(5, 5, 5, 5)); 37 | } 38 | 39 | public static void setText(String text, MessageLevel level) { 40 | synchronized (messageBar) { 41 | messageBar.setText(text); 42 | switch (level) { 43 | case INFO: 44 | String iconStyleInfo = "-fx-background-image:url(\"" + ResourceLocator.getResourcePath(Resource.MESSAGE_INFO_PNG).toExternalForm() + "\");"; 45 | messageBar.setStyle(iconStyleInfo 46 | + " -fx-padding: 0 5 0 25; -fx-background-repeat: no-repeat; -fx-background-position: left center; -fx-font-weight: bold; -fx-text-inner-color: #000000;"); 47 | break; 48 | case WARN: 49 | String iconStyleWarn = "-fx-background-image:url(\"" + ResourceLocator.getResourcePath(Resource.MESSAGE_WARN_PNG).toExternalForm() + "\");"; 50 | messageBar.setStyle(iconStyleWarn 51 | + " -fx-padding: 0 5 0 25; -fx-background-repeat: no-repeat; -fx-background-position: left center; -fx-font-weight: bold; -fx-text-inner-color: #717100;"); 52 | break; 53 | case ALERT: 54 | String iconStyleError = "-fx-background-image:url(\"" + ResourceLocator.getResourcePath(Resource.MESSAGE_ERROR_PNG).toExternalForm() + "\");"; 55 | messageBar.setStyle(iconStyleError 56 | + " -fx-padding: 0 5 0 25; -fx-background-repeat: no-repeat; -fx-background-position: left center; -fx-font-weight: bold; -fx-text-inner-color: #CC2900;"); 57 | break; 58 | default: 59 | // String iconStyleDefault = "-fx-background-image:url(\"" + ResourceLocator.getResourcePath(Resource.MESSAGE_DEFAULT_PNG).toExternalForm() + "\");"; 60 | // messageBar.setStyle(iconStyleDefault 61 | // + " -fx-padding: 0 5 0 25; -fx-background-repeat: no-repeat; -fx-background-position: left center; -fx-font-weight: bold; -fx-text-inner-color: transparent;"); 62 | messageBar.setStyle(defaultStyle); 63 | break; 64 | } 65 | countDown.set(CLEAR_TIME_SECOND); 66 | if (!taskRunning.get()) { 67 | taskRunning.set(true); 68 | new Thread(new MessageTask()).start(); 69 | } 70 | } 71 | } 72 | 73 | public static class MessageTask extends Task { 74 | 75 | @Override 76 | protected Void call() throws Exception { 77 | while (countDown.get() > 0) { 78 | Thread.sleep(1000); 79 | countDown.decrementAndGet(); 80 | } 81 | messageBar.clear(); 82 | // String iconStyleDefault = "-fx-background-image:url(\"" + ResourceLocator.getResourcePath(Resource.MESSAGE_DEFAULT_PNG).toExternalForm() + "\");\n"; 83 | try { 84 | // messageBar.setStyle(iconStyleDefault + "-fx-padding: 0 5 0 25;\n-fx-background-repeat: no-repeat;\n-fx-background-position: left center;\n-fx-font-weight: bold;"); 85 | messageBar.setStyle(defaultStyle); 86 | } 87 | catch (Exception e) { 88 | } 89 | taskRunning.set(false); 90 | return null; 91 | } 92 | 93 | } 94 | 95 | public enum MessageLevel { 96 | INFO, WARN, ALERT; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/util/ObjModelLoader.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import com.interactivemesh.jfx.importer.ImportException; 4 | import com.interactivemesh.jfx.importer.obj.ObjModelImporter; 5 | import javafx.scene.Node; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.net.URL; 10 | 11 | public class ObjModelLoader { 12 | 13 | private final static Logger logger = LoggerFactory.getLogger(ObjModelLoader.class); 14 | 15 | public static Node[] load(URL modelUrl) { 16 | Node[] rootNodes = {}; 17 | if (modelUrl != null) { 18 | ObjModelImporter tdsImporter = new ObjModelImporter(); 19 | try { 20 | tdsImporter.read(modelUrl); 21 | } 22 | catch (ImportException e) { 23 | e.printStackTrace(); 24 | logger.debug(e.getMessage()); 25 | } 26 | return tdsImporter.getImport(); 27 | } 28 | return rootNodes; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/util/ResourceLocator.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import java.net.URL; 4 | 5 | public class ResourceLocator { 6 | 7 | public static URL getResourcePath(Resource res) { 8 | return ResourceLocator.class.getClassLoader().getResource(res.getRelativePath()); 9 | } 10 | 11 | public enum Resource { 12 | 13 | ICON_GIF("images/OGV.gif"), 14 | 15 | ROOTLAYOUT_FXML("templates/RootLayout.fxml"), 16 | PANEPRESET_FXML("templates/PanePreset.fxml"), 17 | TOPTEXTFIELD_FXML("templates/TopTextField.fxml"), 18 | CENTERLABEL_FXML("templates/CenterLabel.fxml"), 19 | CENTERTEXTFIELD_FXML("templates/CenterTextField.fxml"), 20 | ARROWTEXTFIELD_FXML("templates/ArrowTextField.fxml"), 21 | 22 | LUCIDASANS_TTF("fonts/LUCIDASANSREGULAR.TTF"), 23 | SEGOEUI_TTF("fonts/SEGOEUI.TTF"), 24 | 25 | SCENE_CSS("css/Scene.css"), 26 | TSPLITMENUBUTTON_CSS("css/TSplitMenuButton.css"), 27 | TEXTFIELD_CSS("css/TextField.css"), 28 | 29 | OPEN_ARROW_OBJ("models/open_arrow.obj"), 30 | FILLED_ARROW_OBJ("models/filled_arrow.obj"), 31 | EMPTY_ARROW_OBJ("models/empty_arrow.obj"), 32 | FILLED_DIAMOND_OBJ("models/filled_diamond.obj"), 33 | EMPTY_DIAMOND_OBJ("models/empty_diamond.obj"), 34 | ARC_OBJ("models/arc.obj"), 35 | 36 | UNDIRECTED_ASSOCIATION_GIF("images/menu/assoc.gif"), 37 | DIRECTED_ASSOCIATION_GIF("images/menu/assoWithNav.gif"), 38 | BIDIRECTED_ASSOCIATION_GIF("images/menu/assoNavToNav.gif"), 39 | UNDIRECTED_AGGREGATION_GIF("images/menu/aggregation.gif"), 40 | DIRECTED_AGGREGATION_GIF("images/menu/aggregationToNavi.gif"), 41 | UNDIRECTED_COMPOSITION_GIF("images/menu/composite.gif"), 42 | DIRECTED_COMPOSITION_GIF("images/menu/compositeToNavi.gif"), 43 | GENERALIZATION_GIF("images/menu/general.gif"), 44 | DEPENDENCY_GIF("images/menu/depend.gif"), 45 | OBJRELATION_GIF("images/menu/rightAngleOff.gif"), 46 | 47 | IMPORT_PNG("images/menu/application-import.png"), 48 | ADD_ATTR_GIF("images/menu/artifactPrj.gif"), 49 | CLASS_GIF("images/menu/structureclass.gif"), 50 | OBJECT_GIF("images/menu/instance.gif"), 51 | RELATION_GIF("images/menu/relation.gif"), 52 | RENAME_GIF("images/menu/text_box2.gif"), 53 | RENAME_ATTR_GIF("images/menu/testcase.gif"), 54 | MOVE_UP_PNG("images/menu/bullet_arrow_up.png"), 55 | MOVE_DOWN_PNG("images/menu/bullet_arrow_down.png"), 56 | CHANGE_DIRECTION_GIF("images/menu/synchronize_dgm_tab.gif"), 57 | ASSOCIATION_CLASS_GIF("images/menu/associationClass.gif"), 58 | ADD_MULTIPLICITY_GIF("images/menu/multiplicity.gif"), 59 | ADD_ROLE_GIF("images/menu/ColRole.gif"), 60 | DELETE_PNG("images/menu/trash.png"), 61 | 62 | MESSAGE_DEFAULT_PNG("images/menu/message_default.png"), 63 | MESSAGE_INFO_PNG("images/menu/message_info.png"), 64 | MESSAGE_WARN_PNG("images/menu/message_warn.png"), 65 | MESSAGE_ERROR_PNG("images/menu/message_error.png"); 66 | 67 | private String relativePath = "./"; 68 | 69 | private Resource(String relativePath) { 70 | this.setRelativePath(relativePath); 71 | } 72 | 73 | public String getRelativePath() { 74 | return relativePath; 75 | } 76 | 77 | public void setRelativePath(String relativePath) { 78 | this.relativePath = relativePath; 79 | } 80 | 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/util/TextUtil.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import javafx.scene.text.Font; 4 | import javafx.scene.text.Text; 5 | 6 | import java.util.Collection; 7 | import java.util.Iterator; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | public class TextUtil { 12 | 13 | private static final Text helper = new Text(); 14 | private static final double DEFAULT_WRAPPING_WIDTH = helper.getWrappingWidth(); 15 | private static final double DEFAULT_LINE_SPACING = helper.getLineSpacing(); 16 | private static final String DEFAULT_TEXT = helper.getText(); 17 | 18 | // private static final TextBoundsType DEFAULT_BOUNDS_TYPE = helper.getBoundsType(); 19 | 20 | public static double computeTextWidth(Font font, String text, double help) { 21 | helper.setText(text); 22 | helper.setFont(font); 23 | 24 | helper.setWrappingWidth(0.0D); 25 | helper.setLineSpacing(0.0D); 26 | double d = Math.min(helper.prefWidth(-1.0D), help); 27 | helper.setWrappingWidth((int) Math.ceil(d)); 28 | d = Math.ceil(helper.getLayoutBounds().getWidth()); 29 | 30 | helper.setWrappingWidth(DEFAULT_WRAPPING_WIDTH); 31 | helper.setLineSpacing(DEFAULT_LINE_SPACING); 32 | helper.setText(DEFAULT_TEXT); 33 | return d; 34 | } 35 | 36 | public static String countUpTrailing(String str, int startValue) { 37 | Pattern p = Pattern.compile("[0-9]+$"); 38 | Matcher m = p.matcher(str); 39 | if (m.find()) { 40 | String trailingNumber = m.group(); 41 | if (trailingNumber != null) { 42 | try { 43 | int parsedNumber = Integer.parseInt(trailingNumber); 44 | int retNumber = 0; 45 | if (parsedNumber < startValue) { 46 | retNumber = startValue; 47 | } 48 | else { 49 | retNumber = parsedNumber += 1; 50 | } 51 | int digitCount = ("" + parsedNumber).length(); 52 | return str.substring(0, str.length() - digitCount) + retNumber; 53 | } 54 | catch (NumberFormatException nfe) { 55 | return str + startValue; 56 | } 57 | } 58 | } 59 | return str + startValue; 60 | } 61 | 62 | public static String replaceLast(String text, String regex, String replacement) { 63 | return text.replaceFirst("(?s)(.*)" + regex, "$1" + replacement); 64 | } 65 | 66 | public static String join(Collection s, String delimiter) { 67 | StringBuffer buffer = new StringBuffer(); 68 | Iterator iter = s.iterator(); 69 | while (iter.hasNext()) { 70 | buffer.append(iter.next()); 71 | if (iter.hasNext()) { 72 | buffer.append(delimiter); 73 | } 74 | } 75 | return buffer.toString(); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/ArrowEdge.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import ch.hsr.ogv.model.EndpointType; 4 | import ch.hsr.ogv.util.ObjModelLoader; 5 | import ch.hsr.ogv.util.ResourceLocator; 6 | import ch.hsr.ogv.util.ResourceLocator.Resource; 7 | import javafx.scene.Group; 8 | import javafx.scene.Node; 9 | import javafx.scene.paint.Color; 10 | import javafx.scene.paint.PhongMaterial; 11 | import javafx.scene.shape.MeshView; 12 | import javafx.scene.transform.Rotate; 13 | 14 | import java.net.URL; 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | public class ArrowEdge extends Group { 20 | 21 | private Color color = Color.BLACK; 22 | private List meshViews = new ArrayList(); 23 | private double additionalGap; 24 | 25 | private EndpointType endpointType; 26 | 27 | public double getAdditionalGap() { 28 | return this.additionalGap; 29 | } 30 | 31 | public ArrowEdge(Color color) { 32 | this(EndpointType.NONE, color); 33 | } 34 | 35 | public ArrowEdge(EndpointType endpointType, Color color) { 36 | this.endpointType = endpointType; 37 | this.color = color; 38 | loadModel(); 39 | } 40 | 41 | private void loadModel() { 42 | URL modelUrl = null; 43 | switch (this.endpointType) { 44 | case EMPTY_ARROW: 45 | modelUrl = ResourceLocator.getResourcePath(Resource.EMPTY_ARROW_OBJ); 46 | this.additionalGap = 30; 47 | break; 48 | case EMPTY_DIAMOND: 49 | modelUrl = ResourceLocator.getResourcePath(Resource.EMPTY_DIAMOND_OBJ); 50 | this.additionalGap = 50; 51 | break; 52 | case FILLED_ARROW: 53 | modelUrl = ResourceLocator.getResourcePath(Resource.FILLED_ARROW_OBJ); 54 | this.additionalGap = 0; 55 | break; 56 | case FILLED_DIAMOND: 57 | modelUrl = ResourceLocator.getResourcePath(Resource.FILLED_DIAMOND_OBJ); 58 | this.additionalGap = 0; 59 | break; 60 | case OPEN_ARROW: 61 | modelUrl = ResourceLocator.getResourcePath(Resource.OPEN_ARROW_OBJ); 62 | this.additionalGap = 0; 63 | break; 64 | case ARC: 65 | modelUrl = ResourceLocator.getResourcePath(Resource.ARC_OBJ); 66 | this.additionalGap = 50; 67 | break; 68 | case NONE: 69 | this.additionalGap = 0; 70 | break; 71 | default: 72 | this.additionalGap = 0; 73 | break; 74 | } 75 | loadModel(modelUrl); 76 | } 77 | 78 | private void loadModel(URL modelUrl) { 79 | Node[] rootNodes = ObjModelLoader.load(modelUrl); 80 | for (Node n : rootNodes) { 81 | MeshView mv = (MeshView) n; 82 | this.meshViews.add(mv); 83 | } 84 | setColor(this.color); 85 | getChildren().clear(); 86 | getChildren().addAll(Arrays.asList(rootNodes)); 87 | } 88 | 89 | public Color getColor() { 90 | return this.color; 91 | } 92 | 93 | public void setColor(Color color) { 94 | this.color = color; 95 | PhongMaterial material = new PhongMaterial(); 96 | material.setDiffuseColor(this.color); 97 | material.setSpecularColor(this.color.brighter()); 98 | for (MeshView mv : this.meshViews) { 99 | mv.setMaterial(material); 100 | } 101 | } 102 | 103 | public EndpointType getEndpointType() { 104 | return endpointType; 105 | } 106 | 107 | public void setEndpointType(EndpointType endpointType) { 108 | this.endpointType = endpointType; 109 | loadModel(); 110 | } 111 | 112 | public void setRotateYAxis(double degree) { 113 | setRotationAxis(Rotate.Y_AXIS); 114 | setRotate(degree); 115 | } 116 | 117 | public void setRotateXAxis(double degree) { 118 | setRotationAxis(Rotate.X_AXIS); 119 | setRotate(degree); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/ArrowLabel.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import ch.hsr.ogv.util.ColorUtil; 4 | import ch.hsr.ogv.util.FXMLResourceUtil; 5 | import ch.hsr.ogv.util.ResourceLocator.Resource; 6 | import ch.hsr.ogv.util.TextUtil; 7 | import javafx.application.Platform; 8 | import javafx.geometry.Insets; 9 | import javafx.geometry.Point3D; 10 | import javafx.geometry.Pos; 11 | import javafx.scene.CacheHint; 12 | import javafx.scene.DepthTest; 13 | import javafx.scene.Group; 14 | import javafx.scene.control.TextField; 15 | import javafx.scene.layout.HBox; 16 | import javafx.scene.layout.Priority; 17 | import javafx.scene.paint.Color; 18 | import javafx.scene.text.Font; 19 | import javafx.scene.text.Text; 20 | import javafx.scene.transform.Rotate; 21 | 22 | public class ArrowLabel extends Group { 23 | 24 | private static final double MIN_WIDTH = 20; 25 | private static final Color SELECTION_COLOR = Color.DODGERBLUE; 26 | 27 | private HBox container = new HBox(); 28 | private Text arrowText; 29 | private TextField arrowTextField; 30 | private Point3D coords = new Point3D(0, 0, 0); 31 | 32 | private Color color = Color.BLACK; 33 | 34 | private volatile boolean isLabelSelected = false; 35 | 36 | public HBox getContainer() { 37 | return container; 38 | } 39 | 40 | public Text getArrowText() { 41 | return arrowText; 42 | } 43 | 44 | public TextField getArrowTextField() { 45 | return arrowTextField; 46 | } 47 | 48 | public Point3D getDiffCoords() { 49 | return coords; 50 | } 51 | 52 | public void setDiffCoords(Point3D diffCoords) { 53 | this.coords = diffCoords; 54 | setTranslate(); 55 | } 56 | 57 | public ArrowLabel() { 58 | this.arrowText = new Text(""); 59 | this.arrowTextField = loadTextField(); 60 | this.container.setStyle("-fx-border-color: transparent;\n" + "-fx-border-width: 1;"); 61 | this.container.setCacheHint(CacheHint.SCALE_AND_ROTATE); 62 | this.container.setDepthTest(DepthTest.ENABLE); 63 | this.container.setAlignment(Pos.CENTER); 64 | this.container.getChildren().add(this.arrowText); 65 | this.container.setMaxWidth(Double.MAX_VALUE); 66 | this.container.setPadding(new Insets(2, 0, 2, 0)); 67 | HBox.setHgrow(this.arrowTextField, Priority.ALWAYS); 68 | setWidth(calcMinWidth()); 69 | setTranslate(); 70 | this.container.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); 71 | this.container.getTransforms().add(new Rotate(180, Rotate.Z_AXIS)); 72 | getChildren().add(this.container); 73 | showLabel(false); 74 | } 75 | 76 | private TextField loadTextField() { 77 | Object loadedPreset = FXMLResourceUtil.loadPreset(Resource.ARROWTEXTFIELD_FXML); // load center textfield preset from fxml file 78 | if (loadedPreset != null && loadedPreset instanceof TextField) { 79 | return (TextField) loadedPreset; 80 | } 81 | return new TextField(); 82 | } 83 | 84 | public Color getColor() { 85 | return color; 86 | } 87 | 88 | public void setColor(Color color) { 89 | this.color = color; 90 | this.arrowText.setFill(color); 91 | } 92 | 93 | public boolean isLabelSelected() { 94 | return isLabelSelected; 95 | } 96 | 97 | public void setLabelSelected(boolean isLabelSelected) { 98 | this.isLabelSelected = isLabelSelected; 99 | if (isLabelSelected) { 100 | this.container.setStyle("-fx-border-color: " + ColorUtil.colorToCssColor(SELECTION_COLOR) + ";\n" + "-fx-border-width: 1;"); 101 | setColor(SELECTION_COLOR); 102 | } 103 | else { 104 | this.container.setStyle("-fx-border-color: transparent;\n" + "-fx-border-width: 1;"); 105 | setColor(Color.BLACK); 106 | } 107 | } 108 | 109 | public void allowTextInput(boolean value) { 110 | this.container.getChildren().clear(); 111 | if (value) { 112 | this.container.getChildren().add(this.arrowTextField); 113 | this.container.setPadding(new Insets(0, 0, 0, 0)); 114 | Platform.runLater(() -> { 115 | this.arrowTextField.requestFocus(); 116 | this.arrowTextField.selectAll(); 117 | this.arrowTextField.applyCss(); 118 | }); 119 | } 120 | else { 121 | this.container.getChildren().add(this.arrowText); 122 | this.container.setPadding(new Insets(2, 0, 2, 0)); 123 | if (isLabelSelected()) { 124 | setLabelSelected(true); 125 | } 126 | } 127 | this.arrowTextField.setEditable(value); 128 | this.arrowTextField.setDisable(!value); 129 | } 130 | 131 | public String getTextFieldText() { 132 | return this.arrowTextField.getText(); 133 | } 134 | 135 | public String getLabelText() { 136 | return this.arrowText.getText(); 137 | } 138 | 139 | public void setText(String text) { 140 | showLabel(text != null && !text.isEmpty()); 141 | this.arrowText.setText(text); 142 | this.arrowTextField.setText(text); 143 | } 144 | 145 | public Font getFont() { 146 | return this.arrowTextField.getFont(); 147 | } 148 | 149 | public void setFont(Font font) { 150 | this.arrowText.setFont(font); 151 | this.arrowTextField.setFont(font); 152 | } 153 | 154 | public void setCoordsX(double x) { 155 | this.coords = new Point3D(x, this.coords.getY(), this.coords.getZ()); 156 | setTranslateX(this.coords.getX()); 157 | } 158 | 159 | public void setCoordsY(double y) { 160 | this.coords = new Point3D(this.coords.getX(), y, this.coords.getZ()); 161 | setTranslateY(this.coords.getY()); 162 | } 163 | 164 | public void setCoordsZ(double z) { 165 | this.coords = new Point3D(this.coords.getX(), this.coords.getY(), z); 166 | setTranslateZ(this.coords.getZ()); 167 | } 168 | 169 | public void setTranslateXYZ(double x, double y, double z) { 170 | setCoordsX(x); 171 | setCoordsY(y); 172 | setCoordsZ(z); 173 | } 174 | 175 | private void setTranslate() { 176 | setTranslateX(this.coords.getX()); 177 | setTranslateY(this.coords.getY()); 178 | setTranslateZ(this.coords.getZ()); 179 | } 180 | 181 | public void setRotateYAxis(double degree) { 182 | setRotationAxis(Rotate.Y_AXIS); 183 | setRotate(degree); 184 | } 185 | 186 | public double calcMinWidth() { 187 | return TextUtil.computeTextWidth(getFont(), getTextFieldText(), 0.0D) + 15; 188 | } 189 | 190 | public void setWidth(double width) { 191 | if (width < MIN_WIDTH) { 192 | width = MIN_WIDTH; 193 | } 194 | this.container.setMinWidth(width); 195 | this.container.prefWidth(width); 196 | this.arrowText.prefWidth(width); 197 | this.arrowTextField.setPrefWidth(width); 198 | this.arrowTextField.selectAll(); 199 | this.arrowTextField.deselect(); 200 | } 201 | 202 | public void showLabel(boolean show) { 203 | if (!show) { 204 | setLabelSelected(false); 205 | allowTextInput(false); 206 | this.arrowText.setText(""); 207 | this.arrowTextField.setText(""); 208 | } 209 | this.arrowText.setVisible(show); 210 | this.arrowText.setDisable(!show); 211 | this.arrowTextField.setVisible(show); 212 | this.arrowTextField.setEditable(show); 213 | this.arrowTextField.setDisable(!show); 214 | setMouseTransparent(!show); 215 | } 216 | 217 | } 218 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/ArrowSelection.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.geometry.Point3D; 4 | import javafx.scene.Group; 5 | import javafx.scene.paint.Color; 6 | 7 | public class ArrowSelection extends Group { 8 | 9 | private final static int INIT_SELECT_SIZE = 4; 10 | private final static Color SELECTION_COLOR = Color.DODGERBLUE; 11 | 12 | private SphereAdapter sphereStart; 13 | private SphereAdapter sphereEnd; 14 | 15 | public ArrowSelection() { 16 | this.sphereStart = new SphereAdapter(SELECTION_COLOR, INIT_SELECT_SIZE); 17 | this.sphereEnd = new SphereAdapter(SELECTION_COLOR, INIT_SELECT_SIZE); 18 | getChildren().addAll(this.sphereStart, this.sphereEnd); 19 | } 20 | 21 | private void setStartXYZ(Point3D point) { 22 | this.sphereStart.setTranslateX(point.getX()); 23 | this.sphereStart.setTranslateY(point.getY()); 24 | this.sphereStart.setTranslateZ(point.getZ()); 25 | } 26 | 27 | private void setEndXYZ(Point3D point) { 28 | this.sphereEnd.setTranslateX(point.getX()); 29 | this.sphereEnd.setTranslateY(point.getY()); 30 | this.sphereEnd.setTranslateZ(point.getZ()); 31 | } 32 | 33 | public void setStartEndXYZ(Point3D start, Point3D end) { 34 | setStartXYZ(start); 35 | setEndXYZ(end); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/Axis.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import ch.hsr.ogv.util.ColorUtil; 4 | import javafx.scene.Group; 5 | import javafx.scene.paint.Color; 6 | import javafx.scene.paint.PhongMaterial; 7 | import javafx.scene.shape.Box; 8 | 9 | public class Axis extends Group { 10 | 11 | private static final int LENGTH = 200; 12 | private static final int WIDTH = 2; 13 | 14 | private Color getBrighterColor(Color c) { 15 | return ColorUtil.brighter(c, 0.9); 16 | } 17 | 18 | public Axis() { 19 | final PhongMaterial redMaterial = new PhongMaterial(); 20 | redMaterial.setDiffuseColor(getBrighterColor(Color.DARKRED)); 21 | redMaterial.setSpecularColor(getBrighterColor(Color.RED)); 22 | 23 | final PhongMaterial greenMaterial = new PhongMaterial(); 24 | greenMaterial.setDiffuseColor(getBrighterColor(Color.DARKGREEN)); 25 | greenMaterial.setSpecularColor(getBrighterColor(Color.GREEN)); 26 | 27 | final PhongMaterial blueMaterial = new PhongMaterial(); 28 | blueMaterial.setDiffuseColor(getBrighterColor(Color.DARKBLUE)); 29 | blueMaterial.setSpecularColor(getBrighterColor(Color.BLUE)); 30 | 31 | final Box xAxis = new Box(LENGTH, WIDTH, WIDTH); 32 | final Box yAxis = new Box(WIDTH, LENGTH, WIDTH); 33 | final Box zAxis = new Box(WIDTH, WIDTH, LENGTH); 34 | 35 | xAxis.setMaterial(redMaterial); 36 | yAxis.setMaterial(greenMaterial); 37 | zAxis.setMaterial(blueMaterial); 38 | 39 | getChildren().addAll(xAxis, yAxis, zAxis); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/BoxSelection.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.scene.Group; 4 | import javafx.scene.paint.Color; 5 | import javafx.scene.transform.Rotate; 6 | 7 | public class BoxSelection extends Group { 8 | 9 | public final static int INIT_SELECT_SIZE = 4; 10 | private final static Color SELECTION_COLOR = Color.DODGERBLUE; 11 | 12 | private Group selection = new Group(); 13 | private Cuboid box; 14 | 15 | private Group pointNE = new Group(); 16 | private Group pointNW = new Group(); 17 | private Group pointSE = new Group(); 18 | private Group pointSW = new Group(); 19 | 20 | private Group lineN = new Group(); 21 | private Group lineE = new Group(); 22 | private Group lineS = new Group(); 23 | private Group lineW = new Group(); 24 | 25 | public Group getPointNE() { 26 | return this.pointNE; 27 | } 28 | 29 | public Group getPointNW() { 30 | return this.pointNW; 31 | } 32 | 33 | public Group getPointSE() { 34 | return this.pointSE; 35 | } 36 | 37 | public Group getPointSW() { 38 | return this.pointSW; 39 | } 40 | 41 | public Group getLineN() { 42 | return this.lineN; 43 | } 44 | 45 | public Group getLineE() { 46 | return this.lineE; 47 | } 48 | 49 | public Group getLineS() { 50 | return this.lineS; 51 | } 52 | 53 | public Group getLineW() { 54 | return this.lineW; 55 | } 56 | 57 | public BoxSelection(Cuboid box) { 58 | this.box = box; 59 | buildSelection(); 60 | getChildren().add(selection); 61 | } 62 | 63 | private void buildSelection() { 64 | 65 | for (int i = 0; i < 8; i++) { 66 | SphereAdapter sphere = new SphereAdapter(SELECTION_COLOR, INIT_SELECT_SIZE); 67 | 68 | CylinderAdapter cylinderV = new CylinderAdapter(SELECTION_COLOR, INIT_SELECT_SIZE - 2, 10); 69 | cylinderV.heightProperty().bind(this.box.depthProperty()); 70 | cylinderV.translateYProperty().bind(this.box.translateYProperty()); 71 | 72 | CylinderAdapter cylinderH = new CylinderAdapter(SELECTION_COLOR, INIT_SELECT_SIZE - 2, 10); 73 | cylinderH.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); 74 | 75 | if (i == 0 || i == 1 || i == 4 || i == 5) { 76 | sphere.translateZProperty().bind(this.box.translateZProperty().subtract(this.box.heightProperty().divide(2))); 77 | cylinderV.translateZProperty().bind(this.box.translateZProperty().subtract(this.box.heightProperty().divide(2))); 78 | if (i == 0 || i == 1) { 79 | cylinderH.translateZProperty().bind(this.box.translateZProperty().subtract(this.box.heightProperty().divide(2))); 80 | cylinderH.getTransforms().add(new Rotate(90, Rotate.Z_AXIS)); 81 | cylinderH.heightProperty().bind(this.box.widthProperty()); 82 | this.lineS.getChildren().add(cylinderH); 83 | this.pointSE.getChildren().addAll(sphere, cylinderV); 84 | } 85 | } 86 | 87 | if (i == 0 || i == 1 || i == 6 || i == 7) { 88 | sphere.translateXProperty().bind(this.box.translateXProperty().subtract(this.box.widthProperty().divide(2))); 89 | cylinderV.translateXProperty().bind(this.box.translateXProperty().subtract(this.box.widthProperty().divide(2))); 90 | if (i == 6 || i == 7) { 91 | cylinderH.translateXProperty().bind(this.box.translateXProperty().add(this.box.widthProperty().divide(2))); 92 | cylinderH.heightProperty().bind(this.box.heightProperty()); 93 | this.lineW.getChildren().add(cylinderH); 94 | this.pointNE.getChildren().addAll(sphere, cylinderV); 95 | } 96 | } 97 | 98 | if (i == 2 || i == 3 || i == 6 || i == 7) { 99 | sphere.translateZProperty().bind(this.box.translateZProperty().add(this.box.heightProperty().divide(2))); 100 | cylinderV.translateZProperty().bind(this.box.translateZProperty().add(this.box.heightProperty().divide(2))); 101 | if (i == 2 || i == 3) { 102 | cylinderH.translateXProperty().bind(this.box.translateXProperty()); 103 | cylinderH.translateZProperty().bind(this.box.translateZProperty().add(this.box.heightProperty().divide(2))); 104 | cylinderH.getTransforms().add(new Rotate(90, Rotate.Z_AXIS)); 105 | cylinderH.heightProperty().bind(this.box.widthProperty()); 106 | this.lineN.getChildren().add(cylinderH); 107 | this.pointNW.getChildren().addAll(sphere, cylinderV); 108 | } 109 | } 110 | 111 | if (i == 2 || i == 3 || i == 4 || i == 5) { 112 | sphere.translateXProperty().bind(this.box.translateXProperty().add(this.box.widthProperty().divide(2))); 113 | cylinderV.translateXProperty().bind(this.box.translateXProperty().add(this.box.widthProperty().divide(2))); 114 | if (i == 4 || i == 5) { 115 | cylinderH.translateXProperty().bind(this.box.translateXProperty().subtract(this.box.widthProperty().divide(2))); 116 | cylinderH.translateZProperty().bind(this.box.translateZProperty()); 117 | cylinderH.heightProperty().bind(this.box.heightProperty()); 118 | this.lineE.getChildren().add(cylinderH); 119 | this.pointSW.getChildren().addAll(sphere, cylinderV); 120 | } 121 | } 122 | 123 | if (i % 2 == 1) { 124 | sphere.translateYProperty().bind(this.box.translateZProperty().subtract(this.box.depthProperty())); 125 | cylinderH.translateYProperty().bind(this.box.translateZProperty().subtract(this.box.depthProperty())); 126 | this.selection.getChildren().add(cylinderV); 127 | } 128 | } 129 | this.selection.getChildren().addAll(this.pointNE, this.pointSE, this.pointNW, this.pointSW); 130 | this.selection.getChildren().addAll(this.lineE, this.lineN, this.lineS, this.lineW); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/ConnectorBox.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.geometry.Point3D; 4 | import javafx.scene.Group; 5 | import javafx.scene.paint.PhongMaterial; 6 | import javafx.scene.shape.Box; 7 | 8 | public class ConnectorBox extends Group { 9 | 10 | public ConnectorBox(PaneBox paneBox, Point3D centerLabelPos, Arrow arrow) { 11 | Box conectorBox = new Box(arrow.getWidth(), paneBox.getDepth(), arrow.getWidth()); 12 | setTranslateX(centerLabelPos.getX() + PaneBox.HORIZONTAL_BORDER_GAP); 13 | setTranslateY(centerLabelPos.getY() + (paneBox.getDepth() / 2)); 14 | setTranslateZ(centerLabelPos.getZ()); 15 | PhongMaterial material = new PhongMaterial(); 16 | material.setDiffuseColor(arrow.getColor()); 17 | material.setSpecularColor(arrow.getColor().brighter()); 18 | conectorBox.setMaterial(material); 19 | getChildren().add(conectorBox); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/Cuboid.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.beans.property.DoubleProperty; 4 | import javafx.scene.CacheHint; 5 | import javafx.scene.DepthTest; 6 | import javafx.scene.Group; 7 | import javafx.scene.paint.Color; 8 | import javafx.scene.paint.PhongMaterial; 9 | import org.fxyz.shapes.primitives.CuboidMesh; 10 | 11 | public class Cuboid extends Group { 12 | 13 | private CuboidMesh box = null; 14 | private Color color; 15 | 16 | public Cuboid() { 17 | this(10); 18 | } 19 | 20 | public Cuboid(double size) { 21 | this(Color.WHITE, size); 22 | } 23 | 24 | public Cuboid(Color color, double size) { 25 | this.box = new CuboidMesh(size, size, size); 26 | this.box.setDepthTest(DepthTest.ENABLE); 27 | this.box.setCache(true); 28 | this.box.setCacheHint(CacheHint.SCALE_AND_ROTATE); 29 | setColor(color); 30 | getChildren().add(this.box); 31 | } 32 | 33 | public Color getColor() { 34 | return this.color; 35 | } 36 | 37 | public void setColor(Color color) { 38 | this.color = color; 39 | PhongMaterial material = new PhongMaterial(); 40 | material.setDiffuseColor(this.color); 41 | material.setSpecularColor(this.color.brighter()); 42 | this.box.setMaterial(material); 43 | } 44 | 45 | public DoubleProperty widthProperty() { 46 | return this.box.widthProperty(); 47 | } 48 | 49 | public DoubleProperty heightProperty() { 50 | return this.box.heightProperty(); 51 | } 52 | 53 | public DoubleProperty depthProperty() { 54 | return this.box.depthProperty(); 55 | } 56 | 57 | public void setDrawTopFace(boolean drawTopFace) { 58 | this.box.setDrawTopFace(drawTopFace); 59 | } 60 | 61 | public void setDepth(double value) { 62 | this.box.setDepth(value); 63 | } 64 | 65 | public double getDepth() { 66 | return this.box.getDepth(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/CylinderAdapter.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.beans.property.DoubleProperty; 4 | import javafx.scene.CacheHint; 5 | import javafx.scene.DepthTest; 6 | import javafx.scene.Group; 7 | import javafx.scene.paint.Color; 8 | import javafx.scene.paint.PhongMaterial; 9 | import javafx.scene.shape.Cylinder; 10 | 11 | public class CylinderAdapter extends Group { 12 | 13 | private Cylinder cylinder; 14 | private Color color; 15 | 16 | public Color getColor() { 17 | return color; 18 | } 19 | 20 | public CylinderAdapter() { 21 | this(5); 22 | } 23 | 24 | public CylinderAdapter(double radius) { 25 | this(Color.WHITE, radius, 10); 26 | } 27 | 28 | public CylinderAdapter(Color color, double radius, double height) { 29 | this.cylinder = new Cylinder(radius, height); 30 | this.cylinder.setDepthTest(DepthTest.ENABLE); 31 | this.cylinder.setCache(true); 32 | this.cylinder.setCacheHint(CacheHint.SCALE_AND_ROTATE); 33 | setColor(color); 34 | getChildren().add(this.cylinder); 35 | } 36 | 37 | public void setColor(Color color) { 38 | this.color = color; 39 | PhongMaterial material = new PhongMaterial(); 40 | material.setDiffuseColor(this.color); 41 | material.setSpecularColor(this.color.brighter()); 42 | this.cylinder.setMaterial(material); 43 | } 44 | 45 | public DoubleProperty radiusProperty() { 46 | return this.cylinder.radiusProperty(); 47 | } 48 | 49 | public DoubleProperty heightProperty() { 50 | return this.cylinder.heightProperty(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/DashedArrow.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import ch.hsr.ogv.model.RelationType; 4 | import ch.hsr.ogv.util.GeometryUtil; 5 | import javafx.geometry.Point3D; 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Box; 8 | 9 | import java.util.ArrayList; 10 | 11 | public class DashedArrow extends Arrow { 12 | 13 | private static final int DASHED_ELEMENT_COUNT = 20; 14 | 15 | private ArrayList dashedLines; 16 | 17 | public DashedArrow(PaneBox startBox, PaneBox endBox, RelationType type) { 18 | super(startBox, endBox, type); 19 | } 20 | 21 | public DashedArrow(PaneBox startBox, Point3D endPoint, RelationType type) { 22 | super(startBox, endPoint, type); 23 | } 24 | 25 | @Override 26 | protected void addElementsToGroup() { 27 | getChildren().clear(); 28 | getChildren().addAll(this.dashedLines); 29 | getChildren().addAll(this.arrowStart, this.arrowEnd); 30 | getChildren().addAll(this.lineSelectionHelpers); 31 | getChildren().addAll(this.startSelectionHelper, this.endSelectionHelper); 32 | getChildren().addAll(this.labelStartRight, this.labelStartLeft, this.labelEndRight, this.labelEndLeft); 33 | } 34 | 35 | @Override 36 | protected void prepareLines() { 37 | super.prepareLines(); 38 | this.dashedLines = new ArrayList(); 39 | for (int i = 0; i < DASHED_ELEMENT_COUNT; i++) { 40 | Box dashedLine = new Box(this.width, this.width, this.startEndDistance); 41 | dashedLine.setVisible(false); 42 | this.dashedLines.add(dashedLine); 43 | } 44 | } 45 | 46 | @Override 47 | protected void setLineVisibility() { 48 | this.line.setVisible(false); 49 | for (Box dashedLine : this.dashedLines) { 50 | dashedLine.setVisible(true); 51 | } 52 | } 53 | 54 | @Override 55 | protected void setSingleElements() { 56 | double endGap = this.arrowEnd.getAdditionalGap(); 57 | double startGap = this.arrowStart.getAdditionalGap(); 58 | double gapDistance = this.startEndDistance - (endGap + startGap) / 2; 59 | 60 | this.line.setDepth(gapDistance); 61 | this.line.setTranslateZ((-endGap + startGap) / 4); 62 | 63 | ArrayList dashedLineCoords = divideLine(new Point3D(0, 0, -gapDistance / 2), new Point3D(0, 0, gapDistance / 2), this.dashedLines.size()); 64 | 65 | for (int i = 0; i < this.dashedLines.size(); i++) { 66 | Box dashedLine = this.dashedLines.get(i); 67 | dashedLine.setDepth(gapDistance / (2 * DASHED_ELEMENT_COUNT)); 68 | Point3D dashedLineCoord = dashedLineCoords.get(i); 69 | dashedLine.setTranslateZ(dashedLineCoord.getZ() - dashedLine.getDepth() + (-endGap + startGap) / 4); 70 | } 71 | } 72 | 73 | private ArrayList divideLine(Point3D start, Point3D end, int count) { 74 | ArrayList pointList = new ArrayList(); 75 | for (int i = 1; i <= count; i++) { 76 | pointList.add(GeometryUtil.divideLineFraction(start, end, ((double) i) / ((double) count))); 77 | } 78 | return pointList; 79 | } 80 | 81 | @Override 82 | public void setColor(Color color) { 83 | super.setColor(color); 84 | for (Box dashedLine : this.dashedLines) { 85 | applyColor(dashedLine, this.color); 86 | } 87 | } 88 | 89 | @Override 90 | public void setSelected(boolean selected) { 91 | super.setSelected(selected); 92 | Color colorToApply = colorToApply(selected); 93 | for (Box dashedLine : this.dashedLines) { 94 | applyColor(dashedLine, colorToApply); 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/Floor.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.scene.DepthTest; 4 | import javafx.scene.Group; 5 | import javafx.scene.Node; 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Rectangle; 8 | import javafx.scene.transform.Rotate; 9 | 10 | import java.util.HashSet; 11 | 12 | public class Floor extends Group implements Selectable { 13 | 14 | private HashSet tiles = new HashSet(); 15 | private final double TILE_SIZE = 1000; 16 | private final int TILE_DIMENSION = 10; 17 | public final static Color DEFAULT_COLOR = Color.WHITESMOKE; 18 | 19 | private Color color = DEFAULT_COLOR; 20 | 21 | private volatile boolean selected = false; 22 | 23 | public Floor() { 24 | for (int x = 0; x < TILE_DIMENSION; x++) { 25 | for (int z = 0; z < TILE_DIMENSION; z++) { 26 | buildFloorTile(x, z); 27 | } 28 | } 29 | 30 | for (Rectangle tile : this.tiles) { 31 | getChildren().add(tile); 32 | } 33 | } 34 | 35 | private void buildFloorTile(int x, int z) { 36 | Rectangle tile = new Rectangle(TILE_SIZE, TILE_SIZE, this.color); 37 | tile.setDepthTest(DepthTest.ENABLE); 38 | tile.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); 39 | tile.setTranslateX(-((TILE_DIMENSION * TILE_SIZE) / 2) + (x * TILE_SIZE)); 40 | tile.setTranslateZ(-((TILE_DIMENSION * TILE_SIZE) / 2) + (z * TILE_SIZE)); 41 | tile.setOpacity(0.6); 42 | this.tiles.add(tile); 43 | } 44 | 45 | public void setSeeable(boolean value) { 46 | for (Rectangle tile : this.tiles) { 47 | if (value) { 48 | tile.setFill(getColor()); 49 | } 50 | else { 51 | tile.setFill(Color.TRANSPARENT); 52 | } 53 | } 54 | 55 | } 56 | 57 | public void setColor(Color color) { 58 | for (Rectangle tile : this.tiles) { 59 | tile.setFill(color); 60 | } 61 | this.color = color; 62 | } 63 | 64 | public Color getColor() { 65 | return this.color; 66 | } 67 | 68 | public boolean hasTile(Node node) { 69 | if (node == null || !(node instanceof Rectangle)) 70 | return false; 71 | Rectangle rect = (Rectangle) node; 72 | return this.tiles.contains(rect); 73 | } 74 | 75 | @Override 76 | public void setSelected(boolean selected) { 77 | this.selected = selected; 78 | } 79 | 80 | @Override 81 | public boolean isSelected() { 82 | return this.selected; 83 | } 84 | 85 | @Override 86 | public Group getSelection() { 87 | return null; // floor has no real (visible) selection 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/Selectable.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.scene.Group; 4 | 5 | public interface Selectable { 6 | 7 | public void setSelected(boolean selected); 8 | 9 | public boolean isSelected(); 10 | 11 | public Group getSelection(); 12 | 13 | public void requestFocus(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/SphereAdapter.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.beans.property.DoubleProperty; 4 | import javafx.event.EventHandler; 5 | import javafx.scene.CacheHint; 6 | import javafx.scene.DepthTest; 7 | import javafx.scene.Group; 8 | import javafx.scene.input.MouseEvent; 9 | import javafx.scene.paint.Color; 10 | import javafx.scene.paint.PhongMaterial; 11 | import javafx.scene.shape.Sphere; 12 | 13 | public class SphereAdapter extends Group { 14 | 15 | private Sphere sphere; 16 | private Color color; 17 | 18 | public Color getColor() { 19 | return this.color; 20 | } 21 | 22 | public SphereAdapter() { 23 | this(5); 24 | } 25 | 26 | public SphereAdapter(double radius) { 27 | this(Color.WHITE, radius); 28 | } 29 | 30 | public SphereAdapter(Color color, double radius) { 31 | this.sphere = new Sphere(radius); 32 | this.sphere.setDepthTest(DepthTest.ENABLE); 33 | this.sphere.setCache(true); 34 | this.sphere.setCacheHint(CacheHint.SCALE_AND_ROTATE); 35 | setColor(color); 36 | this.sphere.setOnMouseClicked(new EventHandler() { 37 | @Override 38 | public void handle(MouseEvent t) { 39 | sphere.requestFocus(); 40 | } 41 | }); 42 | getChildren().add(this.sphere); 43 | } 44 | 45 | public void setColor(Color color) { 46 | this.color = color; 47 | PhongMaterial material = new PhongMaterial(); 48 | material.setDiffuseColor(this.color); 49 | material.setSpecularColor(this.color.brighter()); 50 | sphere.setMaterial(material); 51 | } 52 | 53 | public DoubleProperty radiusProperty() { 54 | return this.sphere.radiusProperty(); 55 | } 56 | 57 | public void requestFocus() { 58 | this.sphere.requestFocus(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/SubSceneAdapter.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.scene.*; 4 | import javafx.scene.paint.Color; 5 | 6 | public class SubSceneAdapter implements Selectable { 7 | 8 | public final static Color DEFAULT_COLOR = Color.LIGHTCYAN; 9 | private Color color = DEFAULT_COLOR; 10 | 11 | private SubScene subScene; 12 | private SubSceneCamera subSceneCamera; 13 | private Axis axis; 14 | private Floor floor; 15 | private VerticalHelper verticalHelper; 16 | 17 | private volatile boolean selected = false; 18 | private volatile boolean ySpaceVisible = true; 19 | 20 | private final Group root = new Group(); 21 | 22 | private final Xform world = new Xform(); 23 | 24 | public SubScene getSubScene() { 25 | return this.subScene; 26 | } 27 | 28 | public SubSceneCamera getSubSceneCamera() { 29 | return this.subSceneCamera; 30 | } 31 | 32 | public Axis getAxis() { 33 | return this.axis; 34 | } 35 | 36 | public Floor getFloor() { 37 | return this.floor; 38 | } 39 | 40 | public VerticalHelper getVerticalHelper() { 41 | return this.verticalHelper; 42 | } 43 | 44 | public Color getColor() { 45 | return color; 46 | } 47 | 48 | public void setColor(Color color) { 49 | if (this.subScene != null) 50 | this.subScene.setFill(color); 51 | this.color = color; 52 | } 53 | 54 | public boolean isYSpaceVisible() { 55 | return ySpaceVisible; 56 | } 57 | 58 | public void setYSpaceVisible(boolean ySpaceVisible) { 59 | this.ySpaceVisible = ySpaceVisible; 60 | } 61 | 62 | public SubSceneAdapter(double initWidth, double initHeight) { 63 | // create a new subscene that resides in the root group 64 | this.root.setDepthTest(DepthTest.ENABLE); 65 | this.subScene = new SubScene(this.root, initWidth, initHeight, true, SceneAntialiasing.BALANCED); 66 | this.subScene.setFill(color); 67 | 68 | // create axis and add them to the world Xform 69 | this.axis = new Axis(); 70 | this.world.getChildren().add(axis); 71 | 72 | // create ground floor and add it to the world Xform 73 | this.floor = new Floor(); 74 | this.world.getChildren().add(floor); 75 | 76 | this.verticalHelper = new VerticalHelper(); 77 | this.world.getChildren().add(this.verticalHelper); 78 | 79 | // add a camera for the subscene 80 | this.subSceneCamera = new SubSceneCamera(); 81 | this.root.getChildren().add(this.subSceneCamera.getCameraXform()); 82 | this.subScene.setCamera(this.subSceneCamera.get()); 83 | 84 | // populate the root group with the world objects 85 | this.root.getChildren().add(world); 86 | } 87 | 88 | public void receiveMouseEvents(Node... nodes) { 89 | for (Node n : nodes) { 90 | n.setMouseTransparent(false); 91 | } 92 | } 93 | 94 | public void worldReceiveMouseEvents() { 95 | receiveMouseEvents(world.getChildren().toArray(new Node[world.getChildren().size()])); 96 | } 97 | 98 | public void restrictMouseEvents(Node... nodes) { 99 | for (Node n : nodes) { 100 | n.setMouseTransparent(true); 101 | } 102 | } 103 | 104 | public void worldRestrictMouseEvents() { 105 | restrictMouseEvents(world.getChildren().toArray(new Node[world.getChildren().size()])); 106 | } 107 | 108 | public boolean add(Node node) { 109 | boolean retAdd = this.world.getChildren().add(node); 110 | this.floor.toFront(); 111 | this.verticalHelper.toFront(); 112 | return retAdd; 113 | } 114 | 115 | public boolean remove(Node node) { 116 | return this.world.getChildren().remove(node); 117 | } 118 | 119 | @Override 120 | public void setSelected(boolean selected) { 121 | this.selected = selected; 122 | } 123 | 124 | @Override 125 | public boolean isSelected() { 126 | return this.selected; 127 | } 128 | 129 | @Override 130 | public Group getSelection() { 131 | return null; // SubScene has no real (visible) selection 132 | } 133 | 134 | @Override 135 | public void requestFocus() { 136 | this.subScene.requestFocus(); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/SubSceneCamera.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import javafx.scene.PerspectiveCamera; 4 | 5 | public class SubSceneCamera { 6 | 7 | private final PerspectiveCamera camera = new PerspectiveCamera(true); 8 | private final Xform cameraXform = new Xform(); 9 | private final Xform cameraXform2 = new Xform(); 10 | private final Xform cameraXform3 = new Xform(); 11 | public static final int CAMERA_DISTANCE = 1800; 12 | 13 | public PerspectiveCamera get() { 14 | return camera; 15 | } 16 | 17 | public Xform getCameraXform() { 18 | return cameraXform; 19 | } 20 | 21 | public Xform getCameraXform2() { 22 | return cameraXform2; 23 | } 24 | 25 | public Xform getCameraXform3() { 26 | return cameraXform3; 27 | } 28 | 29 | public SubSceneCamera() { 30 | cameraXform.getChildren().add(cameraXform2); 31 | cameraXform2.getChildren().add(cameraXform3); 32 | cameraXform3.getChildren().add(camera); 33 | cameraXform3.setRotateZ(180.0); 34 | 35 | camera.setNearClip(1); // 0.1 36 | camera.setFarClip(30000.0); 37 | camera.setTranslateZ(-CAMERA_DISTANCE); 38 | cameraXform.ry.setAngle(0.0); // 320 39 | cameraXform.rx.setAngle(90.0); // 40 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/TSplitMenuButton.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import ch.hsr.ogv.util.ResourceLocator; 4 | import ch.hsr.ogv.util.ResourceLocator.Resource; 5 | import javafx.beans.property.BooleanProperty; 6 | import javafx.beans.property.ObjectProperty; 7 | import javafx.collections.ObservableMap; 8 | import javafx.scene.control.*; 9 | import javafx.scene.image.ImageView; 10 | 11 | public class TSplitMenuButton implements Toggle { 12 | 13 | private SplitMenuButton splitMenuButton; 14 | private MenuItem selectedChoice; 15 | private ToggleButton toggleButton = new ToggleButton(); 16 | 17 | public TSplitMenuButton(SplitMenuButton splitMenuButton, MenuItem startChoice, ToggleGroup tg) { 18 | this.splitMenuButton = splitMenuButton; 19 | this.splitMenuButton.getStylesheets().add(ResourceLocator.getResourcePath(Resource.TSPLITMENUBUTTON_CSS).toExternalForm()); 20 | this.selectedChoice = startChoice; 21 | toggleButton.setToggleGroup(tg); 22 | } 23 | 24 | public MenuItem selectedChoice() { 25 | return selectedChoice; 26 | } 27 | 28 | public void setChoice(MenuItem newChoice) { 29 | selectedChoice = newChoice; 30 | ImageView graphic = (ImageView) newChoice.getGraphic(); 31 | ImageView graphic2 = new ImageView(graphic.getImage()); 32 | splitMenuButton.setGraphic(graphic2); 33 | String title = newChoice.getText(); 34 | splitMenuButton.setText(title); 35 | } 36 | 37 | public final void setSelected(boolean value) { 38 | selectedProperty().set(value); 39 | toggleButton.selectedProperty().set(value); 40 | if (toggleButton.selectedProperty().get()) { 41 | splitMenuButton.getStyleClass().add("tsplit-menu-button"); 42 | } 43 | else { 44 | splitMenuButton.getStyleClass().remove("tsplit-menu-button"); 45 | } 46 | } 47 | 48 | public final boolean isSelected() { 49 | return selectedProperty() == null ? false : selectedProperty().get(); 50 | } 51 | 52 | @Override 53 | public ObservableMap getProperties() { 54 | return toggleButton.getProperties(); 55 | } 56 | 57 | @Override 58 | public ToggleGroup getToggleGroup() { 59 | return toggleButton.getToggleGroup(); 60 | } 61 | 62 | @Override 63 | public Object getUserData() { 64 | return toggleButton.getUserData(); 65 | } 66 | 67 | @Override 68 | public BooleanProperty selectedProperty() { 69 | return toggleButton.selectedProperty(); 70 | } 71 | 72 | @Override 73 | public void setToggleGroup(ToggleGroup toggleGroup) { 74 | toggleButton.setToggleGroup(toggleGroup); 75 | } 76 | 77 | @Override 78 | public void setUserData(Object value) { 79 | toggleButton.setUserData(value); 80 | } 81 | 82 | @Override 83 | public ObjectProperty toggleGroupProperty() { 84 | return toggleButton.toggleGroupProperty(); 85 | } 86 | 87 | public boolean isDisable() { 88 | return splitMenuButton.isDisable(); 89 | 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/VerticalHelper.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.view; 2 | 3 | import ch.hsr.ogv.model.ModelClass; 4 | import javafx.scene.Group; 5 | import javafx.scene.Node; 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Rectangle; 8 | import javafx.scene.transform.Rotate; 9 | 10 | import java.util.ArrayList; 11 | import java.util.HashSet; 12 | 13 | public class VerticalHelper extends Group { 14 | 15 | private HashSet> helperAreas = new HashSet>(); 16 | public final static double DEPTH_SIZE = 2000; 17 | public final static double DEPTH_DIMENSION = 3; 18 | public final static double OPACITY = 0.1; 19 | 20 | private final static double PLUS_SIZE = 2; 21 | 22 | public final static Color DEFAULT_COLOR = Color.DODGERBLUE; 23 | 24 | public VerticalHelper() { 25 | for (int i = 0; i < DEPTH_DIMENSION; i++) { 26 | buildHelperArea(i); 27 | } 28 | 29 | for (ArrayList oneDimension : this.helperAreas) { 30 | getChildren().addAll(oneDimension); 31 | } 32 | setMouseTransparent(true); 33 | setVisible(false); 34 | } 35 | 36 | private void buildHelperArea(int depthDimension) { 37 | Rectangle northRectangle = new Rectangle(PLUS_SIZE, DEPTH_SIZE, DEFAULT_COLOR); 38 | Rectangle southRectangle = new Rectangle(PLUS_SIZE, DEPTH_SIZE, DEFAULT_COLOR); 39 | Rectangle eastRectangle = new Rectangle(PLUS_SIZE, DEPTH_SIZE, DEFAULT_COLOR); 40 | Rectangle westRectangle = new Rectangle(PLUS_SIZE, DEPTH_SIZE, DEFAULT_COLOR); 41 | 42 | northRectangle.setOpacity(OPACITY); 43 | northRectangle.setTranslateY(ModelClass.OBJECT_LEVEL_DIFF + depthDimension * DEPTH_SIZE); 44 | 45 | southRectangle.setOpacity(OPACITY); 46 | southRectangle.setTranslateY(ModelClass.OBJECT_LEVEL_DIFF + depthDimension * DEPTH_SIZE); 47 | 48 | eastRectangle.setOpacity(OPACITY); 49 | eastRectangle.setTranslateY(ModelClass.OBJECT_LEVEL_DIFF + depthDimension * DEPTH_SIZE); 50 | eastRectangle.getTransforms().add(new Rotate(90, Rotate.Y_AXIS)); 51 | 52 | westRectangle.setOpacity(OPACITY); 53 | westRectangle.setTranslateY(ModelClass.OBJECT_LEVEL_DIFF + depthDimension * DEPTH_SIZE); 54 | westRectangle.getTransforms().add(new Rotate(90, Rotate.Y_AXIS)); 55 | 56 | ArrayList oneDimension = new ArrayList(); 57 | oneDimension.add(northRectangle); 58 | oneDimension.add(southRectangle); 59 | oneDimension.add(eastRectangle); 60 | oneDimension.add(westRectangle); 61 | this.helperAreas.add(oneDimension); 62 | } 63 | 64 | public void setDimension(PaneBox paneBox) { 65 | setDimension(paneBox.getTranslateX(), paneBox.getTranslateZ(), paneBox.getWidth(), paneBox.getHeight()); 66 | } 67 | 68 | public void setDimension(double x, double z, double width, double height) { 69 | for (ArrayList oneDimension : this.helperAreas) { 70 | Rectangle northRectangle = oneDimension.get(0); 71 | Rectangle southRectangle = oneDimension.get(1); 72 | Rectangle eastRectangle = oneDimension.get(2); 73 | Rectangle westRectangle = oneDimension.get(3); 74 | 75 | northRectangle.setWidth(width + PLUS_SIZE); 76 | northRectangle.setTranslateX(x - width / 2 - PLUS_SIZE / 2); 77 | northRectangle.setTranslateZ(z + height / 2 + PLUS_SIZE / 2); 78 | 79 | southRectangle.setWidth(width + PLUS_SIZE); 80 | southRectangle.setTranslateX(x - width / 2 - PLUS_SIZE / 2); 81 | southRectangle.setTranslateZ(z - height / 2 - PLUS_SIZE / 2); 82 | 83 | eastRectangle.setWidth(height + PLUS_SIZE); 84 | eastRectangle.setTranslateX(x + width / 2 + PLUS_SIZE / 2); 85 | eastRectangle.setTranslateZ(z + height / 2 + PLUS_SIZE / 2); 86 | 87 | westRectangle.setWidth(height + PLUS_SIZE); 88 | westRectangle.setTranslateX(x - width / 2 - PLUS_SIZE / 2); 89 | westRectangle.setTranslateZ(z + height / 2 + PLUS_SIZE / 2); 90 | } 91 | } 92 | 93 | private boolean isVerticalHelper(Rectangle rectangle) { 94 | HashSet allRectangles = new HashSet(); 95 | for (ArrayList oneDimension : this.helperAreas) { 96 | allRectangles.addAll(oneDimension); 97 | } 98 | if (allRectangles.contains(rectangle)) { 99 | return true; 100 | } 101 | return false; 102 | } 103 | 104 | public boolean isVerticalHelper(Node node) { 105 | if (node == null || !(node instanceof Rectangle)) { 106 | return false; 107 | } 108 | return isVerticalHelper((Rectangle) node); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/ch/hsr/ogv/view/Xform.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, 2013 Oracle and/or its affiliates. 3 | * All rights reserved. Use is subject to license terms. 4 | * 5 | * This file is available and licensed under the following license: 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the distribution. 16 | * - Neither the name of Oracle nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package ch.hsr.ogv.view; 33 | 34 | import javafx.scene.Group; 35 | import javafx.scene.transform.Rotate; 36 | import javafx.scene.transform.Scale; 37 | import javafx.scene.transform.Translate; 38 | 39 | /** 40 | * @author Oracle 41 | */ 42 | public class Xform extends Group { 43 | 44 | public enum RotateOrder { 45 | XYZ, XZY, YXZ, YZX, ZXY, ZYX 46 | } 47 | 48 | public Translate t = new Translate(); 49 | public Translate p = new Translate(); 50 | public Translate ip = new Translate(); 51 | public Rotate rx = new Rotate(); 52 | 53 | { 54 | rx.setAxis(Rotate.X_AXIS); 55 | } 56 | 57 | public Rotate ry = new Rotate(); 58 | 59 | { 60 | ry.setAxis(Rotate.Y_AXIS); 61 | } 62 | 63 | public Rotate rz = new Rotate(); 64 | 65 | { 66 | rz.setAxis(Rotate.Z_AXIS); 67 | } 68 | 69 | public Scale s = new Scale(); 70 | 71 | public Xform() { 72 | super(); 73 | getTransforms().addAll(t, rz, ry, rx, s); 74 | } 75 | 76 | public Xform(RotateOrder rotateOrder) { 77 | super(); 78 | // choose the order of rotations based on the rotateOrder 79 | switch (rotateOrder) { 80 | case XYZ: 81 | getTransforms().addAll(t, p, rz, ry, rx, s, ip); 82 | break; 83 | case XZY: 84 | getTransforms().addAll(t, p, ry, rz, rx, s, ip); 85 | break; 86 | case YXZ: 87 | getTransforms().addAll(t, p, rz, rx, ry, s, ip); 88 | break; 89 | case YZX: 90 | getTransforms().addAll(t, p, rx, rz, ry, s, ip); // For Camera 91 | break; 92 | case ZXY: 93 | getTransforms().addAll(t, p, ry, rx, rz, s, ip); 94 | break; 95 | case ZYX: 96 | getTransforms().addAll(t, p, rx, ry, rz, s, ip); 97 | break; 98 | } 99 | } 100 | 101 | public void setTranslate(double x, double y, double z) { 102 | t.setX(x); 103 | t.setY(y); 104 | t.setZ(z); 105 | } 106 | 107 | public void setTranslate(double x, double y) { 108 | t.setX(x); 109 | t.setY(y); 110 | } 111 | 112 | // Cannot override these methods as they are final: 113 | // public void setTranslateX(double x) { t.setX(x); } 114 | // public void setTranslateY(double y) { t.setY(y); } 115 | // public void setTranslateZ(double z) { t.setZ(z); } 116 | // Use these methods instead: 117 | public void setTx(double x) { 118 | t.setX(x); 119 | } 120 | 121 | public void setTy(double y) { 122 | t.setY(y); 123 | } 124 | 125 | public void setTz(double z) { 126 | t.setZ(z); 127 | } 128 | 129 | public void setRotate(double x, double y, double z) { 130 | rx.setAngle(x); 131 | ry.setAngle(y); 132 | rz.setAngle(z); 133 | } 134 | 135 | public void setRotateX(double x) { 136 | rx.setAngle(x); 137 | } 138 | 139 | public void setRotateY(double y) { 140 | ry.setAngle(y); 141 | } 142 | 143 | public void setRotateZ(double z) { 144 | rz.setAngle(z); 145 | } 146 | 147 | public void setRx(double x) { 148 | rx.setAngle(x); 149 | } 150 | 151 | public void setRy(double y) { 152 | ry.setAngle(y); 153 | } 154 | 155 | public void setRz(double z) { 156 | rz.setAngle(z); 157 | } 158 | 159 | public void setScale(double scaleFactor) { 160 | s.setX(scaleFactor); 161 | s.setY(scaleFactor); 162 | s.setZ(scaleFactor); 163 | } 164 | 165 | public void setScale(double x, double y, double z) { 166 | s.setX(x); 167 | s.setY(y); 168 | s.setZ(z); 169 | } 170 | 171 | // Cannot override these methods as they are final: 172 | // public void setScaleX(double x) { s.setX(x); } 173 | // public void setScaleY(double y) { s.setY(y); } 174 | // public void setScaleZ(double z) { s.setZ(z); } 175 | // Use these methods instead: 176 | public void setSx(double x) { 177 | s.setX(x); 178 | } 179 | 180 | public void setSy(double y) { 181 | s.setY(y); 182 | } 183 | 184 | public void setSz(double z) { 185 | s.setZ(z); 186 | } 187 | 188 | public void setPivot(double x, double y, double z) { 189 | p.setX(x); 190 | p.setY(y); 191 | p.setZ(z); 192 | ip.setX(-x); 193 | ip.setY(-y); 194 | ip.setZ(-z); 195 | } 196 | 197 | public void reset() { 198 | t.setX(0.0); 199 | t.setY(0.0); 200 | t.setZ(0.0); 201 | rx.setAngle(0.0); 202 | ry.setAngle(0.0); 203 | rz.setAngle(0.0); 204 | s.setX(1.0); 205 | s.setY(1.0); 206 | s.setZ(1.0); 207 | p.setX(0.0); 208 | p.setY(0.0); 209 | p.setZ(0.0); 210 | ip.setX(0.0); 211 | ip.setY(0.0); 212 | ip.setZ(0.0); 213 | } 214 | 215 | public void resetTSP() { 216 | t.setX(0.0); 217 | t.setY(0.0); 218 | t.setZ(0.0); 219 | s.setX(1.0); 220 | s.setY(1.0); 221 | s.setZ(1.0); 222 | p.setX(0.0); 223 | p.setY(0.0); 224 | p.setZ(0.0); 225 | ip.setX(0.0); 226 | ip.setY(0.0); 227 | ip.setZ(0.0); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: ch.hsr.ogv.Main 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/css/Scene.css: -------------------------------------------------------------------------------- 1 | .root { 2 | -fx-font-family: 'System'; 3 | } -------------------------------------------------------------------------------- /src/main/resources/css/TSplitMenuButton.css: -------------------------------------------------------------------------------- 1 | /* ==== SELECTED ToggleButton ================================================= */ 2 | 3 | .toggle-button:selected { 4 | -fx-background-color: linear-gradient(to bottom, derive(-fx-outer-border, -20%), -fx-outer-border), 5 | linear-gradient(to bottom, 6 | derive(-fx-text-box-border, -10%) 0%, 7 | derive(-fx-text-box-border, -2%) 20%, 8 | derive(-fx-text-box-border, 5%) 50%); 9 | -fx-background-insets: 0, 1; 10 | } 11 | 12 | .toggle-button:selected:focused { 13 | -fx-background-color: -fx-faint-focus-color, -fx-focus-color, 14 | linear-gradient(to bottom, 15 | derive(-fx-text-box-border, -10%) 0%, 16 | derive(-fx-text-box-border, -2%) 20%, 17 | derive(-fx-text-box-border, 5%) 50%); 18 | -fx-background-insets: -2, -0.3, 1; 19 | -fx-background-radius: 7, 6, 4; 20 | } 21 | 22 | /******************************************************************************* 23 | * * 24 | * SplitMenuButton * 25 | * * 26 | ******************************************************************************/ 27 | 28 | .split-menu-button { 29 | -fx-background-color: -fx-outer-border; 30 | -fx-background-insets: 0; 31 | -fx-background-radius: 5; 32 | -fx-padding: 0; 33 | } 34 | 35 | .split-menu-button:focused { 36 | -fx-background-color: -fx-faint-focus-color, -fx-focus-color; 37 | -fx-background-insets: -2, -0.3; 38 | -fx-background-radius: 7, 6; 39 | } 40 | 41 | .split-menu-button > .label { 42 | -fx-text-fill: -fx-text-base-color; 43 | -fx-background-color: -fx-inner-border, -fx-body-color; 44 | -fx-background-insets: 1 0 1 1, 2 1 2 2; 45 | -fx-background-radius: 4 0 0 4, 3 0 0 3; 46 | -fx-padding: 0.333333em 0.667em 0.416667em 0.667em; /* 4 8 5 8 */ 47 | } 48 | 49 | .split-menu-button > .arrow-button { 50 | -fx-background-color: -fx-inner-border, -fx-body-color; 51 | -fx-background-insets: 1, 2; 52 | -fx-background-radius: 4, 3; 53 | -fx-background-radius: 0 4 4 0, 0 3 3 0; 54 | -fx-padding: 0.5em 0.833333em 0.5em 0.833333em; /* 6 10 6 10 */ 55 | } 56 | 57 | /* ==== SELECTED TOGGLE SplitMenuButton ================================================= */ 58 | 59 | .tsplit-menu-button > .label { 60 | -fx-background-color: linear-gradient(to bottom, derive(-fx-outer-border, -20%), -fx-outer-border), 61 | linear-gradient(to bottom, 62 | derive(-fx-text-box-border, -10%) 0%, 63 | derive(-fx-text-box-border, -2%) 20%, 64 | derive(-fx-text-box-border, 5%) 50%); 65 | -fx-background-insets: 0, 1; 66 | } 67 | -------------------------------------------------------------------------------- /src/main/resources/css/TextInput.css: -------------------------------------------------------------------------------- 1 | .text-input { 2 | -fx-font-size: 15; 3 | -fx-background-color: transparent; 4 | } 5 | 6 | .text-input:focused { 7 | -fx-font-size: 15; 8 | -fx-background-color: white; 9 | -fx-border-color: dodgerblue; 10 | -fx-background-insets: 1 1 1 1; 11 | } 12 | 13 | .text-input:disabled { 14 | -fx-font-size: 15; 15 | -fx-opacity: 1.0; 16 | } -------------------------------------------------------------------------------- /src/main/resources/css/TextInputSmall.css: -------------------------------------------------------------------------------- 1 | .text-input { 2 | -fx-font-size: 12; 3 | -fx-background-color: transparent; 4 | } 5 | 6 | .text-input:focused { 7 | -fx-font-size: 12; 8 | -fx-background-color: white; 9 | -fx-border-color: transparent; 10 | -fx-background-insets: 1 1 1 1; 11 | } 12 | 13 | .text-input:disabled { 14 | -fx-font-size: 12; 15 | -fx-opacity: 1.0; 16 | } -------------------------------------------------------------------------------- /src/main/resources/fonts/LUCIDASANSREGULAR.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/fonts/LUCIDASANSREGULAR.TTF -------------------------------------------------------------------------------- /src/main/resources/fonts/SEGOEUI.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/fonts/SEGOEUI.TTF -------------------------------------------------------------------------------- /src/main/resources/images/OGV.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/OGV.gif -------------------------------------------------------------------------------- /src/main/resources/images/OGV.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/OGV.icns -------------------------------------------------------------------------------- /src/main/resources/images/OGV.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/OGV.ico -------------------------------------------------------------------------------- /src/main/resources/images/OGV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/OGV.png -------------------------------------------------------------------------------- /src/main/resources/images/OGV.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/OGV.xcf -------------------------------------------------------------------------------- /src/main/resources/images/OGV.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/OGV.zip -------------------------------------------------------------------------------- /src/main/resources/images/menu/ActivityClassDiagram.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/ActivityClassDiagram.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/ColRole.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/ColRole.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/aggregation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/aggregation.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/aggregationToNavi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/aggregationToNavi.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/application-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/application-import.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/artifactPrj.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/artifactPrj.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/assoNavToNav.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/assoNavToNav.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/assoWithNav.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/assoWithNav.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/assoc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/assoc.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/associationClass.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/associationClass.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/bullet_arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/bullet_arrow_down.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/bullet_arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/bullet_arrow_up.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/close.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/composite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/composite.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/compositeToNavi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/compositeToNavi.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/depend.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/depend.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/error.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/general.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/general.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/help.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/info.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/instance.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/instance.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/message_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/message_default.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/message_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/message_error.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/message_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/message_info.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/message_warn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/message_warn.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/mm_pc_fd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/mm_pc_fd.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/multiplicity.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/multiplicity.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/new.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/new.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/open.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/open.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/relation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/relation.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/rightAngleOff.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/rightAngleOff.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/structureclass.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/structureclass.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/synchronize_dgm_tab.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/synchronize_dgm_tab.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/testcase.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/testcase.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/text_box2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/text_box2.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/trash.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/add.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/add.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/arrow-down-01-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/arrow-down-01-16.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/arrow-up-01-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/arrow-up-01-16.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/artifact.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/artifact.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/close_button.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/close_button.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/close_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/close_button.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/close_button_rollover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/close_button_rollover.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/delSelect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/delSelect.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/mm_arrow_triangle_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/mm_arrow_triangle_down.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/mm_arrow_triangle_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/mm_arrow_triangle_up.png -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/setcolor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/setcolor.gif -------------------------------------------------------------------------------- /src/main/resources/images/menu/unused/warn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nurtak/ObjectGraphVisualization/f6a60db1105ab88977c517826aa6c7de59d5ee42/src/main/resources/images/menu/unused/warn.png -------------------------------------------------------------------------------- /src/main/resources/log4j2.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=DEBUG, file, stdout 3 | # Direct log messages to a log file 4 | log4j.appender.file=org.apache.log4j.RollingFileAppender 5 | log4j.appender.file.File=./logs/ogv.log 6 | log4j.appender.file.MaxFileSize=10MB 7 | log4j.appender.file.MaxBackupIndex=10 8 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 9 | log4j.appender.file.layout.ConversionPattern=%d{dd-MM-yyyy HH:mm:ss} %-5p %c{1}:%L - %m%n 10 | # Direct log messages to stdout 11 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 12 | log4j.appender.stdout.Target=System.out 13 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 14 | log4j.appender.stdout.layout.ConversionPattern=%d{dd-MM-yyyy HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /src/main/resources/models/arc.mtl: -------------------------------------------------------------------------------- 1 | # Alias Wavefront MTL File Exported from SketchUp 2 | # with OBJexporter (c) 2013 TIG 3 | # Made for 'arc.obj' 4 | 5 | newmtl Default_Material 6 | Ka 1 1 1 7 | Kd 1 1 1 8 | Ks 0.333 0.333 0.333 9 | Ns 0 10 | d 1 11 | Tr 1 12 | 13 | #EOF 14 | -------------------------------------------------------------------------------- /src/main/resources/models/empty_arrow.mtl: -------------------------------------------------------------------------------- 1 | # 2 | ## Alias OBJ Material File 3 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 4 | 5 | newmtl _auto_ 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 1.000000 1.000000 1.000000 8 | Ks 0.330000 0.330000 0.330000 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/models/empty_arrow.obj: -------------------------------------------------------------------------------- 1 | # Alias OBJ Model File 2 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 3 | # File units = meters 4 | 5 | mtllib empty_arrow.mtl 6 | 7 | g Mesh1 skpD895_1 Model 8 | 9 | usemtl _auto_ 10 | v -11.1625 -0.990716 18.9602 11 | vt -19.9994 33.8583 12 | vn -0 -1 -0 13 | v 7.74799 -0.990716 17.1219 14 | vt 13.8626 30.5665 15 | v 10.9996 -0.990716 18.9602 16 | vt 19.685 33.8583 17 | f 1/1/1 2/2/1 3/3/1 18 | 19 | v -7.87537 -0.990716 17.1219 20 | vt -14.1133 30.5665 21 | f 2/2/1 1/1/1 4/4/1 22 | 23 | v -0.00221232 -0.990716 3.82515 24 | vt -0.0152355 6.75675 25 | f 1/1/1 5/5/1 4/4/1 26 | 27 | v 0.00629605 -0.990716 -0.0021471 28 | vt 0 -0.0965907 29 | f 6/6/1 5/5/1 1/1/1 30 | 31 | f 6/6/1 2/2/1 5/5/1 32 | 33 | f 2/2/1 6/6/1 3/3/1 34 | 35 | v 0.00629605 1.02518 -0.0021471 36 | vt 0.0835634 3.93701 37 | vn 0.865128 0 -0.501551 38 | v 10.9996 1.02518 18.9602 39 | vt -39.1648 3.93701 40 | vt -39.1648 0 41 | vt 0.0835634 0 42 | f 7/7/2 8/8/2 3/9/2 6/10/2 43 | 44 | vn 0 1 -0 45 | v 7.74799 1.02518 17.1219 46 | vt -13.8626 30.5665 47 | vt -19.685 33.8583 48 | f 7/6/3 9/11/3 8/12/3 49 | 50 | v -0.00221232 1.02518 3.82515 51 | vt 0.0152355 6.75675 52 | f 9/11/3 7/6/3 10/13/3 53 | 54 | v -11.1625 1.02518 18.9602 55 | vt 19.9994 33.8583 56 | f 10/13/3 7/6/3 11/14/3 57 | 58 | vt -0.0832271 0 59 | vn -0.861647 0 -0.507509 60 | vt 39.3237 0 61 | vt 39.3237 3.93701 62 | vt -0.0832271 3.93701 63 | f 6/15/4 1/16/4 11/17/4 7/18/4 64 | 65 | vt 19.685 0 66 | vn -9.71445e-016 0 1 67 | vt 19.685 3.93701 68 | vt -19.9994 3.93701 69 | vt -19.9994 0 70 | f 3/19/5 8/20/5 11/21/5 1/22/5 71 | 72 | f 9/11/3 11/14/3 8/12/3 73 | 74 | v -7.87537 1.02518 17.1219 75 | vt 14.1133 30.5665 76 | f 11/14/3 9/11/3 12/23/3 77 | 78 | vt 14.1133 0 79 | vn 9.71445e-016 0 -1 80 | vt 14.1133 3.93701 81 | vt -13.8626 3.93701 82 | vt -13.8626 0 83 | f 4/24/6 12/25/6 9/26/6 2/27/6 84 | 85 | vt -5.82177 3.93701 86 | vn 0.860473 0 0.509496 87 | vt -33.4923 3.93701 88 | vt -33.4923 0 89 | vt -5.82177 0 90 | f 10/28/7 12/29/7 4/30/7 5/31/7 91 | 92 | f 10/13/3 11/14/3 12/23/3 93 | 94 | vt 5.82986 0 95 | vn -0.863955 0 0.503569 96 | vt 33.3889 0 97 | vt 33.3889 3.93701 98 | vt 5.82986 3.93701 99 | f 5/32/8 2/33/8 9/34/8 10/35/8 100 | 101 | -------------------------------------------------------------------------------- /src/main/resources/models/empty_diamond.mtl: -------------------------------------------------------------------------------- 1 | # 2 | ## Alias OBJ Material File 3 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 4 | 5 | newmtl FrontColor 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 1.000000 1.000000 1.000000 8 | Ks 0.330000 0.330000 0.330000 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/models/empty_diamond.obj: -------------------------------------------------------------------------------- 1 | # Alias OBJ Model File 2 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 3 | # File units = meters 4 | 5 | mtllib empty_diamond.mtl 6 | 7 | g Mesh1 Union Model 8 | 9 | usemtl FrontColor 10 | v 0.00629605 -0.990716 -0.0021471 11 | vt -439.716 1194.48 12 | vn -2.18829e-019 -1 -4.76312e-016 13 | v -8.97318 -0.990716 15.1803 14 | vt -86.1936 596.743 15 | v -11.1625 -0.990716 15.1677 16 | vt 6.2195e-032 597.239 17 | f 1/1/1 2/2/1 3/3/1 18 | 19 | v -0.00221232 -0.990716 3.05969 20 | vt -439.381 1073.93 21 | f 2/2/1 1/1/1 4/4/1 22 | 23 | v 8.81028 -0.990716 15.1551 24 | vt -786.33 597.736 25 | f 4/4/1 1/1/1 5/5/1 26 | 27 | v 10.9996 -0.990716 15.1677 28 | vt -872.524 597.239 29 | f 5/5/1 1/1/1 6/6/1 30 | 31 | v 0.00629605 1.02518 -0.0021471 32 | vt 709.185 79.366 33 | vn 0.809734 3.75248e-016 -0.586798 34 | v 10.9996 1.02518 15.1677 35 | vt -28.39 79.366 36 | vt -28.39 -1.12409e-013 37 | vt 709.185 1.71808e-013 38 | f 7/7/2 8/8/2 6/9/2 1/10/2 39 | 40 | vt 439.716 1194.48 41 | vn -3.17386e-018 1 4.8336e-016 42 | v 8.81028 1.02518 15.1551 43 | vt 786.33 597.736 44 | vt 872.524 597.239 45 | f 7/11/3 9/12/3 8/13/3 46 | 47 | v -0.00221232 1.02518 3.05969 48 | vt 439.381 1073.93 49 | f 7/11/3 10/14/3 9/12/3 50 | 51 | v -8.97318 1.02518 15.1803 52 | vt 86.1936 596.743 53 | f 7/11/3 11/15/3 10/14/3 54 | 55 | v -11.1625 1.02518 15.1677 56 | vt 2.51896e-016 597.239 57 | f 11/15/3 7/11/3 12/16/3 58 | 59 | vt -1222.6 5.24881e-013 60 | vn -0.805284 1.22997e-016 -0.592889 61 | vt -480.947 2.40664e-013 62 | vt -480.947 79.366 63 | vt -1222.6 79.366 64 | f 1/17/4 3/18/4 12/19/4 7/20/4 65 | 66 | v -0.169196 1.02518 30.3376 67 | vt 253.97 79.366 68 | vn -0.809734 2.80367e-017 0.586798 69 | vt -483.605 79.366 70 | vt -483.605 2.94043e-013 71 | v -0.169196 -0.990716 30.3376 72 | vt 253.97 9.82572e-015 73 | f 13/21/5 12/22/5 3/23/5 14/24/5 74 | 75 | vt 432.807 3.83623e-014 76 | f 13/25/3 11/15/3 12/16/3 77 | 78 | v -0.160688 1.02518 27.2758 79 | vt 433.142 120.545 80 | f 11/15/3 13/25/3 15/26/3 81 | 82 | f 15/26/3 13/25/3 8/13/3 83 | 84 | vt 256.607 1.02541e-013 85 | vn 0.805284 -2.94209e-016 0.592889 86 | vt 998.257 3.86759e-013 87 | vt 998.257 79.366 88 | vt 256.607 79.366 89 | f 14/27/6 6/28/6 8/29/6 13/30/6 90 | 91 | vt -432.807 4.51119e-032 92 | v -0.160688 -0.990716 27.2758 93 | vt -433.142 120.545 94 | f 14/31/1 16/32/1 6/6/1 95 | 96 | f 14/31/1 2/2/1 16/32/1 97 | 98 | f 2/2/1 14/31/1 3/3/1 99 | 100 | vt 431.551 79.366 101 | vn 0.808233 4.27942e-016 -0.588863 102 | vt -157.633 79.366 103 | vt -157.633 -1.23348e-013 104 | vt 431.551 1.04026e-013 105 | f 11/33/7 15/34/7 16/35/7 2/36/7 106 | 107 | vt -948.253 79.366 108 | vn -0.803788 9.33402e-018 -0.594915 109 | vt -948.253 2.86797e-013 110 | vt -354.575 5.94237e-014 111 | vt -354.575 79.366 112 | f 9/37/8 5/38/8 16/39/8 15/40/8 113 | 114 | vt -20.0693 79.366 115 | vn -0.808233 -6.11346e-017 0.588863 116 | vt -609.253 79.366 117 | vt -609.253 4.51219e-013 118 | vt -20.0693 2.23845e-013 119 | f 9/41/9 10/42/9 4/43/9 5/44/9 120 | 121 | vt 530.933 79.366 122 | vn 0.803788 -2.81661e-016 0.594915 123 | vt 530.933 2.03738e-013 124 | vt 1124.61 4.31112e-013 125 | vt 1124.61 79.366 126 | f 11/45/10 2/46/10 4/47/10 10/48/10 127 | 128 | f 6/6/1 16/32/1 5/5/1 129 | 130 | f 15/26/3 8/13/3 9/12/3 131 | 132 | -------------------------------------------------------------------------------- /src/main/resources/models/filled_arrow.mtl: -------------------------------------------------------------------------------- 1 | # 2 | ## Alias OBJ Material File 3 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 4 | 5 | newmtl _auto_ 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 1.000000 1.000000 1.000000 8 | Ks 0.330000 0.330000 0.330000 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/models/filled_arrow.obj: -------------------------------------------------------------------------------- 1 | # Alias OBJ Model File 2 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 3 | # File units = meters 4 | 5 | mtllib filled_arrow.mtl 6 | 7 | g Mesh1 skp412A1 Model 8 | 9 | usemtl _auto_ 10 | v 10.116 -1 17.3644 11 | vt 19.6681 34.1337 12 | vn 0 -1 0 13 | v -9.791 -1 17.4888 14 | vt -19.5196 34.1337 15 | v 0.00775914 -1 0.0872946 16 | vt -0.0169575 0 17 | f 1/1/1 2/2/1 3/3/1 18 | 19 | vt 19.6681 0 20 | vn 0.00625188 0 0.99998 21 | v 10.116 1 17.3644 22 | vt 19.6681 3.93701 23 | v -9.791 1 17.4888 24 | vt -19.5196 3.93701 25 | vt -19.5196 0 26 | f 1/4/2 4/5/2 5/6/2 2/7/2 27 | 28 | v 0.00775914 1 0.0872946 29 | vt 0.00847161 3.93701 30 | vn 0.863128 0 -0.504986 31 | vt -39.3947 3.93701 32 | vt -39.3947 0 33 | vt 0.00847161 0 34 | f 6/8/3 4/9/3 1/10/3 3/11/3 35 | 36 | vt -19.6681 34.1337 37 | vn 0 1 -0 38 | vt 0.0169575 0 39 | vt 19.5196 34.1337 40 | f 4/12/4 6/13/4 5/14/4 41 | 42 | vt 0.00841251 0 43 | vn -0.871353 0 -0.490657 44 | vt 39.3208 0 45 | vt 39.3208 3.93701 46 | vt 0.00841251 3.93701 47 | f 3/15/5 2/16/5 5/17/5 6/18/5 48 | 49 | -------------------------------------------------------------------------------- /src/main/resources/models/filled_diamond.mtl: -------------------------------------------------------------------------------- 1 | # 2 | ## Alias OBJ Material File 3 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 4 | 5 | newmtl _auto_ 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 1.000000 1.000000 1.000000 8 | Ks 0.330000 0.330000 0.330000 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/models/filled_diamond.obj: -------------------------------------------------------------------------------- 1 | # Alias OBJ Model File 2 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 3 | # File units = meters 4 | 5 | mtllib filled_diamond.mtl 6 | 7 | g Mesh1 Mesh1_skp412A1_Model Model 8 | 9 | usemtl _auto_ 10 | v -9.831 -1 14.0085 11 | vt 398.268 683.638 12 | vn -3.80405e-031 -1 -3.06285e-016 13 | v 10.076 -1 13.909 14 | vt -385.472 688.535 15 | v 0.277241 -1 27.8302 16 | vt 0.305478 3.4368 17 | f 1/1/1 2/2/1 3/3/1 18 | 19 | vt -39.3701 -393.988 20 | vn -0.00781108 4.78556e-016 -0.999969 21 | v -9.831 1 14.0085 22 | vt 39.3701 -393.988 23 | v 10.076 1 13.909 24 | vt 39.3701 389.768 25 | vt -39.3701 389.768 26 | f 1/4/2 4/5/2 5/6/2 2/7/2 27 | 28 | v 0.277241 1 27.8302 29 | vt 39.3701 3.12065 30 | vn -0.905702 -2.02874e-016 0.423916 31 | vt 39.3701 791.186 32 | vt -39.3701 791.186 33 | vt -39.3701 3.12065 34 | f 6/8/3 4/9/3 1/10/3 3/11/3 35 | 36 | vt -398.268 683.638 37 | vn 3.80405e-031 1 3.06285e-016 38 | vt -0.305478 3.4368 39 | vt 385.472 688.535 40 | f 4/12/4 6/13/4 5/14/4 41 | 42 | vt 39.3701 2.84478 43 | vn 0.911758 -1.96562e-016 0.410728 44 | vt 39.3701 789.092 45 | vt -39.3701 789.092 46 | vt -39.3701 2.84478 47 | f 3/15/5 2/16/5 5/17/5 6/18/5 48 | 49 | g Mesh2 Mesh1_skp412A1_Model1 Model 50 | 51 | v 10.076 -1 13.909 52 | vn 0 -1 -3.06285e-016 53 | v -9.831 -1 14.0085 54 | v -0.0322409 -1 0.0872946 55 | f 7/1/6 8/2/6 9/3/6 56 | 57 | vn 0.00781108 -4.78556e-016 0.999969 58 | v 10.076 1 13.909 59 | v -9.831 1 14.0085 60 | f 7/4/7 10/5/7 11/6/7 8/7/7 61 | 62 | v -0.0322409 1 0.0872946 63 | vn 0.905702 2.02874e-016 -0.423916 64 | f 12/8/8 10/9/8 7/10/8 9/11/8 65 | 66 | vn 0 1 3.06285e-016 67 | f 10/12/9 12/13/9 11/14/9 68 | 69 | vn -0.911758 1.96562e-016 -0.410728 70 | f 9/15/10 8/16/10 11/17/10 12/18/10 71 | 72 | -------------------------------------------------------------------------------- /src/main/resources/models/open_arrow.mtl: -------------------------------------------------------------------------------- 1 | # 2 | ## Alias OBJ Material File 3 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 4 | 5 | newmtl _auto_ 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 1.000000 1.000000 1.000000 8 | Ks 0.330000 0.330000 0.330000 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/models/open_arrow.obj: -------------------------------------------------------------------------------- 1 | # Alias OBJ Model File 2 | # Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited 3 | # File units = meters 4 | 5 | mtllib open_arrow.mtl 6 | 7 | g Mesh1 skp9C0_1 Model 8 | 9 | usemtl _auto_ 10 | v 0.00738233 -1.01 3.51786 11 | vt 0 6.7675 12 | vn 0 -1 0 13 | v -8.074 -1.01 17.4432 14 | vt -15.782 33.9621 15 | v -10.09 -1.01 17.4432 16 | vt -19.719 33.9621 17 | v 0.00738233 -1.01 -0.0088735 18 | vt 0 -0.119795 19 | v 10.0874 -1.01 17.4432 20 | vt 19.685 33.9621 21 | v 8.08274 -1.01 17.4432 22 | vt 15.7702 33.9621 23 | f 1/1/1 2/2/1 3/3/1 4/4/1 5/5/1 6/6/1 24 | 25 | v 0.00738233 0.9052 3.51786 26 | vt -5.85324 3.93701 27 | vn 0.864905 0 0.501935 28 | v -8.074 0.9052 17.4432 29 | vt -37.2955 3.93701 30 | vt -37.2955 -3.4972e-015 31 | vt -5.85324 -3.4972e-015 32 | f 7/7/2 8/8/2 2/9/2 1/10/2 33 | 34 | v 0.00738233 0.9052 -0.0088735 35 | vn 0 1 -0 36 | v -10.09 0.9052 17.4432 37 | vt 19.719 33.9621 38 | vt 15.782 33.9621 39 | v 8.08274 0.9052 17.4432 40 | vt -15.7702 33.9621 41 | v 10.0874 0.9052 17.4432 42 | vt -19.685 33.9621 43 | f 9/4/3 10/11/3 8/12/3 7/1/3 11/13/3 12/14/3 44 | 45 | vt -0.10369 -3.4972e-015 46 | vn -0.865565 0 -0.500796 47 | vt 39.2716 -3.4972e-015 48 | vt 39.2716 3.93701 49 | vt -0.10369 3.93701 50 | f 4/15/4 3/16/4 10/17/4 9/18/4 51 | 52 | vt -15.782 -3.4972e-015 53 | vn 1.44329e-015 0 1 54 | vt -15.782 3.93701 55 | vt -19.719 3.93701 56 | vt -19.719 -3.4972e-015 57 | f 2/19/5 8/20/5 10/21/5 3/22/5 58 | 59 | vt 0.103735 3.93701 60 | vn 0.865939 0 -0.50015 61 | vt -39.2545 3.93701 62 | vt -39.2545 -3.4972e-015 63 | vt 0.103735 -3.4972e-015 64 | f 9/23/6 12/24/6 5/25/6 4/26/6 65 | 66 | vt 19.685 -3.4972e-015 67 | vt 19.685 3.93701 68 | vt 15.7702 3.93701 69 | vt 15.7702 -3.4972e-015 70 | f 5/27/5 12/28/5 11/29/5 6/30/5 71 | 72 | vt 5.85434 -3.4972e-015 73 | vn -0.865067 0 0.501656 74 | vt 37.2907 -3.4972e-015 75 | vt 37.2907 3.93701 76 | vt 5.85434 3.93701 77 | f 1/31/7 6/32/7 11/33/7 7/34/7 78 | 79 | -------------------------------------------------------------------------------- /src/main/resources/templates/ArrowTextField.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/resources/templates/CenterTextField.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/resources/templates/PanePreset.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 16 | 17 | 34 | 35 | 36 | 37 |

38 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
48 | 49 | -------------------------------------------------------------------------------- /src/main/resources/templates/TopTextField.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/java/ch/hsr/ogv/model/EndpointTest.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | import javafx.geometry.Point3D; 4 | import javafx.scene.paint.Color; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | public class EndpointTest { 11 | 12 | private ModelClass modelClassA; 13 | private ModelClass modelClassB; 14 | private Relation relationAB; 15 | 16 | @BeforeEach 17 | public void setUp() throws Exception { 18 | modelClassA = new ModelClass("A", new Point3D(0, 0, 0), 100.0, 100.0, Color.BEIGE); 19 | modelClassB = new ModelClass("B", new Point3D(-200, 0, 0), 100.0, 100.0, Color.BEIGE); 20 | relationAB = new Relation(modelClassA, modelClassB, RelationType.DIRECTED_ASSOCIATION); 21 | } 22 | 23 | @Test 24 | public void testGetFriend() { 25 | Endpoint endpointA = relationAB.getStart(); 26 | Endpoint endpointB = relationAB.getEnd(); 27 | assertEquals(endpointB, endpointA.getFriend()); 28 | assertEquals(endpointA, endpointB.getFriend()); 29 | } 30 | 31 | @Test 32 | public void testIsStart() { 33 | Endpoint endpointA = relationAB.getStart(); 34 | assertTrue(endpointA.isStart()); 35 | } 36 | 37 | @Test 38 | public void testIsEnd() { 39 | Endpoint endpointB = relationAB.getEnd(); 40 | assertTrue(endpointB.isEnd()); 41 | } 42 | 43 | @Test 44 | public void testGetAppendant() { 45 | Endpoint endpointA = relationAB.getStart(); 46 | Endpoint endpointB = relationAB.getEnd(); 47 | assertEquals(modelClassA, endpointA.getAppendant()); 48 | assertEquals(modelClassB, endpointB.getAppendant()); 49 | } 50 | 51 | @Test 52 | public void testUniqueID() { 53 | Endpoint endpointA = relationAB.getStart(); 54 | Endpoint endpointB = relationAB.getEnd(); 55 | assertNotEquals(endpointB.getUniqueID(), endpointA.getUniqueID()); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/ch/hsr/ogv/model/ModelBoxTest.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | import javafx.geometry.Point3D; 4 | import javafx.scene.paint.Color; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | public class ModelBoxTest { 11 | 12 | private ModelBox mb; 13 | 14 | @BeforeEach 15 | public void setUp() throws Exception { 16 | mb = new ModelClass("", new Point3D(-200, 200, 0), 100, 100, Color.BEIGE); 17 | } 18 | 19 | @Test 20 | public void testSetCoordinates() { 21 | Point3D newPoint = new Point3D(123, 234, 345); 22 | mb.setCoordinates(newPoint); 23 | assertEquals(newPoint, mb.getCoordinates()); 24 | } 25 | 26 | @Test 27 | public void testSetX() { 28 | double newX = 123; 29 | mb.setX(newX); 30 | assertEquals(new Point3D(123, 200, 0), mb.getCoordinates()); 31 | } 32 | 33 | @Test 34 | public void testSetY() { 35 | double newY = 123; 36 | mb.setY(newY); 37 | assertEquals(new Point3D(-200, 123, 0), mb.getCoordinates()); 38 | } 39 | 40 | @Test 41 | public void testSetZ() { 42 | double newZ = 123; 43 | mb.setZ(newZ); 44 | assertEquals(new Point3D(-200, 200, 123), mb.getCoordinates()); 45 | } 46 | 47 | @Test 48 | public void testSetWidth() { 49 | double newWidth = 123; 50 | mb.setWidth(123); 51 | assertEquals(newWidth, mb.getWidth()); 52 | } 53 | 54 | @Test 55 | public void testSetHeight() { 56 | double newHeight = 123; 57 | mb.setHeight(123); 58 | assertEquals(newHeight, mb.getHeight()); 59 | } 60 | 61 | @Test 62 | public void testSetColor() { 63 | Color newColor = Color.BLUE; 64 | mb.setColor(newColor); 65 | assertEquals(newColor, mb.getColor()); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/ch/hsr/ogv/model/ModelObjectTest.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | import javafx.geometry.Point3D; 4 | import javafx.scene.paint.Color; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | import static org.junit.jupiter.api.Assertions.assertFalse; 10 | 11 | 12 | public class ModelObjectTest { 13 | 14 | private ModelClass modelClassA; 15 | private ModelObject modelObjectA1; 16 | 17 | @BeforeEach 18 | public void setUp() throws Exception { 19 | ModelManager mm = new ModelManager(); 20 | modelClassA = mm.createClass(new Point3D(-200, 200, 0), 100, 100, Color.BEIGE); 21 | modelObjectA1 = mm.createObject(modelClassA); 22 | } 23 | 24 | @Test 25 | public void testAttributeValue() { 26 | String attrName1 = "attr1"; 27 | Attribute attr1 = new Attribute(attrName1); 28 | String attrValue1 = "bla1"; 29 | modelObjectA1.addAttributeValue(attr1, attrValue1); 30 | assertEquals(attrValue1, modelObjectA1.getAttributeValue(attrName1)); 31 | assertEquals(attrValue1, modelObjectA1.getAttributeValues().get(attr1)); 32 | } 33 | 34 | @Test 35 | public void testIsSuperObject() { 36 | assertFalse(modelObjectA1.isSuperObject()); 37 | } 38 | 39 | @Test 40 | public void testChangeAttributeValue() { 41 | String attrName1 = "attr1"; 42 | Attribute attr1 = modelClassA.createAttribute(attrName1); 43 | assertEquals("", modelObjectA1.getAttributeValue(attrName1)); 44 | String newAttrValue = "bli"; 45 | modelObjectA1.changeAttributeValue(attr1, newAttrValue); 46 | assertEquals(newAttrValue, modelObjectA1.getAttributeValue(attrName1)); 47 | } 48 | 49 | @Test 50 | public void testChangeAttributeValueWithName() { 51 | String attrName1 = "attr1"; 52 | Attribute attr1 = modelClassA.createAttribute(attrName1); 53 | assertEquals("", modelObjectA1.getAttributeValue(attrName1)); 54 | String newAttrValue = "bli"; 55 | modelObjectA1.changeAttributeValue(attr1.getName(), newAttrValue); 56 | assertEquals(newAttrValue, modelObjectA1.getAttributeValue(attrName1)); 57 | } 58 | 59 | @Test 60 | public void testChangeAttributeName() { 61 | String attrName1 = "attr1"; 62 | Attribute attr1 = modelClassA.createAttribute(attrName1); 63 | String newAttrName1 = "newAttrName1"; 64 | modelObjectA1.changeAttributeName(attr1, newAttrName1); 65 | assertEquals(modelObjectA1.getAttributeValues().get(attr1), modelObjectA1.getAttributeValue(newAttrName1)); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/ch/hsr/ogv/model/RelationTest.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.model; 2 | 3 | import javafx.geometry.Point3D; 4 | import javafx.scene.paint.Color; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | import static org.junit.jupiter.api.Assertions.assertTrue; 9 | 10 | public class RelationTest { 11 | 12 | @Test 13 | public void testGetFriend() { 14 | ModelClass modelClassA = new ModelClass("A", new Point3D(0, 0, 0), 100.0, 100.0, Color.BEIGE); 15 | ModelClass modelClassB = new ModelClass("B", new Point3D(-200, 0, 0), 100.0, 100.0, Color.BEIGE); 16 | Relation relationAB = new Relation(modelClassA, modelClassB, RelationType.DIRECTED_ASSOCIATION); 17 | 18 | Endpoint endpointA = relationAB.getStart(); 19 | Endpoint endpointB = relationAB.getEnd(); 20 | 21 | assertEquals(endpointB, relationAB.getFriend(endpointA)); 22 | assertEquals(endpointA, relationAB.getFriend(endpointB)); 23 | } 24 | 25 | @Test 26 | public void testGetFriendMM() { 27 | ModelManager mm = new ModelManager(); 28 | ModelClass modelClassA = mm.createClass(new Point3D(0, 0, 0), 100, 100, Color.BEIGE); 29 | ModelClass modelClassB = mm.createClass(new Point3D(-200, 0, 0), 100, 100, Color.BEIGE); 30 | Relation relationAB = mm.createRelation(modelClassA, modelClassB, RelationType.DIRECTED_ASSOCIATION, Color.BLACK); 31 | 32 | Endpoint endpointA = relationAB.getStart(); 33 | Endpoint endpointB = relationAB.getEnd(); 34 | 35 | assertEquals(endpointB, relationAB.getFriend(endpointA)); 36 | assertEquals(endpointA, relationAB.getFriend(endpointB)); 37 | } 38 | 39 | @Test 40 | public void testIsStart() { 41 | ModelClass modelClassA = new ModelClass("A", new Point3D(0, 0, 0), 100.0, 100.0, Color.BEIGE); 42 | ModelClass modelClassB = new ModelClass("B", new Point3D(-200, 0, 0), 100.0, 100.0, Color.BEIGE); 43 | Relation relationAB = new Relation(modelClassA, modelClassB, RelationType.DIRECTED_ASSOCIATION); 44 | 45 | Endpoint endpointA = relationAB.getStart(); 46 | 47 | assertTrue(relationAB.isStart(endpointA)); 48 | } 49 | 50 | @Test 51 | public void testIsStartMM() { 52 | ModelManager mm = new ModelManager(); 53 | ModelClass modelClassA = mm.createClass(new Point3D(0, 0, 0), 100, 100, Color.BEIGE); 54 | ModelClass modelClassB = mm.createClass(new Point3D(-200, 0, 0), 100, 100, Color.BEIGE); 55 | Relation relationAB = mm.createRelation(modelClassA, modelClassB, RelationType.DIRECTED_ASSOCIATION, Color.BLACK); 56 | 57 | Endpoint endpointA = relationAB.getStart(); 58 | 59 | assertTrue(relationAB.isStart(endpointA)); 60 | } 61 | 62 | @Test 63 | public void testIsEnd() { 64 | ModelClass modelClassA = new ModelClass("A", new Point3D(0, 0, 0), 100.0, 100.0, Color.BEIGE); 65 | ModelClass modelClassB = new ModelClass("B", new Point3D(-200, 0, 0), 100.0, 100.0, Color.BEIGE); 66 | Relation relationAB = new Relation(modelClassA, modelClassB, RelationType.DIRECTED_ASSOCIATION); 67 | 68 | Endpoint endpointB = relationAB.getEnd(); 69 | 70 | assertTrue(relationAB.isEnd(endpointB)); 71 | } 72 | 73 | @Test 74 | public void testIsEndMM() { 75 | ModelManager mm = new ModelManager(); 76 | ModelClass modelClassA = mm.createClass(new Point3D(0, 0, 0), 100, 100, Color.BEIGE); 77 | ModelClass modelClassB = mm.createClass(new Point3D(-200, 0, 0), 100, 100, Color.BEIGE); 78 | Relation relationAB = mm.createRelation(modelClassA, modelClassB, RelationType.DIRECTED_ASSOCIATION, Color.BLACK); 79 | 80 | Endpoint endpointB = relationAB.getEnd(); 81 | 82 | assertTrue(relationAB.isEnd(endpointB)); 83 | } 84 | 85 | @Test 86 | public void testChangeDirection() { 87 | ModelManager mm = new ModelManager(); 88 | ModelClass modelClassA = mm.createClass(new Point3D(0, 0, 0), 100, 100, Color.BEIGE); 89 | ModelClass modelClassB = mm.createClass(new Point3D(-200, 0, 0), 100, 100, Color.BEIGE); 90 | Relation relationAB = mm.createRelation(modelClassA, modelClassB, RelationType.DIRECTED_ASSOCIATION, Color.BLACK); 91 | 92 | Endpoint endpointStart = relationAB.getStart(); 93 | Endpoint endpointEnd = relationAB.getEnd(); 94 | 95 | assertEquals(endpointStart, modelClassA.getEndpoints().get(0)); 96 | assertEquals(endpointEnd, modelClassB.getEndpoints().get(0)); 97 | 98 | relationAB.changeDirection(); 99 | 100 | assertEquals(endpointStart, relationAB.getStart()); 101 | assertEquals(endpointEnd, relationAB.getEnd()); 102 | 103 | assertEquals(endpointEnd, modelClassA.getEndpoints().get(0)); 104 | assertEquals(endpointStart, modelClassB.getEndpoints().get(0)); 105 | 106 | assertEquals(endpointEnd, relationAB.getFriend(endpointStart)); 107 | assertEquals(endpointStart, relationAB.getFriend(endpointEnd)); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/test/java/ch/hsr/ogv/util/GeometryUtilTest.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import javafx.geometry.Point2D; 4 | import javafx.geometry.Point3D; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | 9 | public class GeometryUtilTest { 10 | 11 | @Test 12 | public void testDivideLineFractionHalf() { 13 | Point3D startPoint = new Point3D(0, 0, 0); 14 | Point3D endPoint = new Point3D(300, 300, 0); 15 | Point3D result = GeometryUtil.divideLineFraction(startPoint, endPoint, 1.0 / 2.0); 16 | 17 | Point3D middlePoint = new Point3D(150, 150, 0); 18 | assertEquals(middlePoint, result); 19 | } 20 | 21 | @Test 22 | public void testDivideLineFractionHalf2() { 23 | Point3D startPoint = new Point3D(0, 0, 0); 24 | Point3D endPoint = new Point3D(300, 600, 900); 25 | Point3D result = GeometryUtil.divideLineFraction(startPoint, endPoint, 1.0 / 2.0); 26 | 27 | Point3D middlePoint = new Point3D(150, 300, 450); 28 | assertEquals(middlePoint, result); 29 | } 30 | 31 | @Test 32 | public void testDivideLineFractionHalf3() { 33 | Point3D startPoint = new Point3D(100, 1000, 2000); 34 | Point3D endPoint = new Point3D(300, 1600, 2900); 35 | Point3D result = GeometryUtil.divideLineFraction(startPoint, endPoint, 1.0 / 2.0); 36 | 37 | Point3D middlePoint = new Point3D(200, 1300, 2450); 38 | assertEquals(middlePoint, result); 39 | } 40 | 41 | @Test 42 | public void testDivideLineFractionTrippleFirst() { 43 | Point3D startPoint = new Point3D(0, 0, 0); 44 | Point3D endPoint = new Point3D(300, 300, 0); 45 | Point3D result = GeometryUtil.divideLineFraction(startPoint, endPoint, 1.0 / 3.0); 46 | 47 | Point3D middlePoint = new Point3D(100, 100, 0); 48 | assertEquals(middlePoint, result); 49 | } 50 | 51 | @Test 52 | public void testDivideLineFractionTrippleSecond() { 53 | Point3D startPoint = new Point3D(0, 0, 0); 54 | Point3D endPoint = new Point3D(300, 300, 0); 55 | Point3D result = GeometryUtil.divideLineFraction(startPoint, endPoint, 2.0 / 3.0); 56 | 57 | Point3D middlePoint = new Point3D(200, 200, 0); 58 | assertEquals(middlePoint, result); 59 | } 60 | 61 | @Test 62 | public void testdivideLineFraction2D() { 63 | Point2D startPoint = new Point2D(0, 0); 64 | Point2D endPoint = new Point2D(300, 300); 65 | Point2D result = GeometryUtil.divideLineFraction(startPoint, endPoint, 2.0 / 3.0); 66 | 67 | Point2D middlePoint = new Point2D(200, 200); 68 | assertEquals(middlePoint, result); 69 | } 70 | 71 | @Test 72 | public void testRotateXAngle45() { 73 | Point3D startPoint = new Point3D(0, 0, 0); 74 | Point3D endPoint = new Point3D(300, 300, 0); 75 | double result = GeometryUtil.rotateXAngle(startPoint, endPoint); 76 | assertEquals(45.0, result, 0.5); 77 | } 78 | 79 | @Test 80 | public void testRotateXAngle0() { 81 | Point3D startPoint = new Point3D(0, 0, 0); 82 | Point3D endPoint = new Point3D(300, 0, 0); 83 | double result = GeometryUtil.rotateXAngle(startPoint, endPoint); 84 | assertEquals(0.0, result, 0.5); 85 | } 86 | 87 | @Test 88 | public void testRotateXAngle90() { 89 | Point3D startPoint = new Point3D(0, 0, 0); 90 | Point3D endPoint = new Point3D(0, 300, 0); 91 | double result = GeometryUtil.rotateXAngle(startPoint, endPoint); 92 | assertEquals(90.0, result, 0.5); 93 | } 94 | 95 | @Test 96 | public void testRotateYAngle90() { 97 | Point3D startPoint = new Point3D(0, 0, 0); 98 | Point3D endPoint = new Point3D(300, 0, 0); 99 | double result = GeometryUtil.rotateYAngle(startPoint, endPoint); 100 | assertEquals(90.0, result, 0.5); 101 | } 102 | 103 | @Test 104 | public void testRotateYAngle0() { 105 | Point3D startPoint = new Point3D(0, 0, 0); 106 | Point3D endPoint = new Point3D(0, 300, 0); 107 | double result = GeometryUtil.rotateYAngle(startPoint, endPoint); 108 | assertEquals(0.0, result, 0.5); 109 | } 110 | 111 | @Test 112 | public void testLineIntersect() { 113 | Point2D firstLineStart = new Point2D(0, 0); 114 | Point2D firstLineEnd = new Point2D(0, 200); 115 | Point2D secondLineStart = new Point2D(-100, 100); 116 | Point2D secondLineEnd = new Point2D(100, 100); 117 | Point2D intersection = new Point2D(0, 100); 118 | Point2D result = GeometryUtil.lineIntersect(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd); 119 | assertEquals(intersection, result); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/test/java/ch/hsr/ogv/util/MultiplicityParserTest.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertNull; 7 | 8 | public class MultiplicityParserTest { 9 | 10 | @Test 11 | public void testGetParsed() { 12 | String singleDigitMultip = "5"; 13 | String rangeMultiplicity = "1..5"; 14 | String reversedRangeMultip = "5..1"; 15 | String doubleDigitMultip = "2,4"; 16 | String trippleDigitMultip = "2,4,6"; 17 | String rangeWithComma = "2..6,8"; 18 | String rangeWithCommaAndAsteriks = "2..6,*"; 19 | String rangeWithOverlapMultip = "1..5,2..7"; 20 | String asteriksMultip = "*"; 21 | String rangeMultipWithAsteriks = "2..*"; 22 | String reversedRangeMultipWithAsteriks = "*..*"; 23 | 24 | String singleCharMultip = "a"; 25 | String letterMultipl = "abc"; 26 | String emptyMultip = ""; 27 | String doublePointsMultip = ""; 28 | String numberWithLettersMultip = "ab123c"; 29 | String stupidRangesMultip = "1..5,2..7"; 30 | String stupidRangesWithAsteriksMultip = "1..5,2..*"; 31 | String doubleDoublePointsMultip = "1....5"; 32 | String doubleCommaMultip = "1,,3"; 33 | 34 | assertEquals("5", MultiplicityParser.getParsed(singleDigitMultip)); 35 | assertEquals("1..5", MultiplicityParser.getParsed(rangeMultiplicity)); 36 | assertNull(MultiplicityParser.getParsed(reversedRangeMultip)); 37 | assertEquals("2,4", MultiplicityParser.getParsed(doubleDigitMultip)); 38 | assertEquals("2,4,6", MultiplicityParser.getParsed(trippleDigitMultip)); 39 | assertEquals("2..6,8", MultiplicityParser.getParsed(rangeWithComma)); 40 | assertEquals("2..6,*", MultiplicityParser.getParsed(rangeWithCommaAndAsteriks)); 41 | assertEquals("1..5,2..7", MultiplicityParser.getParsed(rangeWithOverlapMultip)); 42 | assertEquals("*", MultiplicityParser.getParsed(asteriksMultip)); 43 | assertEquals("2..*", MultiplicityParser.getParsed(rangeMultipWithAsteriks)); 44 | assertNull(MultiplicityParser.getParsed(reversedRangeMultipWithAsteriks)); 45 | 46 | assertNull(MultiplicityParser.getParsed(singleCharMultip)); 47 | assertNull(MultiplicityParser.getParsed(letterMultipl)); 48 | assertNull(MultiplicityParser.getParsed(emptyMultip)); 49 | assertNull(MultiplicityParser.getParsed(doublePointsMultip)); 50 | assertNull(MultiplicityParser.getParsed(numberWithLettersMultip)); 51 | assertEquals("1..5,2..7", MultiplicityParser.getParsed(stupidRangesMultip)); 52 | assertEquals("1..5,2..*", MultiplicityParser.getParsed(stupidRangesWithAsteriksMultip)); 53 | assertNull(MultiplicityParser.getParsed(doubleDoublePointsMultip)); 54 | assertEquals("1,3", MultiplicityParser.getParsed(doubleCommaMultip)); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/ch/hsr/ogv/util/TextUtilTest.java: -------------------------------------------------------------------------------- 1 | package ch.hsr.ogv.util; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.ArrayList; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | 9 | public class TextUtilTest { 10 | 11 | @Test 12 | public void testCountUpTrailingWithoutNo() { 13 | String str = "bla"; 14 | String result = TextUtil.countUpTrailing(str, 10); 15 | assertEquals("bla10", result); 16 | } 17 | 18 | @Test 19 | public void testCountUpTrailingWithHigherStartValue() { 20 | String str = "bla10"; 21 | String result = TextUtil.countUpTrailing(str, 42); 22 | assertEquals("bla42", result); 23 | } 24 | 25 | @Test 26 | public void testCountUpTrailingWithSmallerStartValue() { 27 | String str = "bla42"; 28 | String result = TextUtil.countUpTrailing(str, 10); 29 | assertEquals("bla43", result); 30 | } 31 | 32 | @Test 33 | public void testJoin() { 34 | ArrayList strings = new ArrayList<>(); 35 | strings.add("Donald"); 36 | strings.add("Dagobert"); 37 | strings.add("Mickey"); 38 | String delimiter = "-"; 39 | String result = TextUtil.join(strings, delimiter); 40 | assertEquals(strings.get(0) + "-" + strings.get(1) + "-" + strings.get(2), result); 41 | } 42 | } 43 | --------------------------------------------------------------------------------