diff --git a/.classpath b/.classpath
index 23427e3..fe8612c 100644
--- a/.classpath
+++ b/.classpath
@@ -13,7 +13,7 @@
-
+
diff --git a/.gitignore b/.gitignore
index 2ac8426..7ffee92 100755
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@ hs_err_pid*
/JetUML-0.9/*
/JetUML-0.9/.idea/workspace.xml
*.iml
-logging
+*.log
+.fuse*
META-INF
diff --git a/conf/ladder.conf b/conf/ladder.conf
new file mode 100644
index 0000000..8fa552d
--- /dev/null
+++ b/conf/ladder.conf
@@ -0,0 +1,18 @@
+# Where should the Ladder system look for the configuration file to configure
+# the logging system?
+loggingConfigFile = logging/ladderLoggingConfig.lcf
+
+# What folder are any domain descriptions stored in?
+domainDescriptions = ../LadderDomains/domainDescriptions/domains/
+
+# What folder are the shape descriptions stored in?
+shapeDescriptions = ../LadderDomains/domainDescriptions/shapes/
+
+# What folder is testData stored in?
+testData = ../LadderData/testData517
+
+# This configuration property is the default domain to load
+defaultLoadDomain = COA.xml
+
+# What folder are the various models stored in?
+modelDir = model
diff --git a/lib/kryo-4.0.0.jar b/lib/kryo-4.0.0.jar
deleted file mode 100644
index e0805d4..0000000
Binary files a/lib/kryo-4.0.0.jar and /dev/null differ
diff --git a/lib/kryo-4.0.2.jar b/lib/kryo-4.0.2.jar
new file mode 100644
index 0000000..85bb050
Binary files /dev/null and b/lib/kryo-4.0.2.jar differ
diff --git a/logging/ladderLoggingConfig.lcf b/logging/ladderLoggingConfig.lcf
new file mode 100644
index 0000000..d54c4d2
--- /dev/null
+++ b/logging/ladderLoggingConfig.lcf
@@ -0,0 +1,230 @@
+# The root category uses the appender called ROOT_APP. You can comment/uncomment
+# a given line to change the default level of debugging for the entire
+# application. For development, you probably want DEBUG. For Deployment, you
+# probably don't want anything but ERROR by default. This can always be changed
+# by editing this file if you need more/less, and you don't have to modify
+# the logging code within the application itself.
+
+
+###################### Root Logger
+## For development
+#log4j.rootCategory=DEBUG, ROOT_APP
+## For deployment
+log4j.rootCategory=ERROR, ROOT_APP
+
+
+###################### ROOT_APP appender
+# APP is set to be a RollingFileAppender which outputs to the file
+# "ladder.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.ROOT_APP=org.apache.log4j.RollingFileAppender
+log4j.appender.ROOT_APP.File=logging/ladder.log
+# 5MB log size limit
+log4j.appender.ROOT_APP.MaxFileSize=5000KB
+# just one other file, then start to recycle
+log4j.appender.ROOT_APP.MaxBackupIndex=1
+log4j.appender.ROOT_APP.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the ROOT_APP log.
+# See org.apache.log4j.PatternLayout for field details
+# Date, priority, thread, logger location (SLOW), message, endline
+log4j.appender.ROOT_APP.layout.ConversionPattern=%-35d{dd MMM yyyy, HH:mm:ss:SSS} %-5p [%t] %l -- %m%n
+
+
+###################### Class Loggers
+#Examples adding loggers for specific classes/packages
+#
+# Adding a logger to a class
+# log4j.logger.=DEBUG,
+#
+# Multiple loggers
+# log4j.logger.=DEBUG, , , ...
+#
+# Currently the available logs are:
+# HIGH_LEVEL - For high level recognition
+# LOW_LEVEL - For low level recognition
+# SEGS - For segmentations
+# CON - Console logging
+
+# These go to both Console (short version) and to the Test file appender
+log4j.logger.test.functional.ladder.recognition.constraint.domains.ShapeDefinitionAccuracyFactory=DEBUG, CONSHORT, TEST
+log4j.logger.test.functional.ladder.recognition.constraint.domains.DomainDescriptionAccuracyTest=DEBUG, CONSHORT, TEST
+
+
+log4j.logger.org.ladder.recognition.constraint.CALVIN=ERROR, HIGH_LEVEL, CON
+log4j.logger.org.ladder.recognition.constraint.builders.ShapeBuilderTracy=ERROR, HIGH_LEVEL, CON
+log4j.logger.org.ladder.recognition.constraint.grouping.PostMidLevelGrouper=ERROR, HIGH_LEVEL, CON
+log4j.logger.org.ladder.recognition.paleo=ERROR, LOW_LEVEL, PALEO
+log4j.logger.org.ladder.recognition.profiling.RunTimeLogger=DEBUG, RUNTIME
+log4j.logger.org.ladder.segmentation=ERROR, LOW_LEVEL, SEGS
+
+log4j.logger.org.ladder.recognition.constraint.domains.compiler.DomainDefinitionCompiler=WARN,CON
+#log4j.logger.org.ladder.recognition.handwriting.HandwritingRecognizer=ERROR, CON
+#log4j.logger.test.functional.ladder.recognition.constraint.domains=INFO, CON
+#log4j.logger.test.functional.ladder.recognition.shapes.SingleShapeAccuracy=INFO, CON
+log4j.logger.org.ladder.recognition.RecognitionManager=ERROR, CON
+#log4j.logger.edu.tamu.deepGreen.recognition.area.AreaRecognizer=DEBUG, CON
+
+## I want to see all the recognition package stuff on the console.
+#log4j.logger.org.ladder.recognition=DEBUG, CON
+## turn constraints off
+#log4j.logger.org.ladder.recognition.constraint.confidence=OFF
+#log4j.logger.org.ladder.recognition.constraint.ConstraintFactory=OFF
+## turn paleo off, except for actual PaleoRecognizer
+#log4j.logger.org.ladder.recognition.paleo=OFF
+#log4j.logger.org.ladder.recognition.paleo.PaleoSketchRecognizer=DEBUG, CON
+## COA TestPanel DEBUG and to the console
+#log4j.logger.edu.tamu.deepGreen.test.COATestPanel=DEBUG, CON
+#log4j.logger.edu.tamu.deepGreen.SIDCLookup=DEBUG, CON
+#log4j.logger.test.ladder.recognition.constraint.domains.SingleExampleShapeAccuracyTest=INFO, CON
+
+###################### LADDER appenders
+# To create an appender, copy one of the ones below and replace the name and file name
+# For example, copy HIGH_LEVEL, replace all instances of HIGH_LEVEL with the new name
+# and change highLevel.log to the name for your log file
+
+
+###################### CON appender
+# CON is set to be a ConsoleAppender which outputs to the file
+# "ladder.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.CON=org.apache.log4j.ConsoleAppender
+log4j.appender.CON.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the CON log.
+# See org.apache.log4j.PatternLayout for field details
+# priority, thread, logger location (SLOW) -- message, endline
+log4j.appender.CON.layout.ConversionPattern=%-5p [%t] %F.%M:%L -- %m%n
+
+
+
+###################### CONSHORT appender
+# CON is set to be a ConsoleAppender which outputs to the file
+# "ladder.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.CONSHORT=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSHORT.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the CON log.
+# See org.apache.log4j.PatternLayout for field details
+# priority, thread, logger location (SLOW) -- message, endline
+log4j.appender.CONSHORT.layout.ConversionPattern=%m%n
+
+
+###################### HIGH_LEVEL appender
+# HIGH_LEVEL is set to be a RollingFileAppender which outputs to the file
+# "highLevel.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.HIGH_LEVEL=org.apache.log4j.RollingFileAppender
+log4j.appender.HIGH_LEVEL.File=logging/highLevel.log
+# 5MB log size limit
+log4j.appender.HIGH_LEVEL.MaxFileSize=5000KB
+# just one other file, then start to recycle
+log4j.appender.HIGH_LEVEL.MaxBackupIndex=1
+log4j.appender.HIGH_LEVEL.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the HIGH_LEVEL log.
+# See org.apache.log4j.PatternLayout for field details
+# Date, priority, thread, logger location (SLOW), message, endline
+log4j.appender.HIGH_LEVEL.layout.ConversionPattern=%-35d{dd MMM yyyy, HH:mm:ss:SSS} %-5p [%t] %l -- %m%n%n
+
+###################### LOW_LEVEL appender
+# LOW_LEVEL is set to be a RollingFileAppender which outputs to the file
+# "lowLevel.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.LOW_LEVEL=org.apache.log4j.RollingFileAppender
+log4j.appender.LOW_LEVEL.File=logging/lowLevel.log
+# 5MB log size limit
+log4j.appender.LOW_LEVEL.MaxFileSize=5000KB
+# just one other file, then start to recycle
+log4j.appender.LOW_LEVEL.MaxBackupIndex=1
+log4j.appender.LOW_LEVEL.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the LOW_LEVEL log.
+# See org.apache.log4j.PatternLayout for field details
+# Date, priority, thread, logger location (SLOW), message, endline
+log4j.appender.LOW_LEVEL.layout.ConversionPattern=%-35d{dd MMM yyyy, HH:mm:ss:SSS} %-5p [%t] %l -- %m%n%n
+
+
+###################### PALEO appender
+# PALEO is set to be a RollingFileAppender which outputs to the file
+# "paleo.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.PALEO=org.apache.log4j.RollingFileAppender
+log4j.appender.PALEO.File=logging/paleo.log
+# 5MB log size limit
+log4j.appender.PALEO.MaxFileSize=5000KB
+# just one other file, then start to recycle
+log4j.appender.PALEO.MaxBackupIndex=1
+log4j.appender.PALEO.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the PALEO log.
+# See org.apache.log4j.PatternLayout for field details
+# Date, priority, thread, logger location (SLOW), message, endline
+log4j.appender.PALEO.layout.ConversionPattern=%-35d{dd MMM yyyy, HH:mm:ss:SSS} %-5p [%t] %l -- %m%n%n
+
+
+###################### SEGS appender
+# SEGS is set to be a RollingFileAppender which outputs to the file
+# "segs.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.SEGS=org.apache.log4j.RollingFileAppender
+log4j.appender.SEGS.File=logging/segmentation.log
+# 5MB log size limit
+log4j.appender.SEGS.MaxFileSize=5000KB
+# just one other file, then start to recycle
+log4j.appender.SEGS.MaxBackupIndex=1
+log4j.appender.SEGS.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the SEGS log.
+# See org.apache.log4j.PatternLayout for field details
+# Date, priority, thread, logger location (SLOW), message, endline
+log4j.appender.SEGS.layout.ConversionPattern=%-35d{dd MMM yyyy, HH:mm:ss:SSS} %-5p [%t] %l -- %m%n%n
+
+
+###################### CONSTR appender
+# CONSTR is set to be a RollingFileAppender which outputs to the file
+# "constraint.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.CONSTR=org.apache.log4j.RollingFileAppender
+log4j.appender.CONSTR.File=logging/constraint.log
+# 5MB log size limit
+log4j.appender.CONSTR.MaxFileSize=5000KB
+# just one other file, then start to recycle
+log4j.appender.CONSTR.MaxBackupIndex=1
+log4j.appender.CONSTR.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the SEGS log.
+# See org.apache.log4j.PatternLayout for field details
+# Date, priority, thread, logger location (SLOW), message, endline
+log4j.appender.CONSTR.layout.ConversionPattern=%-35d{dd MMM yyyy, HH:mm:ss:SSS} %-5p [%t] %l -- %m%n%n
+
+###################### RUNTIME appender
+# RUNTIME is set to be a RollingFileAppender which outputs to the file
+# "runtime.log". If the file gets above a specified size limit, create a new
+# log file, up to a certain number of log files.
+log4j.appender.RUNTIME=org.apache.log4j.RollingFileAppender
+log4j.appender.RUNTIME.File=logging/runtime.log
+# 5MB log size limit
+log4j.appender.RUNTIME.MaxFileSize=5000KB
+# just one other file, then start to recycle
+log4j.appender.RUNTIME.MaxBackupIndex=1
+log4j.appender.RUNTIME.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the SEGS log.
+# See org.apache.log4j.PatternLayout for field details
+# Date, priority, thread, logger location (SLOW), message, endline
+log4j.appender.RUNTIME.layout.ConversionPattern=%-5p [%t]: %m%n
+
+###################### TEST appender
+# TEST is set to be a FileAppender which outputs to the file
+# "test.log". The logger does NOT append, but overwrites with a new file each
+# time
+log4j.appender.TEST=org.apache.log4j.FileAppender
+# Do not append, start a new file each time
+log4j.appender.TEST.append=false
+log4j.appender.TEST.File=logging/test.log
+log4j.appender.TEST.layout=org.apache.log4j.PatternLayout
+# Format to use when logging entries in the TEST log.
+# See org.apache.log4j.PatternLayout for field details
+# Date, priority, thread, logger location (SLOW), message, endline
+log4j.appender.TEST.layout.ConversionPattern=%m%n
+
+
+
+# We can create different appenders and files for different parts of LADDER.
+# These loggers will log their information in their local appenders, PLUS all
+# that information will also be present in the root logger. But, these
+# sub-loggers can have different priorities, etc.
+# For example, here's a logger for objects in org.ladder.core
diff --git a/src/controller/AbstractDiagramController.java b/src/controller/AbstractDiagramController.java
index 31c6af3..ac58b51 100644
--- a/src/controller/AbstractDiagramController.java
+++ b/src/controller/AbstractDiagramController.java
@@ -1,6 +1,7 @@
package controller;
import javafx.application.Platform;
+
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXML;
import javafx.geometry.Bounds;
@@ -20,6 +21,7 @@
import model.edges.*;
import model.nodes.*;
import util.Constants;
+import util.GlobalVariables;
import util.NetworkUtils;
import util.commands.*;
import util.insertIMG.*;
@@ -40,16 +42,20 @@
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
+import org.slf4j.LoggerFactory;
+
import java.io.IOException;
import java.io.File;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+
+import org.controlsfx.control.Notifications;
+import org.slf4j.Logger;
/**
* Controls all user inputs and delegates work to other controllers.
*/
public abstract class AbstractDiagramController {
+ private static Logger logger = LoggerFactory.getLogger(AbstractDiagramController.class);
protected Graph graph;
protected Stage aStage;
@@ -110,13 +116,16 @@ protected enum ToolEnum {
@FXML CheckMenuItem mouseMenuItem;
@FXML
- protected Button createBtn, packageBtn, edgeBtn, selectBtn, drawBtn, undoBtn, redoBtn, moveBtn, deleteBtn, recognizeBtn, voiceBtn;
+ protected Button createBtn, packageBtn, edgeBtn, selectBtn, drawBtn, undoBtn, redoBtn, moveBtn, deleteBtn, recognizeBtn, voiceBtn, commitBtn;
ContextMenu aContextMenu;
private AbstractDiagramController instance = this;
+ private String userName;
+ private String collaborationType = Constants.collaborationTypeSynchronous;
public void initialize() {
+ logger.debug("initialize()");
initDrawPaneActions();
initContextMenu();
initZoomSlider();
@@ -140,6 +149,7 @@ public void initialize() {
}
private void initDrawPaneActions() {
+ logger.debug("initDrawPaneActions()");
//Makes sure the pane doesn't scroll when using a touch screen.
drawPane.setOnScroll(event -> event.consume());
@@ -152,12 +162,29 @@ private void initDrawPaneActions() {
abstract void initNodeActions(AbstractNodeView nodeView);
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String newValue) {
+ userName = newValue;
+ }
+
+ public String getCollaborationType() {
+ return collaborationType;
+ }
+
+ public void setCollaborationType(String newValue) {
+ collaborationType = newValue;
+ }
+
//----------------- DELETING ----------------------------------------
/**
* Deletes all selected nodes, edges and sketches.
*/
void deleteSelected() {
+ logger.debug("deleteSelected()");
CompoundCommand command = new CompoundCommand();
for (AbstractNodeView nodeView : selectedNodes) {
deleteNode(nodeView, command, false, false);
@@ -189,6 +216,7 @@ void deleteSelected() {
* @param remote, If true this command was received from a remote server.
*/
public void deleteNode(AbstractNodeView nodeView, CompoundCommand pCommand, boolean undo, boolean remote) {
+ logger.debug("deleteNode()");
CompoundCommand command = null;
if (pCommand == null && !undo) {
command = new CompoundCommand();
@@ -220,6 +248,7 @@ public void deleteNode(AbstractNodeView nodeView, CompoundCommand pCommand, bool
* @param undo If true this is an undo and no command should be created
*/
public void deleteEdgeView(AbstractEdgeView edgeView, CompoundCommand pCommand, boolean undo, boolean remote) {
+ logger.debug("deleteEdgeView()");
CompoundCommand command = null;
if (pCommand == null && !undo) { //If this is not part of a compoundcommand
command = new CompoundCommand();
@@ -243,6 +272,7 @@ public void deleteEdgeView(AbstractEdgeView edgeView, CompoundCommand pCommand,
}
public void addSketch(Sketch sketch, boolean isImport, boolean remote){
+ logger.debug("addSketch()");
initSketchActions(sketch);
drawPane.getChildren().add(sketch.getPath());
if(!isImport){
@@ -252,6 +282,7 @@ public void addSketch(Sketch sketch, boolean isImport, boolean remote){
}
public void deleteSketch(Sketch sketch, CompoundCommand pCommand, boolean remote) {
+ logger.debug("deleteSketch()");
CompoundCommand command;
if (pCommand == null) {
command = new CompoundCommand();
@@ -272,6 +303,7 @@ public void deleteSketch(Sketch sketch, CompoundCommand pCommand, boolean remote
* @param remote, true if change comes from a remote server
*/
public void deleteNodeEdges(AbstractNode node, CompoundCommand command, boolean undo, boolean remote) {
+ logger.debug("deleteNodeEdges()");
AbstractEdge edge;
ArrayList edgeViewsToBeDeleted = new ArrayList<>();
for (AbstractEdgeView edgeView : allEdgeViews) {
@@ -295,6 +327,7 @@ public void deleteNodeEdges(AbstractNode node, CompoundCommand command, boolean
* @param sketch
*/
private void initSketchActions(Sketch sketch) {
+ logger.debug("initSketchActions()");
sketch.getPath().setOnMousePressed(event -> {
if (mouseCreationActivated) {
handleOnSketchPressedEvents(sketch);
@@ -353,6 +386,7 @@ private void initSketchActions(Sketch sketch) {
}
private void handleOnSketchPressedEvents(Sketch sketch) {
+ logger.debug("handleOnSketchPressedEvents()");
if (sketch.isSelected()) {
selectedSketches.remove(sketch);
sketch.setSelected(false);
@@ -373,6 +407,7 @@ public ArrayList getSelectedEdges() {
//---------------------- MENU HANDLERS ---------------------------------
public void handleMenuActionUML() {
+ logger.debug("handleMenuActionUML()");
List umlButtons = Arrays.asList(createBtn, packageBtn, edgeBtn);
if (umlVisible) {
@@ -398,6 +433,7 @@ public void handleMenuActionUML() {
}
public void handleMenuActionSketches() {
+ logger.debug("handleMenuActionSketches()");
if (sketchesVisible) {
for (Sketch sketch : graph.getAllSketches()) {
drawPane.getChildren().remove(sketch.getPath());
@@ -415,6 +451,7 @@ public void handleMenuActionSketches() {
}
public void handleMenuActionGrid() {
+ logger.debug("handleMenuActionGrid()");
if (graphController.isGridVisible()) {
graphController.setGridVisible(false);
} else {
@@ -423,10 +460,12 @@ public void handleMenuActionGrid() {
}
public void handleMenuActionSnapToGrid(boolean b) {
+ logger.debug("handleMenuActionSnapToGrid()");
nodeController.setSnapToGrid(b);
}
public void handleMenuActionSnapIndicators(boolean b) {
+ logger.debug("handleMenuActionSnapIndicators()");
nodeController.setSnapIndicators(b);
}
@@ -437,6 +476,7 @@ public void handleMenuActionSnapIndicators(boolean b) {
* @param buttons
*/
private void setButtons(boolean disable, List buttons) {
+ logger.debug("setButtons()");
for (Button button : buttons) {
button.setDisable(disable);
}
@@ -446,14 +486,17 @@ private void setButtons(boolean disable, List buttons) {
//------------------------- SAVE-LOAD FEATURE ---------------------------
public void handleMenuActionMouse() {
+ logger.debug("handleMenuActionMouse()");
mouseCreationActivated = !mouseCreationActivated;
}
public void handleMenuActionExit() {
+ logger.debug("handleMenuActionExit()");
Platform.exit();
}
public void handleMenuActionSave() {
+ logger.debug("handleMenuActionSave()");
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save Diagram");
if (!graph.getName().equals("")) {
@@ -468,6 +511,7 @@ public void handleMenuActionSave() {
}
public void handleMenuActionLoad() {
+ logger.debug("handleMenuActionLoad()");
final FileChooser fileChooser = new FileChooser();
File file = fileChooser.showOpenDialog(getStage());
fileChooser.setTitle("Choose XML-file");
@@ -481,6 +525,7 @@ public void handleMenuActionLoad() {
}
public void createXMI(String path) {
+ logger.debug("createXMI()");
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
@@ -498,33 +543,37 @@ public void createXMI(String path) {
}
public void handleMenuActionInsert (){
+ logger.debug("handleMenuActionInsert()");
InsertIMG insertIMG = new InsertIMG(aStage, drawPane);
insertIMG.openFileChooser(this, new Point2D.Double(0,0));
}
public void handleMenuActionNew() {
+ logger.debug("handleMenuActionNew()");
reset();
}
//---------------------------- Remote Collaboration features ---------------------------------
public void handleMenuActionServer(){
- TextInputDialog portDialog = new TextInputDialog("54555");
- portDialog.setTitle("Server Port");
- portDialog.setHeaderText("Please enter port number");
- portDialog.setContentText("Port:");
-
- Optional port = portDialog.showAndWait();
+ logger.debug("handleMenuActionServer()");
+ String[] result = NetworkUtils.ServerConfigDialog();
- ServerController server = new ServerController(graph, this, Integer.parseInt(port.get()));
- serverControllers.add(server);
+ if (result != null) {
+ this.setCollaborationType(GlobalVariables.getKey(result[1]));
+ this.setUserName(result[2]);
+ ServerController server = new ServerController(graph, this, Integer.parseInt(result[0]));
+ serverControllers.add(server);
+ }
}
public boolean handleMenuActionClient(){
+ logger.debug("handleMenuActionClient()");
- String[] result = NetworkUtils.queryServerPort();
+ String[] result = NetworkUtils.clientConfigDialog();
if (result != null) {
+ this.setUserName(result[2]);
ClientController client = new ClientController(this, result[0], Integer.parseInt(result[1]));
if(!client.connect()){
client.close();
@@ -538,23 +587,64 @@ public boolean handleMenuActionClient(){
}
}
+ public boolean handleMenuActionChangeCollaborationType(){
+ logger.debug("handleMenuActionChangeCollaborationType()");
+
+ String[] result = NetworkUtils.clientConfigDialog();
+
+ if (result != null) {
+ // TODO: Implement method
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean handleMenuActionCommit(){
+ logger.debug("handleMenuActionCommit()");
+ boolean success = false;
+ for (AbstractNodeView nodeView : allNodeViews) {
+ if (nodeView instanceof ClassNodeView) {
+ if (((ClassNodeView)nodeView).commitChanges()) {
+ success = true;
+ }
+ }
+ }
+ if (success) {
+ Notifications.create()
+ .title(GlobalVariables.getString("sentedSuccessfully"))
+ .text(GlobalVariables.getString("localChangesSented"))
+ .showInformation();
+ } else {
+ Notifications.create()
+ .title(GlobalVariables.getString("sendFailed"))
+ .text(GlobalVariables.getString("withoutLocalChanges"))
+ .showInformation();
+ }
+ return true;
+ }
+
public void setServerLabel(String s){
+ logger.debug("setServerLabel()");
serverLabel.setText(s);
}
public void closeServers(){
+ logger.debug("closeServers()");
for (ServerController server : serverControllers) {
server.closeServer();
}
}
public void closeClients(){
+ logger.debug("closeClients()");
for(ClientController client : clientControllers){
client.closeClient();
}
}
public void handleMenuActionImage(){
+ logger.debug("handleMenuActionImage()");
try{
WritableImage image = getSnapShot();
FileChooser fileChooser = new FileChooser();
@@ -562,11 +652,12 @@ public void handleMenuActionImage(){
File output = fileChooser.showSaveDialog(getStage());
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", output);
} catch (IOException ex) {
- Logger.getLogger(AbstractDiagramController.class.getName()).log(Level.SEVERE, null, ex);
+ logger.error(ex.toString());
}
}
public WritableImage getSnapShot(){
+ logger.debug("getSnapShot()");
SnapshotParameters sp = new SnapshotParameters();
Bounds bounds = scrollPane.getViewportBounds();
//Not sure why abs is needed, the minX/Y values are negative.
@@ -577,15 +668,19 @@ public WritableImage getSnapShot(){
//------------------------- Context Menu ---------------------------------
private void initContextMenu() {
+ logger.debug("initContextMenu()");
aContextMenu = new ContextMenu();
MenuItem cmItemDelete = new MenuItem("Delete");
cmItemDelete.setOnAction(event -> {
//TODO Is this really needed? Why just not delete all selected?
- if (aContextMenu.getOwnerNode() instanceof AbstractNodeView) {
- deleteNode((AbstractNodeView) aContextMenu.getOwnerNode(), null, false, false);
- }
- deleteSelected();
+ //TODO: Reactivate code when UMLCollab class delete support is implemented
+ if (!this.getCollaborationType().equals(Constants.collaborationTypeUMLCollab)) {
+ if (aContextMenu.getOwnerNode() instanceof AbstractNodeView) {
+ deleteNode((AbstractNodeView) aContextMenu.getOwnerNode(), null, false, false);
+ }
+ deleteSelected();
+ }
});
MenuItem cmItemCopy = new MenuItem("Copy");
@@ -606,7 +701,7 @@ private void initContextMenu() {
InsertIMG insertImg = new InsertIMG(aStage, drawPane);
insertImg.openFileChooser(AbstractDiagramController.this, point);
});
-
+
aContextMenu.getItems().addAll(cmItemCopy, cmItemPaste, cmItemDelete, cmItemInsertImg);
}
@@ -617,9 +712,10 @@ private void initContextMenu() {
* @return the created AbstractNodeView
*/
public AbstractNodeView createNodeView(AbstractNode node, boolean remote) {
+ logger.debug("createNodeView()");
AbstractNodeView newView;
if (node instanceof ClassNode) {
- newView = new ClassNodeView((ClassNode) node);
+ newView = new ClassNodeView((ClassNode) node, this);
} else if (node instanceof PackageNode) {
newView = new PackageNodeView((PackageNode) node);
} else {
@@ -642,6 +738,7 @@ public AbstractNodeView createNodeView(AbstractNode node, boolean remote) {
* @return
*/
public AbstractNodeView addNodeView(AbstractNodeView nodeView, AbstractNode node) {
+ logger.debug("addNodeView()");
drawPane.getChildren().add(nodeView);
initNodeActions(nodeView);
nodeMap.put(nodeView, node);
@@ -663,6 +760,7 @@ public AbstractNodeView addNodeView(AbstractNodeView nodeView, AbstractNode node
* @return
*/
public PictureNodeView createPictureView (ImageView view, Image image, Point2D.Double point){
+ logger.debug("createPictureView()");
PictureNode picNode = new PictureNode(image, point.getX(), point.getY(), view.getImage().getWidth(), view.getImage().getHeight());
PictureNodeView picView = new PictureNodeView(view, picNode);
picNode.setTranslateX(point.getX());
@@ -687,6 +785,7 @@ public PictureNodeView createPictureView (ImageView view, Image image, Point2D.D
* [2+] = Optional new values
*/
public void remoteCommand(String[] dataArray){
+ logger.debug("remoteCommand()");
if(dataArray[0].equals(Constants.changeSketchPoint)){
for(Sketch sketch : graph.getAllSketches()){
if(dataArray[1].equals(sketch.getId())){
@@ -736,7 +835,7 @@ else if(dataArray[0].equals(Constants.changeNodeTranslateY) || dataArray[0].equa
} else if (dataArray[0].equals(Constants.changeNodeTitle)){
for(AbstractNode node : graph.getAllNodes()){
if(dataArray[1].equals(node.getId())){
- node.remoteSetTitle(dataArray[2]);
+ node.remoteSetTitle(dataArray, getCollaborationType());
break;
}
}
@@ -758,11 +857,17 @@ else if(dataArray[0].equals(Constants.changeNodeTranslateY) || dataArray[0].equa
}
}
deleteEdgeView(edgeToBeDeleted, null, false, true);
- } else if (dataArray[0].equals(Constants.changeClassNodeAttributes) ||dataArray[0].equals(Constants.changeClassNodeOperations)){
+ } else if (dataArray[0].equals(Constants.changeClassNodeAttribute)){
+ for(AbstractNode node : graph.getAllNodes()){
+ if(dataArray[1].equals(node.getId())){
+ ((ClassNode)node).remoteSetAttribute(dataArray, getCollaborationType());
+ break;
+ }
+ }
+ } else if (dataArray[0].equals(Constants.changeClassNodeOperation)){
for(AbstractNode node : graph.getAllNodes()){
if(dataArray[1].equals(node.getId())){
- ((ClassNode)node).remoteSetAttributes(dataArray[2]);
- ((ClassNode)node).remoteSetOperations(dataArray[3]);
+ ((ClassNode)node).remoteSetOperation(dataArray, getCollaborationType());
break;
}
}
@@ -804,6 +909,7 @@ else if(dataArray[0].equals(Constants.changeNodeTranslateY) || dataArray[0].equa
*/
public AbstractEdgeView createEdgeView(AbstractEdge edge, AbstractNodeView startNodeView,
AbstractNodeView endNodeView) {
+ logger.debug("createEdgeView()");
AbstractEdgeView edgeView;
if (edge instanceof AssociationEdge) {
edgeView = new AssociationEdgeView(edge, startNodeView, endNodeView);
@@ -826,6 +932,7 @@ public AbstractEdgeView createEdgeView(AbstractEdge edge, AbstractNodeView start
* @return
*/
public AbstractEdgeView addEdgeView(AbstractEdgeView edgeView) {
+ logger.debug("addEdgeView()");
if (edgeView != null) {
drawPane.getChildren().add(edgeView);
graph.addEdge(edgeView.getRefEdge(), false);
@@ -841,6 +948,7 @@ public AbstractEdgeView addEdgeView(AbstractEdgeView edgeView) {
* @return null if graph already hasEdge or start/endnodeview is null. Otherwise the created AbstractEdgeView.
*/
public AbstractEdgeView addEdgeView(AbstractEdge edge, boolean remote) {
+ logger.debug("addEdgeView()");
AbstractNodeView startNodeView = null;
AbstractNodeView endNodeView = null;
AbstractNode tempNode;
@@ -876,6 +984,7 @@ public AbstractEdgeView addEdgeView(AbstractEdge edge, boolean remote) {
* Resets the program, removes everything on the canvas
*/
private void reset() {
+ logger.debug("reset()");
graph = new Graph();
drawPane.getChildren().clear();
nodeMap.clear();
@@ -891,6 +1000,7 @@ private void reset() {
* @param remote True if graph comes from a remote server
*/
public void load(Graph pGraph, boolean remote) {
+ logger.debug("load()");
reset();
if (pGraph != null) {
@@ -918,6 +1028,7 @@ public void load(Graph pGraph, boolean remote) {
//------------------------ Zoom-feature -------------------------------------
private void initZoomSlider() {
+ logger.debug("initZoomSlider()");
zoomSlider.valueProperty().addListener((ov, old_val, new_val) -> {
if (zoomSlider.isValueChanging()) {
@@ -932,6 +1043,7 @@ private void initZoomSlider() {
* Visualises which graph elements are selected and which are not.
*/
void drawSelected() {
+ logger.debug("drawSelected()");
for (AbstractNodeView nodeView : allNodeViews) {
if (selectedNodes.contains(nodeView)) {
nodeView.setSelected(true);
@@ -960,10 +1072,12 @@ void drawSelected() {
Button buttonInUse;
private void initColorPicker(){
+ logger.debug("initColorPicker()");
colorPicker.setValue(Color.BLACK);
colorPicker.setOnAction(t -> sketchController.color = colorPicker.getValue());
}
void setButtonClicked(Button b) {
+ logger.debug("setButtonClicked()");
buttonInUse.getStyleClass().remove("button-in-use");
buttonInUse = b;
buttonInUse.getStyleClass().add("button-in-use");
@@ -976,6 +1090,7 @@ Stage getStage() {
}
void setStage(Stage pStage) {
+ logger.debug("setStage()");
this.aStage = pStage;
}
@@ -1004,6 +1119,7 @@ UndoManager getUndoManager() {
}
void setMode(Mode pMode) {
+ logger.debug("setMode()");
mode = pMode;
}
@@ -1016,23 +1132,28 @@ ToolEnum getTool() {
}
void setTool(ToolEnum pTool) {
+ logger.debug("setTool()");
tool = pTool;
}
void addDialog(AnchorPane dialog) {
+ logger.debug("addDialog()");
allDialogs.add(dialog);
}
boolean removeDialog(AnchorPane dialog) {
+ logger.debug("removeDialog()");
mode = Mode.NO_MODE;
return allDialogs.remove(dialog);
}
void closeLog(){
+ logger.debug("closeLog()");
undoManager.closeLog();
}
public GraphController getGraphController(){
+ logger.debug("getGraphController()");
return graphController;
}
}
diff --git a/src/controller/ClassDiagramController.java b/src/controller/ClassDiagramController.java
index ae58db6..7abc5fd 100644
--- a/src/controller/ClassDiagramController.java
+++ b/src/controller/ClassDiagramController.java
@@ -6,6 +6,8 @@
import javafx.scene.input.MouseButton;
import model.Sketch;
import org.controlsfx.control.Notifications;
+
+import util.GlobalVariables;
import util.commands.CompoundCommand;
import util.commands.MoveGraphElementCommand;
import view.nodes.AbstractNodeView;
@@ -333,6 +335,10 @@ private void initToolBarActions() {
voiceBtn.setGraphic(new ImageView(image));
voiceBtn.setText("");
+ image = new Image("/icons/commitw.png");
+ commitBtn.setGraphic(new ImageView(image));
+ commitBtn.setText("");
+
buttonInUse = createBtn;
buttonInUse.getStyleClass().add("button-in-use");
@@ -389,7 +395,10 @@ private void initToolBarActions() {
.showInformation();
}
voiceController.onVoiceButtonClick();
-
+ });
+
+ commitBtn.setOnAction(event -> {
+ handleMenuActionCommit();
});
}
}
diff --git a/src/controller/ClientController.java b/src/controller/ClientController.java
index 878c6ea..d2c2154 100644
--- a/src/controller/ClientController.java
+++ b/src/controller/ClientController.java
@@ -1,24 +1,33 @@
package controller;
import com.esotericsoftware.kryo.Kryo;
+
+
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
-
import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.scene.control.Alert;
+import javafx.scene.control.Tab;
import model.*;
import model.edges.*;
import model.nodes.AbstractNode;
+import model.nodes.Attribute;
import model.nodes.ClassNode;
+import model.nodes.Operation;
import model.nodes.PackageNode;
+import model.nodes.Title;
import util.Constants;
-
+import util.GlobalVariables;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Communicates changes in the graph to and from the host.
@@ -26,42 +35,80 @@
*/
public class ClientController implements PropertyChangeListener {
+ private static Logger logger = LoggerFactory.getLogger(ClientController.class);
private AbstractDiagramController diagramController;
private Client client;
private String serverIp;
private int port;
-
public ClientController(AbstractDiagramController pDiagramController, String pServerIp, int pPort) {
+ logger.debug("ClientController()");
diagramController = pDiagramController;
serverIp = pServerIp;
port = pPort;
-
- client = new Client();
+
+ // Increase of buffers size to avoid overflow. Defaults: 8192, 2048
+ client = new Client(16384,16384);
initKryo(client.getKryo());
client.addListener(new Listener() {
public void received (Connection connection, Object object) {
- if (object instanceof AbstractNode) {
- Platform.runLater(() -> diagramController.createNodeView((AbstractNode)object, true));
- }
- else if (object instanceof AbstractEdge) {
- Platform.runLater(() -> diagramController.addEdgeView((AbstractEdge)object, true));
- }
- else if (object instanceof Graph){
- Graph graph = (Graph) object;
- graph.addRemotePropertyChangeListener(ClientController.this);
- Platform.runLater(() -> diagramController.load(graph, true));
- }
- else if (object instanceof String[]){
- Platform.runLater(() -> diagramController.remoteCommand((String[])object));
- }
+ if ( object instanceof Object[]) {
+ logger.debug("received()");
+ Object[] dataArray = (Object[]) object;
+ if ( dataArray[0] instanceof AbstractNode) {
+ Platform.runLater(() -> diagramController.createNodeView((AbstractNode)dataArray[0], true));
+ }
+ else if (dataArray[0] instanceof AbstractEdge) {
+ Platform.runLater(() -> diagramController.addEdgeView((AbstractEdge)dataArray[0], true));
+ }
+ else if (dataArray[0] instanceof Graph){
+ Graph graph = (Graph) dataArray[0];
+ graph.addRemotePropertyChangeListener(ClientController.this);
+ Platform.runLater(() -> diagramController.load(graph, true));
+ diagramController.setCollaborationType((String)dataArray[1]);
+ // Update tab name
+ Set keys = TabController.getTabMap().keySet();
+ for (Tab tab: keys)
+ {
+ AbstractDiagramController value = TabController.getTabMap().get(tab);
+ if (value == diagramController) {
+ Platform.runLater(() -> tab.setText(graph.getName()));
+ }
+ }
+ logger.info("Collaboration type setted to " + dataArray[1]);
+ Platform.runLater(() -> diagramController.setServerLabel(
+ GlobalVariables.getString("user") + ": " + diagramController.getUserName() +
+ "\n" + GlobalVariables.getString("collaborationType") + ": " + GlobalVariables.getString(diagramController.getCollaborationType()) +
+ "\n" + GlobalVariables.getString("clientMode") + " (" +
+ serverIp + ":" + port + ")" ));
+ }
+ else if (dataArray[0] instanceof String){
+ String request = (String) dataArray[0];
+ if(request.equals(Constants.changeCollaborationType)){
+ diagramController.setCollaborationType((String)dataArray[1]);
+ logger.info("Collaboration type changed to " + dataArray[1]);
+ Platform.runLater(() -> diagramController.setServerLabel(
+ GlobalVariables.getString("user") + ": " + diagramController.getUserName() +
+ "\n" + GlobalVariables.getString("collaborationType") + ": " + GlobalVariables.getString(diagramController.getCollaborationType()) +
+ "\n" + GlobalVariables.getString("clientMode") + " (" +
+ serverIp + ":" + port + ")" ));
+ Graph graph = (Graph) dataArray[2];
+ graph.addRemotePropertyChangeListener(ClientController.this);
+ Platform.runLater(() -> diagramController.load(graph, true));
+ }
+ else if (object instanceof String[]){
+ Platform.runLater(() -> diagramController.remoteCommand((String[])object));
+ }
+ }
+ }
}
});
}
public boolean connect(){
+ logger.debug("connect()");
client.start();
try {
client.connect(5000, serverIp, port, port);
@@ -75,12 +122,13 @@ public boolean connect(){
client.close();
return false;
}
-
- client.sendTCP(Constants.requestGraph);
+ Object[] dataArray = {Constants.requestGraph, diagramController.getUserName()};
+ client.sendTCP(dataArray);
return true;
}
public void close(){
+ logger.debug("close()");
client.close();
}
@@ -89,86 +137,102 @@ public void close(){
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
- String propertyName = evt.getPropertyName();
+ logger.debug("propertyChange()");
+
+ String propertyName = evt.getPropertyName();
if(propertyName.equals(Constants.sketchAdd)){
- String[] dataArray = {Constants.sketchAdd}; //Because serializing Sketch was tricky
+ String[] dataArray = { Constants.sketchAdd, diagramController.getUserName()}; //Because serializing Sketch was tricky
client.sendTCP(dataArray);
}
else if (propertyName.equals(Constants.changeSketchPoint)){
Sketch sketch = (Sketch) evt.getSource();
Point2D point = (Point2D) evt.getNewValue();
String[] dataArray = {Constants.changeSketchPoint, sketch.getId(),
- Double.toString(point.getX()), Double.toString(point.getY())};
+ Double.toString(point.getX()), Double.toString(point.getY()), diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if (propertyName.equals(Constants.changeSketchStart)) {
Sketch sketch = (Sketch) evt.getSource();
Point2D point = (Point2D) evt.getNewValue();
String[] dataArray = {Constants.changeSketchStart, sketch.getId(),
- Double.toString(point.getX()), Double.toString(point.getY()), sketch.getColor().toString()};
+ Double.toString(point.getX()), Double.toString(point.getY()), sketch.getColor().toString(), diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if (propertyName.equals(Constants.sketchRemove)){
- String[] dataArray = {Constants.sketchRemove, (String)evt.getNewValue()};
+ String[] dataArray = {Constants.sketchRemove, (String)evt.getNewValue(), diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if(propertyName.equals(Constants.NodeAdd)) {
AbstractNode node = (AbstractNode) evt.getNewValue();
- client.sendTCP(node);
+ Object[] dataArray = {node, diagramController.getUserName()};
+ client.sendTCP(dataArray);
}
else if (propertyName.equals(Constants.NodeRemove)){
- String[] dataArray = {Constants.NodeRemove, (String)evt.getNewValue()};
+ String[] dataArray = {Constants.NodeRemove, (String)evt.getNewValue(), diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if (propertyName.equals(Constants.EdgeAdd)){
AbstractEdge edge = (AbstractEdge) evt.getNewValue();
- client.sendTCP(edge);
+ Object[] dataArray = {edge, diagramController.getUserName()};
+ client.sendTCP(dataArray);
}
else if(propertyName.equals(Constants.EdgeRemove)) {
- String [] dataArray = {Constants.EdgeRemove, (String)evt.getNewValue()};
+ String [] dataArray = {Constants.EdgeRemove, (String)evt.getNewValue(), diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if (propertyName.equals(Constants.changeNodeTranslateX) || propertyName.equals(Constants.changeNodeTranslateY)) { //NodeX/Y not needed
AbstractNode node = (AbstractNode) evt.getSource();
- String[] dataArray = {propertyName, node.getId(), Double.toString(node.getTranslateX()), Double.toString(node.getTranslateY())};
+ String[] dataArray = {propertyName, node.getId(),
+ Double.toString(node.getTranslateX()),
+ Double.toString(node.getTranslateY()), diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if (propertyName.equals(Constants.changeNodeWidth) || propertyName.equals(Constants.changeNodeHeight)){
AbstractNode node = (AbstractNode) evt.getSource();
- String[] dataArray = {propertyName, node.getId(), Double.toString(node.getWidth()), Double.toString(node.getHeight())};
+ String[] dataArray = {propertyName, node.getId(),
+ Double.toString(node.getWidth()),
+ Double.toString(node.getHeight()), diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if (propertyName.equals(Constants.changeNodeTitle)) {
AbstractNode node = (AbstractNode) evt.getSource();
- String[] dataArray = {propertyName, node.getId(), node.getTitle()};
+ String[] dataArray = {propertyName, node.getId(), node.getTitle(), diagramController.getUserName()};
+ client.sendTCP(dataArray);
+ }
+ else if (propertyName.equals(Constants.changeClassNodeAttribute)){
+ AbstractNode node = (AbstractNode) evt.getSource();
+ String newValueStr = (String) evt.getNewValue();
+ String[] dataArray = {propertyName, node.getId(), newValueStr, diagramController.getUserName()};
client.sendTCP(dataArray);
}
- else if (propertyName.equals(Constants.changeClassNodeAttributes) || propertyName.equals(Constants.changeClassNodeOperations)){
- ClassNode node = (ClassNode) evt.getSource();
- String[] dataArray = {propertyName, node.getId(), node.getAttributes(), node.getOperations()};
+ else if (propertyName.equals(Constants.changeClassNodeOperation)){
+ AbstractNode node = (AbstractNode) evt.getSource();
+ String newValueStr = (String) evt.getNewValue();
+ String[] dataArray = {propertyName, node.getId(), newValueStr, diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if(propertyName.equals(Constants.changeEdgeStartMultiplicity) || propertyName.equals(Constants.changeEdgeEndMultiplicity)){
AbstractEdge edge = (AbstractEdge) evt.getSource();
- String[] dataArray = {propertyName, edge.getId(), edge.getStartMultiplicity(), edge.getEndMultiplicity()};
+ String[] dataArray = {propertyName, edge.getId(), edge.getStartMultiplicity(), edge.getEndMultiplicity(), diagramController.getUserName()};
client.sendTCP(dataArray);
}
else if(propertyName.equals(Constants.changeLabel)){
AbstractEdge edge = (AbstractEdge) evt.getSource();
- String[] dataArray = {propertyName, edge.getId(), edge.getLabel()};
+ String[] dataArray = {propertyName, edge.getId(), edge.getLabel(), diagramController.getUserName()};
client.sendTCP(dataArray);
} else if (propertyName.equals(Constants.changeSketchTranslateX)) {
Sketch sketch = (Sketch) evt.getSource();
- String[] dataArray = {propertyName, sketch.getId(), Double.toString(sketch.getTranslateX())};
+ String[] dataArray = {propertyName, sketch.getId(), Double.toString(sketch.getTranslateX()), diagramController.getUserName()};
client.sendTCP(dataArray);
} else if (propertyName.equals(Constants.changeSketchTranslateY)) {
Sketch sketch = (Sketch) evt.getSource();
- String[] dataArray = {propertyName, sketch.getId(), Double.toString(sketch.getTranslateY())};
+ String[] dataArray = {propertyName, sketch.getId(), Double.toString(sketch.getTranslateY()), diagramController.getUserName()};
client.sendTCP(dataArray);
}
}
private void initKryo(Kryo kryo){
+ logger.debug("initKryo()");
kryo.register(ClassNode.class);
kryo.register(AbstractNode.class);
kryo.register(PackageNode.class);
@@ -181,9 +245,11 @@ private void initKryo(Kryo kryo){
kryo.register(ArrayList.class);
kryo.register(AbstractEdge.Direction.class);
kryo.register(String[].class);
+ kryo.register(Object[].class);
}
public void closeClient(){
+ logger.debug("closeClient()");
client.close();
}
}
diff --git a/src/controller/Launcher.java b/src/controller/Launcher.java
index 5a1be6b..b626529 100644
--- a/src/controller/Launcher.java
+++ b/src/controller/Launcher.java
@@ -38,7 +38,7 @@ public void start(Stage stage) {
tabController.setStage(stage);
stage.setScene(scene);
- stage.setTitle("OctoUML");
+ stage.setTitle("OctoUML v0.15.0 build 001");
stage.setFullScreen(true);
stage.getIcons().add(new Image("icons/appIcon.png"));
stage.show();
diff --git a/src/controller/NodeController.java b/src/controller/NodeController.java
index 9ef5da9..3237c34 100644
--- a/src/controller/NodeController.java
+++ b/src/controller/NodeController.java
@@ -1,6 +1,5 @@
package controller;
-import controller.dialog.NodeEditDialogController;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
@@ -316,7 +315,7 @@ private void removeSnapIndicators(){
public void onDoubleClick(AbstractNodeView nodeView){
if(nodeView instanceof ClassNodeView){
- showClassNodeEditDialog((ClassNode) diagramController.getNodeMap().get(nodeView));
+ // ClassNodeEditDialog deplecated
}
else { //PackageNode
showNodeTitleDialog(diagramController.getNodeMap().get(nodeView));
@@ -363,14 +362,14 @@ private boolean showNodeTitleDialog(AbstractNode node){
//If name found in less then 5 seconds it sets the name to the package
if(time < 500) {
diagramController.voiceController.titleName = "";
- node.setTitle(title2);
+ node.setTitle(title2,false, null);
}
//Else the name is not changed to a new name
else{
diagramController.voiceController.titleName = "";
}
- node.setTitle(title2);
+ node.setTitle(title2,false,null);
}
VBox group = new VBox();
@@ -380,7 +379,7 @@ private boolean showNodeTitleDialog(AbstractNode node){
okButton.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent event) {
- node.setTitle(input.getText());
+ node.setTitle(input.getText(),false, null);
aDrawPane.getChildren().remove(group);
}
});
@@ -410,96 +409,4 @@ public void handle(ActionEvent event) {
return true;
}
-
- public boolean showClassNodeEditDialog(ClassNode node) {
- if(diagramController.voiceController.voiceEnabled) {
-
- //Change variable testing in MainController to 1(true)
- diagramController.voiceController.testing = 1;
-
- String title = "";
- int time = 0;
- //Looking for a name you want to add to the class or until 5 seconds have passed
- while ((title.equals("") || title == null) && time < 500) {
- try {
- TimeUnit.MILLISECONDS.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- //Check if a name has been commanded
- title = diagramController.voiceController.titleName;
- time++;
- }
-
- //Change variable testing in MainController to 0(false)
- diagramController.voiceController.testing = 0;
-
- //If name found in less then 5 seconds it sets the name to the class
- if (time < 500) {
- diagramController.voiceController.titleName = "";
- node.setTitle(title);
- }
- //Else the name is not changed to a new name
- else {
- diagramController.voiceController.titleName = "";
- }
- }
-
-
- try {
- //Load the classDiagramView.fxml file and create a new stage for the popup
- FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("view/fxml/nodeEditDialog.fxml"));
-
- AnchorPane dialog = loader.load();
- dialog.setBackground(new Background(new BackgroundFill(Color.WHITESMOKE, new CornerRadii(1), null)));
- dialog.setStyle("-fx-border-color: black");
- //Set location for dialog.
- double maxX = aDrawPane.getWidth() - dialog.getPrefWidth();
- double maxY = aDrawPane.getHeight() - dialog.getPrefHeight();
- dialog.setLayoutX(Math.min(maxX,node.getTranslateX()+5));
- dialog.setLayoutY(Math.min(maxY, node.getTranslateY()+5));
-
- NodeEditDialogController controller = loader.getController();
- controller.setNode(node);
- controller.getOkButton().setOnAction(new EventHandler() {
- @Override
- public void handle(ActionEvent event) {
- CompoundCommand command = new CompoundCommand();
- if(controller.hasTitledChanged()){
- command.add(new SetNodeTitleCommand(node, controller.getTitle(), node.getTitle()));
- node.setTitle(controller.getTitle());
- }
- if(controller.hasAttributesChanged()){
- command.add(new SetNodeAttributeCommand(node, controller.getAttributes(), node.getAttributes()));
- node.setAttributes(controller.getAttributes());
- }
- if(controller.hasOperationsChanged()){
- command.add(new SetNodeOperationsCommand(node, controller.getOperations(), node.getOperations()));
- node.setOperations(controller.getOperations());
- }
- if(command.size() > 0){
- diagramController.getUndoManager().add(command);
- }
- aDrawPane.getChildren().remove(dialog);
- diagramController.removeDialog(dialog);
- }
- });
-
- controller.getCancelButton().setOnAction(new EventHandler() {
- @Override
- public void handle(ActionEvent event) {
- aDrawPane.getChildren().remove(dialog);
- diagramController.removeDialog(dialog);
- }
- });
- aDrawPane.getChildren().add(dialog);
- diagramController.addDialog(dialog);
- return controller.isOkClicked();
-
- } catch (IOException e) {
- //Exception gets thrown if the classDiagramView.fxml file could not be loaded
- e.printStackTrace();
- return false;
- }
- }
}
diff --git a/src/controller/ServerController.java b/src/controller/ServerController.java
index af08a44..14db1b2 100644
--- a/src/controller/ServerController.java
+++ b/src/controller/ServerController.java
@@ -1,6 +1,7 @@
package controller;
import com.esotericsoftware.kryo.Kryo;
+
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.Server;
@@ -12,18 +13,23 @@
import model.nodes.ClassNode;
import model.nodes.PackageNode;
import util.Constants;
+import util.GlobalVariables;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Forward changes in the graph to all clients.
* Used by MainController for turning the diagram in to a host for clients to connect to.
*/
public class ServerController implements PropertyChangeListener {
+ private static Logger logger = LoggerFactory.getLogger(ServerController.class);
private Graph graph;
private Server server;
private AbstractDiagramController diagramController;
@@ -31,12 +37,14 @@ public class ServerController implements PropertyChangeListener {
private int nrClients = 0;
public ServerController(Graph pGraph, AbstractDiagramController pDiagramController, int pPort) {
+ logger.debug("ServerController()");
diagramController = pDiagramController;
port = pPort;
graph = pGraph;
graph.addRemotePropertyChangeListener(this);
- server = new Server();
+ // Increase of buffers size to avoid overflow. Defaults: 16384, 2048
+ server = new Server(16384,16384);
server.start();
try {
server.bind(port,port);
@@ -44,43 +52,64 @@ public ServerController(Graph pGraph, AbstractDiagramController pDiagramControll
e.printStackTrace();
}
- Platform.runLater(() -> diagramController.setServerLabel("Clients: " + Integer.toString(nrClients)));
+ Platform.runLater(() -> diagramController.setServerLabel(
+ GlobalVariables.getString("user") + ": " + diagramController.getUserName() +
+ "\n" + GlobalVariables.getString("collaborationType") + ": " + GlobalVariables.getString(diagramController.getCollaborationType()) +
+ "\n" + GlobalVariables.getString("serverMode") +
+ " (" + GlobalVariables.getString("port") + ": " + port + ", " +
+ GlobalVariables.getString("clients") + ": " + Integer.toString(nrClients) + ")") );
initKryo(server.getKryo());
-
server.addListener(new Listener() {
public void received (Connection connection, Object object) {
- if (object instanceof Sketch) {
- Platform.runLater(() -> diagramController.addSketch((Sketch)object, false, true));
- }
- else if (object instanceof String) {
- String request = (String)object;
- if(request.equals(Constants.requestGraph)){
- connection.sendTCP(diagramController.getGraphModel());
+ if ( object instanceof Object[]) {
+ logger.debug("received()");
+ Object[] dataArray = (Object[]) object;
+ if (dataArray[0] instanceof Sketch) {
+ Platform.runLater(() -> diagramController.addSketch((Sketch)dataArray[0], false, true));
+ }
+ else if (dataArray[0] instanceof String) {
+ String request = (String) dataArray[0];
+ if(request.equals(Constants.requestGraph)){
+ Object[] sendDataArray = {diagramController.getGraphModel(),
+ diagramController.getCollaborationType(),
+ diagramController.getUserName()};
+ connection.sendTCP(sendDataArray);
+ }
+ else if (object instanceof String[]) {
+ server.sendToAllExceptTCP(connection.getID(), object);
+ Platform.runLater(() -> diagramController.remoteCommand((String[])object));
+ }
+ }
+ else if (dataArray[0] instanceof AbstractNode) {
+ server.sendToAllExceptTCP(connection.getID(), dataArray);
+ Platform.runLater(() -> diagramController.createNodeView((AbstractNode)dataArray[0], true));
+ }
+ else if (dataArray[0] instanceof AbstractEdge) {
+ server.sendToAllExceptTCP(connection.getID(), dataArray);
+ Platform.runLater(() -> diagramController.addEdgeView((AbstractEdge)dataArray[0], true));
}
- }
- else if (object instanceof AbstractNode) {
- server.sendToAllExceptTCP(connection.getID(), object);
- Platform.runLater(() -> diagramController.createNodeView((AbstractNode)object, true));
- }
- else if (object instanceof AbstractEdge) {
- server.sendToAllExceptTCP(connection.getID(), object);
- Platform.runLater(() -> diagramController.addEdgeView((AbstractEdge)object, true));
- }
- else if (object instanceof String[]){
- server.sendToAllExceptTCP(connection.getID(), object);
- Platform.runLater(() -> diagramController.remoteCommand((String[])object));
- }
+ }
}
public void connected(Connection c){
nrClients++;
- Platform.runLater(() -> diagramController.setServerLabel("Clients: " + Integer.toString(nrClients)));
+ Platform.runLater(() -> diagramController.setServerLabel(
+ GlobalVariables.getString("user") + ": " + diagramController.getUserName() +
+ "\n" + GlobalVariables.getString("collaborationType") + ": " + GlobalVariables.getString(diagramController.getCollaborationType()) +
+ "\n" + GlobalVariables.getString("serverMode") +
+ " (" + GlobalVariables.getString("port") + ": " + port + ", " +
+ GlobalVariables.getString("clients") + ": " + Integer.toString(nrClients) + ")") );
}
public void disconnected(Connection c){
nrClients--;
- Platform.runLater(() -> diagramController.setServerLabel("Clients: " + Integer.toString(nrClients)));
+ Platform.runLater(() -> diagramController.setServerLabel(
+ GlobalVariables.getString("user") + ": " + diagramController.getUserName() +
+ "\n" + GlobalVariables.getString("collaborationType") + ": " + GlobalVariables.getString(diagramController.getCollaborationType()) +
+ "\n" + GlobalVariables.getString("serverMode") +
+ " (" + GlobalVariables.getString("port") + ": " + port + ", " +
+ GlobalVariables.getString("clients") + ": " + Integer.toString(nrClients) + ")") );
}
});
@@ -91,86 +120,105 @@ public void disconnected(Connection c){
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
+ logger.debug("propertyChange()");
String propertyName = evt.getPropertyName();
if(propertyName.equals(Constants.sketchAdd)){
- String[] dataArray = {Constants.sketchAdd};
+ String[] dataArray = {Constants.sketchAdd, diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if (propertyName.equals(Constants.changeSketchPoint)){
Sketch sketch = (Sketch) evt.getSource();
Point2D point = (Point2D) evt.getNewValue();
String[] dataArray = {Constants.changeSketchPoint, sketch.getId(),
- Double.toString(point.getX()), Double.toString(point.getY())};
+ Double.toString(point.getX()), Double.toString(point.getY()), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if (propertyName.equals(Constants.changeSketchStart)) {
Sketch sketch = (Sketch) evt.getSource();
Point2D point = (Point2D) evt.getNewValue();
String[] dataArray = {Constants.changeSketchStart, sketch.getId(),
- Double.toString(point.getX()), Double.toString(point.getY()), sketch.getColor().toString()};
+ Double.toString(point.getX()), Double.toString(point.getY()), sketch.getColor().toString(), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if (propertyName.equals(Constants.sketchRemove)){
- String[] dataArray = {Constants.sketchRemove, (String)evt.getNewValue()};
+ String[] dataArray = {Constants.sketchRemove, (String)evt.getNewValue(), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if(propertyName.equals(Constants.NodeAdd)) {
AbstractNode node = (AbstractNode) evt.getNewValue();
- server.sendToAllTCP(node);
+ Object[] dataArray = {node, diagramController.getUserName()};
+ server.sendToAllTCP(dataArray);
}
else if (propertyName.equals(Constants.NodeRemove)){
- String[] dataArray = {Constants.NodeRemove, (String)evt.getNewValue()};
+ String[] dataArray = {Constants.NodeRemove, (String)evt.getNewValue(), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if (propertyName.equals(Constants.EdgeAdd)){
AbstractEdge edge = (AbstractEdge) evt.getNewValue();
- server.sendToAllTCP(edge);
+ Object[] dataArray = {edge, diagramController.getUserName()};
+ server.sendToAllTCP(dataArray);
}
else if(propertyName.equals(Constants.EdgeRemove)) {
- String [] dataArray = {Constants.EdgeRemove, (String)evt.getNewValue()};
+ String [] dataArray = {Constants.EdgeRemove, (String)evt.getNewValue(), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if (propertyName.equals(Constants.changeNodeTranslateX) || propertyName.equals(Constants.changeNodeTranslateY)) { //NodeX/Y not needed
AbstractNode node = (AbstractNode) evt.getSource();
- String[] dataArray = {propertyName, node.getId(), Double.toString(node.getTranslateX()), Double.toString(node.getTranslateY())};
+ String[] dataArray = {propertyName, node.getId(), Double.toString(node.getTranslateX()),
+ Double.toString(node.getTranslateY()), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if (propertyName.equals(Constants.changeNodeWidth) || propertyName.equals(Constants.changeNodeHeight)){
AbstractNode node = (AbstractNode) evt.getSource();
- String[] dataArray = {propertyName, node.getId(), Double.toString(node.getWidth()), Double.toString(node.getHeight())};
+ String[] dataArray = {propertyName, node.getId(), Double.toString(node.getWidth()),
+ Double.toString(node.getHeight()), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if (propertyName.equals(Constants.changeNodeTitle)) {
AbstractNode node = (AbstractNode) evt.getSource();
- String[] dataArray = {propertyName, node.getId(), node.getTitle()};
+ String[] dataArray = {propertyName, node.getId(), node.getTitle(), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
- else if (propertyName.equals(Constants.changeClassNodeAttributes) || propertyName.equals(Constants.changeClassNodeOperations)){
- ClassNode node = (ClassNode) evt.getSource();
- String[] dataArray = {propertyName, node.getId(), node.getAttributes(), node.getOperations()};
+ else if (propertyName.equals(Constants.changeClassNodeAttribute)){
+ AbstractNode node = (AbstractNode) evt.getSource();
+ String newValueStr = (String) evt.getNewValue();
+ String[] dataArray = {propertyName, node.getId(), newValueStr, diagramController.getUserName()};
+ server.sendToAllTCP(dataArray);
+ }
+ else if (propertyName.equals(Constants.changeClassNodeOperation)){
+ AbstractNode node = (AbstractNode) evt.getSource();
+ String newValueStr = (String) evt.getNewValue();
+ String[] dataArray = {propertyName, node.getId(), newValueStr, diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if(propertyName.equals(Constants.changeEdgeStartMultiplicity) || propertyName.equals(Constants.changeEdgeEndMultiplicity)){
AbstractEdge edge = (AbstractEdge) evt.getSource();
- String[] dataArray = {propertyName, edge.getId(), edge.getStartMultiplicity(), edge.getEndMultiplicity()};
+ String[] dataArray = {propertyName, edge.getId(), edge.getStartMultiplicity(),
+ edge.getEndMultiplicity(), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
else if(propertyName.equals(Constants.changeLabel)){
AbstractEdge edge = (AbstractEdge) evt.getSource();
- String[] dataArray = {propertyName, edge.getId(), edge.getLabel()};
+ String[] dataArray = {propertyName, edge.getId(), edge.getLabel(), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
} else if (propertyName.equals(Constants.changeSketchTranslateX)) {
Sketch sketch = (Sketch) evt.getSource();
- String[] dataArray = {propertyName, sketch.getId(), Double.toString(sketch.getTranslateX())};
+ String[] dataArray = {propertyName, sketch.getId(), Double.toString(sketch.getTranslateX()), diagramController.getUserName()};
server.sendToAllTCP(dataArray);
} else if (propertyName.equals(Constants.changeSketchTranslateY)) {
Sketch sketch = (Sketch) evt.getSource();
- String[] dataArray = {propertyName, sketch.getId(), Double.toString(sketch.getTranslateY())};
+ String[] dataArray = {propertyName, sketch.getId(), Double.toString(sketch.getTranslateY()), diagramController.getUserName()};
+ server.sendToAllTCP(dataArray);
+ } else if (propertyName.equals(Constants.changeCollaborationType)) {
+ Object[] dataArray = {diagramController.getGraphModel(),
+ diagramController.getCollaborationType(),
+ diagramController.getUserName()};
server.sendToAllTCP(dataArray);
}
}
private void initKryo(Kryo kryo){
+ logger.debug("initKryo()");
kryo.register(ClassNode.class);
kryo.register(AbstractNode.class);
kryo.register(PackageNode.class);
@@ -183,9 +231,11 @@ private void initKryo(Kryo kryo){
kryo.register(ArrayList.class);
kryo.register(AbstractEdge.Direction.class);
kryo.register(String[].class);
+ kryo.register(Object[].class);
}
public void closeServer(){
+ logger.debug("closeServer()");
server.close();
server.stop();
}
diff --git a/src/controller/TabController.java b/src/controller/TabController.java
index 1643405..858f253 100644
--- a/src/controller/TabController.java
+++ b/src/controller/TabController.java
@@ -37,12 +37,15 @@ public class TabController {
@FXML
private TabPane tabPane;
private Stage stage;
- private Map tabMap = new HashMap<>();
+ private static Map tabMap = new HashMap<>();
public static final String CLASS_DIAGRAM_VIEW_PATH = "view/fxml/classDiagramView.fxml";
public static final String SEQUENCE_DIAGRAM_VIEW_PATH = "view/fxml/sequenceDiagramView.fxml";
-
+ public static Map getTabMap() {
+ return tabMap;
+ }
+
@FXML
public void initialize() {
}
@@ -117,8 +120,9 @@ public void handleMenuActionNewSequenceDiagram() {
}
public void handleMenuActionServer(){
- Tab tab = addTab(CLASS_DIAGRAM_VIEW_PATH);
- tabPane.getSelectionModel().select(tab);
+ // Tab tab = addTab(CLASS_DIAGRAM_VIEW_PATH);
+ // tabPane.getSelectionModel().select(tab);
+ Tab tab = tabPane.getSelectionModel().getSelectedItem();
tabMap.get(tabPane.getSelectionModel().getSelectedItem()).handleMenuActionServer();
}
@@ -130,6 +134,14 @@ public void handleMenuActionClient(){
}
}
+ public void handleMenuActionChangeCollaborationType(){
+ tabMap.get(tabPane.getSelectionModel().getSelectedItem()).handleMenuActionChangeCollaborationType();
+ }
+
+ public void handleMenuActionCommit(){
+ tabMap.get(tabPane.getSelectionModel().getSelectedItem()).handleMenuActionCommit();
+ }
+
public void handleMenuActionImage(){
tabMap.get(tabPane.getSelectionModel().getSelectedItem()).handleMenuActionImage();
}
diff --git a/src/controller/dialog/NodeEditDialogController.java b/src/controller/dialog/NodeEditDialogController.java
deleted file mode 100644
index 3a670a6..0000000
--- a/src/controller/dialog/NodeEditDialogController.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package controller.dialog;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.control.TextArea;
-import javafx.scene.control.TextField;
-import model.nodes.ClassNode;
-
-/**
- * Dialog to edit details of a node.
- *
- * @author Marco Jakob
- */
-public class NodeEditDialogController {
-
- @FXML
- private TextField titleField;
- @FXML
- private TextArea attributesArea;
- @FXML
- private TextArea operationsArea;
- @FXML
- private Button okButton;
- @FXML
- private Button cancelButton;
-
-
- private ClassNode node;
- private boolean okClicked = false;
-
- /**
- * Initializes the controller class. This method is automatically called
- * after the classDiagramView.fxml file has been loaded.
- */
- @FXML
- private void initialize() {
-
- }
-
-
- /**
- * Sets the node to be edited in the dialog.
- *
- * @param node
- */
- public void setNode(ClassNode node) {
- this.node = node;
-
- titleField.setText(this.node.getTitle());
- attributesArea.setText(this.node.getAttributes());
- operationsArea.setText(this.node.getOperations());
- }
-
- public Button getOkButton() {
- return okButton;
- }
-
- public Button getCancelButton() {
- return cancelButton;
- }
-
- public String getTitle() {
- return titleField.getText();
- }
-
- public String getAttributes(){
- return attributesArea.getText();
- }
-
- public String getOperations() {
- return operationsArea.getText();
- }
-
- public boolean hasTitledChanged(){
- if(this.node.getTitle() == null){
- return titleField.getText() != null;
- } else {
- return !this.node.getTitle().equals(titleField.getText());
- }
- }
-
- public boolean hasAttributesChanged(){
- if(this.node.getAttributes() == null){
- return attributesArea.getText() != null;
- } else {
- return !this.node.getAttributes().equals(attributesArea.getText());
- }
- }
-
- public boolean hasOperationsChanged(){
- if(this.node.getOperations() == null){
- return operationsArea.getText() != null;
- } else {
- return !this.node.getOperations().equals(operationsArea.getText());
- }
- }
-
- /**
- * Returns true if the user clicked OK, false otherwise.
- * @return
- */
- public boolean isOkClicked() {
- return okClicked;
- }
-
- /**
- * Called when the user clicks ok.
- */
- private void handleOk() {
- if (isInputValid()) {
- okClicked = true;
- }
- }
-
- /**
- * Called when the user clicks cancel.
- */
-
- private void handleCancel() {
- }
-
- /**
- * Validates the user input in the text fields.
- *
- * @return true if the input is valid
- */
- private boolean isInputValid() {
- return true; //Use if we want to
- }
-}
\ No newline at end of file
diff --git a/src/icons/commit.png b/src/icons/commit.png
new file mode 100644
index 0000000..01147d8
Binary files /dev/null and b/src/icons/commit.png differ
diff --git a/src/icons/commitw.png b/src/icons/commitw.png
new file mode 100644
index 0000000..6d4fd6a
Binary files /dev/null and b/src/icons/commitw.png differ
diff --git a/src/model/Graph.java b/src/model/Graph.java
index 14f956c..59b1399 100644
--- a/src/model/Graph.java
+++ b/src/model/Graph.java
@@ -1,6 +1,7 @@
package model;
import javafx.geometry.Point2D;
+
import model.edges.AbstractEdge;
import model.edges.Edge;
import model.nodes.AbstractNode;
@@ -15,11 +16,16 @@
import java.util.ArrayList;
import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Model-representation of a Graph.
*/
public class Graph implements Serializable, PropertyChangeListener {
+ private static final Logger logger = LoggerFactory.getLogger(Graph.class);
+
private static int objectCount = 0;
private int id;
@@ -32,10 +38,12 @@ public class Graph implements Serializable, PropertyChangeListener {
private String name = "";
public Graph() {
+ logger.debug("Graph()");
id = ++ objectCount;
}
public void setName(String name){
+ logger.debug("setName()");
this.name = name;
}
@@ -50,6 +58,7 @@ public String getName(){
* @param remote, true if change comes from a remote server
*/
public void addNode(AbstractNode n, boolean remote){
+ logger.debug("addNode()");
assert n != null;
for (AbstractNode node : allNodes) {
if (node instanceof PackageNode) {
@@ -74,6 +83,7 @@ public void addNode(AbstractNode n, boolean remote){
* @param e, cannot be null.
*/
public boolean addEdge(Edge e, boolean remote){
+ logger.debug("addEdge()");
assert e != null;
boolean success = allEdges.add(e);
if(!remote){
@@ -89,6 +99,7 @@ public boolean addEdge(Edge e, boolean remote){
* @param s, cannot be null.
*/
public void addSketch(Sketch s, boolean remote) {
+ logger.debug("addSketch()");
assert s != null;
if(!remote){
remoteChanges.firePropertyChange(Constants.sketchAdd, null, s);
@@ -105,6 +116,7 @@ public void addSketch(Sketch s, boolean remote) {
* @return true if the Node is removed, otherwise false.
*/
public boolean removeNode(Node n, boolean remote) {
+ logger.debug("removeNode()");
assert n != null;
if(!remote) {
remoteChanges.firePropertyChange(Constants.NodeRemove, null, n.getId());
@@ -120,6 +132,7 @@ public boolean removeNode(Node n, boolean remote) {
* @return true if the Edge is successfully removed.
*/
public boolean removeEdge(Edge e, boolean remote) {
+ logger.debug("removeEdge()");
assert e != null;
if(!remote){
remoteChanges.firePropertyChange(Constants.EdgeRemove, null, e.getId());
@@ -128,6 +141,7 @@ public boolean removeEdge(Edge e, boolean remote) {
}
public boolean removeSketch(Sketch s, boolean remote) {
+ logger.debug("removeSketch()");
assert s != null;
if(!remote){
remoteChanges.firePropertyChange(Constants.sketchRemove, null, s.getId());
@@ -199,16 +213,19 @@ public Node findNode(Point2D point) {
//------------------------------- Implemented for serializable ----------------------------------------------------
public void setAllNodes(List allNodes) {
+ logger.debug("setAllNodes()");
this.allNodes.clear();
this.allNodes.addAll(allNodes);
}
public void setAllEdges(List allEdges) {
+ logger.debug("setAllEdges()");
this.allEdges.clear();
this.allEdges.addAll(allEdges);
}
public void setAllSketches(List allSketches) {
+ logger.debug("setAllSketches()");
this.allSketches.clear();
this.allSketches.addAll(allSketches);
}
@@ -216,16 +233,24 @@ public void setAllSketches(List allSketches) {
public String getId(){
return "GRAPH_" + id;
}
-
- public void addRemotePropertyChangeListener(PropertyChangeListener l) {
+
+ public void setId(int id) {
+ logger.debug("setId()");
+ this.id = id;
+ }
+
+ public void addRemotePropertyChangeListener(PropertyChangeListener l) {
+ logger.debug("addRemotePropertyChangeListener()");
remoteChanges.addPropertyChangeListener(l);
}
public void removeRemotePropertyChangeListener(PropertyChangeListener l) {
+ logger.debug("removeRemotePropertyChangeListener()");
remoteChanges.removePropertyChangeListener(l);
}
public void listenToElement(Object e){
+ logger.debug("listenToElement()");
if(e instanceof AbstractNode){
((AbstractNode)e).addRemotePropertyChangeListener(this);
} else if (e instanceof Sketch){
@@ -240,6 +265,7 @@ public void listenToElement(Object e){
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
+ logger.debug("propertyChange()");
remoteChanges.firePropertyChange(evt);
}
}
diff --git a/src/model/RemoteChange.java b/src/model/RemoteChange.java
new file mode 100644
index 0000000..26b210a
--- /dev/null
+++ b/src/model/RemoteChange.java
@@ -0,0 +1,37 @@
+package model;
+
+import java.util.Date;
+
+public class RemoteChange {
+
+ private String userName;
+ private Date date;
+ private Object change;
+
+ public RemoteChange(String userName, Date date, Object change) {
+ super();
+ this.userName = userName;
+ this.date = date;
+ this.change = change;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+ public Date getDate() {
+ return date;
+ }
+ public void setDate(Date date) {
+ this.date = date;
+ }
+ public Object getChange() {
+ return change;
+ }
+ public void setChange(Object change) {
+ this.change = change;
+ }
+}
diff --git a/src/model/edges/AbstractEdge.java b/src/model/edges/AbstractEdge.java
index 44c153e..228679d 100644
--- a/src/model/edges/AbstractEdge.java
+++ b/src/model/edges/AbstractEdge.java
@@ -3,6 +3,7 @@
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
+import java.util.UUID;
import model.nodes.Node;
import util.Constants;
@@ -13,7 +14,7 @@
public abstract class AbstractEdge implements Edge, Serializable {
private static int objectCount = 0; //Used to ID instance
- private int id = 0;
+ private String id;
private static final long serialVersionUID = 1L;
//Listened to by the view, is always fired.
@@ -38,7 +39,7 @@ public AbstractEdge(Node startNode, Node endNode) {
this.endNode = endNode;
direction = Direction.NO_DIRECTION;
- id = ++objectCount;
+ id = UUID.randomUUID().toString();
}
public void setDirection(Direction pDirection) {
@@ -163,7 +164,11 @@ public String getId(){
return "EDGE_" + id;
}
- public static void incrementObjectCount(){
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public static void incrementObjectCount(){
objectCount++;
}
diff --git a/src/model/nodes/AbstractNode.java b/src/model/nodes/AbstractNode.java
index eb0ece4..e31cd4b 100644
--- a/src/model/nodes/AbstractNode.java
+++ b/src/model/nodes/AbstractNode.java
@@ -1,17 +1,25 @@
package model.nodes;
import javafx.geometry.Rectangle2D;
+
import util.Constants;
+import util.GlobalVariables;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Abstract Node to hide some basic functionality for Nodes.
*/
public abstract class AbstractNode implements Node, Serializable
{
+ private static Logger logger = LoggerFactory.getLogger(AbstractNode.class);
+
protected static final double CLASS_MIN_WIDTH = 120;
protected static final double CLASS_MIN_HEIGHT = 100;
protected static final double LIFELINE_MIN_WIDTH = 120;
@@ -21,7 +29,7 @@ public abstract class AbstractNode implements Node, Serializable
private static final long serialVersionUID = 1L;
protected static int objectCount = 0; //Used to ID instance
- private int id;
+ private String id;
//Listened to by the view, is always fired.
protected transient PropertyChangeSupport changes = new PropertyChangeSupport(this);
@@ -31,8 +39,9 @@ public abstract class AbstractNode implements Node, Serializable
protected String aTitle;
protected double x, y, width, height, translateX, translateY, scaleX, scaleY;
protected boolean aIsChild;
-
+
public AbstractNode(double x, double y, double width, double height){
+ logger.debug("AbstractNode()");
this.x = x;
this.y = y;
this.width = width;
@@ -43,25 +52,29 @@ public AbstractNode(double x, double y, double width, double height){
scaleX = 1.0d;
scaleY = 1.0d;
- id = ++objectCount;
+ id = UUID.randomUUID().toString();
}
-
+
public void setIsChild(boolean pIsChild){
+ logger.debug("setIsChild()");
aIsChild = pIsChild;
changes.firePropertyChange(Constants.changeNodeIsChild, null, aIsChild);
}
public boolean isChild(){
+ logger.debug("isChild()");
return aIsChild;
}
public void setX(double x){
+ logger.debug("setX()");
this.x = x;
changes.firePropertyChange(Constants.changeNodeX, null, this.x);
remoteChanges.firePropertyChange(Constants.changeNodeX, null, this.x);
}
public void setY(double y){
+ logger.debug("setY()");
this.y = y;
changes.firePropertyChange(Constants.changeNodeY, null, this.y);
remoteChanges.firePropertyChange(Constants.changeNodeY, null, this.y);
@@ -72,6 +85,7 @@ public void setY(double y){
* @param height
*/
public void setHeight(double height){
+ logger.debug("setHeight()");
this.height = height;
changes.firePropertyChange(Constants.changeNodeHeight, null, this.height);
remoteChanges.firePropertyChange(Constants.changeNodeHeight, null, this.height);
@@ -82,19 +96,33 @@ public void setHeight(double height){
* @param width
*/
public void setWidth(double width){
+ logger.debug("setWidth()");
this.width = width;
changes.firePropertyChange(Constants.changeNodeWidth, null, this.width);
remoteChanges.firePropertyChange(Constants.changeNodeWidth, null, this.width);
}
- public void setTitle(String pTitle) {
+ public void setTitleOnly(String pTitle) {
+ logger.debug("setTitleOnly()");
this.aTitle = pTitle;
- changes.firePropertyChange(Constants.changeNodeTitle, null, aTitle);
- remoteChanges.firePropertyChange(Constants.changeNodeTitle, null, aTitle);
+ }
+
+ public void setTitle(String pTitle, boolean transmit, String collaborationType) {
+ logger.debug("setTitle()");
+ if (aTitle == null) {
+ aTitle = pTitle;
+ }
+ changes.firePropertyChange(Constants.changeNodeTitle, null, pTitle);
+ if ( ( collaborationType != null
+ && collaborationType.equals(Constants.collaborationTypeSynchronous) )
+ || transmit) {
+ remoteChanges.firePropertyChange(Constants.changeNodeTitle, null, pTitle);
+ }
}
@Override
public void setTranslateX(double x) {
+ logger.debug("setTranslateX()");
translateX = x;
changes.firePropertyChange(Constants.changeNodeTranslateX, null, translateX);
remoteChanges.firePropertyChange(Constants.changeNodeTranslateX, null, translateX);
@@ -102,6 +130,7 @@ public void setTranslateX(double x) {
@Override
public void setTranslateY(double y) {
+ logger.debug("setTranslateY()");
translateY = y;
changes.firePropertyChange(Constants.changeNodeTranslateY, null, translateY);
remoteChanges.firePropertyChange(Constants.changeNodeTranslateY, null, translateY);
@@ -109,6 +138,7 @@ public void setTranslateY(double y) {
@Override
public void setScaleX(double x) {
+ logger.debug("setScaleX()");
scaleX = x;
changes.firePropertyChange(Constants.changeNodeScaleX, null, scaleX);
remoteChanges.firePropertyChange(Constants.changeNodeScaleX, null, scaleX);
@@ -116,49 +146,61 @@ public void setScaleX(double x) {
@Override
public void setScaleY(double y) {
+ logger.debug("setScaleY()");
scaleY = y;
changes.firePropertyChange(Constants.changeNodeScaleY, null, scaleY);
remoteChanges.firePropertyChange(Constants.changeNodeScaleY, null, scaleY);
}
public void remoteSetX(double x){
+ logger.debug("remoteSetX()");
this.x = x;
changes.firePropertyChange(Constants.changeNodeX, null, this.x);
}
public void remoteSetY(double y){
+ logger.debug("remoteSetY()");
this.y = y;
changes.firePropertyChange(Constants.changeNodeY, null, this.y);
}
public void remoteSetHeight(double height){
+ logger.debug("remoteSetHeight()");
changes.firePropertyChange(Constants.changeNodeHeight, null, this.height);
}
public void remoteSetWidth(double width){
+ logger.debug("remoteSetWidth()");
changes.firePropertyChange(Constants.changeNodeWidth, null, this.width);
}
- public void remoteSetTitle(String pTitle) {
- this.aTitle = pTitle;
- changes.firePropertyChange(Constants.changeNodeTitle, null, aTitle);
+ public void remoteSetTitle(String[] dataArray, String collaborationType) {
+ logger.debug("remoteSetTitle()");
+ if (collaborationType.equals(Constants.collaborationTypeSynchronous)) {
+ aTitle = dataArray[2];
+ }
+ changes.firePropertyChange(Constants.changeNodeTitle, null, dataArray);
}
public void remoteSetTranslateX(double x) {
+ logger.debug("remoteSetTranslateX()");
translateX = x;
changes.firePropertyChange(Constants.changeNodeTranslateX, null, translateX);
}
public void remoteSetTranslateY(double y) {
+ logger.debug("remoteSetTranslateY()");
translateY = y;
changes.firePropertyChange(Constants.changeNodeTranslateY, null, translateY);
}
public void remoteSetScaleX(double x) {
+ logger.debug("remoteSetScaleX()");
scaleX = x;
changes.firePropertyChange(Constants.changeNodeScaleX, null, scaleX);
}
public void remoteSetScaleY(double y) {
+ logger.debug("remoteSetScaleY()");
scaleY = y;
changes.firePropertyChange(Constants.changeNodeScaleY, null, scaleY);
}
@@ -205,6 +247,7 @@ public String getTitle() {
@Override
public Rectangle2D getBounds() {
+ logger.debug("Rectangle2D()");
return new Rectangle2D(x, y, width, height);
}
@@ -213,6 +256,7 @@ public Rectangle2D getBounds() {
@Override
public String toString() {
+ logger.debug("toString()");
return super.toString() + " x=" + getX() + " y=" + getY() + " height=" + getHeight() + " width=" + getWidth();
}
@@ -220,30 +264,40 @@ public String toString() {
* No-arg constructor for JavaBean convention
*/
public AbstractNode(){
-
+ logger.debug("AbstractNode()");
}
public String getId(){
return "NODE_" + id;
}
+
+ public void setId(String id) {
+ logger.debug("setId()");
+ this.id = id;
+ }
- public static void incrementObjectCount(){
+ public static void incrementObjectCount(){
+ logger.debug("incrementObjectCount()");
objectCount++;
}
public void addPropertyChangeListener(PropertyChangeListener l) {
+ logger.debug("addPropertyChangeListener()");
changes.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
+ logger.debug("removePropertyChangeListener()");
changes.removePropertyChangeListener(l);
}
public void addRemotePropertyChangeListener(PropertyChangeListener l) {
+ logger.debug("addRemotePropertyChangeListener()");
remoteChanges.addPropertyChangeListener(l);
}
public void removeRemotePropertyChangeListener(PropertyChangeListener l){
+ logger.debug("removeRemotePropertyChangeListener()");
remoteChanges.removePropertyChangeListener(l);
}
}
diff --git a/src/model/nodes/Attribute.java b/src/model/nodes/Attribute.java
new file mode 100644
index 0000000..0f3722b
--- /dev/null
+++ b/src/model/nodes/Attribute.java
@@ -0,0 +1,13 @@
+package model.nodes;
+
+import util.GlobalVariables;
+
+public class Attribute extends IdentifiedTextField {
+
+ public Attribute(String text) {
+ super(text);
+ setPromptText(GlobalVariables.getString("typeIt")
+ + ": - " + GlobalVariables.getString("name")
+ + " : " + GlobalVariables.getString("type"));
+ }
+}
diff --git a/src/model/nodes/ClassNode.java b/src/model/nodes/ClassNode.java
index b0e246e..537ed15 100644
--- a/src/model/nodes/ClassNode.java
+++ b/src/model/nodes/ClassNode.java
@@ -1,58 +1,286 @@
package model.nodes;
import util.Constants;
+import util.GlobalVariables;
+import weka.core.AdditionalMeasureProducer;
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Represents a UML class.
*/
public class ClassNode extends AbstractNode implements Serializable
{
+ private static final Logger logger = LoggerFactory.getLogger(ClassNode.class);
private static final String TYPE = "CLASS";
- private String attributes;
- private String operations;
+ private List attributes = new ArrayList<>();
+ private List operations = new ArrayList<>();
public ClassNode(double x, double y, double width, double height)
{
super(x, y, width, height );
+ logger.debug("ClassNode()");
+
//Don't accept nodes with size less than minWidth * minHeight.
this.width = width < CLASS_MIN_WIDTH ? CLASS_MIN_WIDTH : width;
this.height = height < CLASS_MIN_HEIGHT ? CLASS_MIN_HEIGHT : height;
}
+
+ private int indexOfAttribute(Attribute newValue) {
+ int cont = 0;
+ for(String oldValueStr: attributes) {
+ Attribute oldValue = new Attribute("");
+ oldValue.toString(oldValueStr);
+ if (oldValue.getXmiId().equals(newValue.getXmiId())) {
+ return cont;
+ }
+ cont++;
+ }
+ return -1;
+ }
+ private int indexOfOperation(Operation newValue) {
+ int cont = 0;
+ for(String oldValueStr: operations) {
+ Operation oldValue = new Operation("");
+ oldValue.toString(oldValueStr);
+ if (oldValue.getXmiId().equals(newValue.getXmiId())) {
+ return cont;
+ }
+ cont++;
+ }
+ return -1;
+ }
- public void setAttributes(String pAttributes){
- attributes = pAttributes;
- changes.firePropertyChange(Constants.changeClassNodeAttributes, null, attributes);
- remoteChanges.firePropertyChange(Constants.changeClassNodeAttributes, null, attributes);
+ public void setAttributesStr(List pAttributes) {
+ logger.debug("setAttributes(List)");
+ attributes = pAttributes;
+ }
+
+ public void setAttributes(List pAttributes) {
+ logger.debug("setAttributes(List)");
+ attributes.clear();
+ for(Attribute attribute: pAttributes) {
+ attributes.add(attribute.toString());
+ }
+ }
+
+ private void removeAttribute(Attribute newValue) {
+ if (newValue != null) {
+ for(String oldValueStr: attributes) {
+ Attribute oldValue = new Attribute("");
+ oldValue.toString(oldValueStr);
+ if (oldValue.getXmiId().equals(newValue.getXmiId())) {
+ attributes.remove(oldValueStr);
+ break;
+ }
+ }
+ }
}
- public void setOperations(String pOperations){
- operations = pOperations;
- changes.firePropertyChange(Constants.changeClassNodeOperations, null, operations);
- remoteChanges.firePropertyChange(Constants.changeClassNodeOperations, null, operations);
+ private void removeOperation(Operation newValue) {
+ for(String oldValueStr: operations) {
+ Operation oldValue = new Operation("");
+ oldValue.toString(oldValueStr);
+ if (oldValue.getXmiId().equals(newValue.getXmiId())) {
+ operations.remove(oldValueStr);
+ break;
+ }
+ }
+ }
+
+ public void setAttributeOnly(int index, Attribute newValue){
+ logger.debug("setAttributeOnly()");
+ if (index == -1) {
+ removeAttribute(newValue);
+ } else {
+ boolean found = false;
+ for(String oldValueStr: attributes) {
+ Attribute oldValue = new Attribute("");
+ oldValue.toString(oldValueStr);
+ if (oldValue.getXmiId().equals(newValue.getXmiId())) {
+ found = true;
+ attributes.remove(oldValueStr);
+ try {
+ attributes.add(index, newValue.toString());
+ } catch(Exception e) {
+ attributes.add(newValue.toString());
+ }
+ break;
+ }
+ }
+ if (!found) {
+ try {
+ attributes.add(index, newValue.toString());
+ } catch(Exception e) {
+ attributes.add(newValue.toString());
+ }
+ }
+ }
+ }
+
+
+ public void setAttribute(int index, Attribute newValue, boolean transmit, String collaborationType){
+ logger.debug("setAttribute()");
+ setAttributeOnly(index, newValue);
+ String newValueStr;
+ if (index == -1) {
+ newValueStr = index + "|" + newValue;
+ } else {
+ newValueStr = indexOfAttribute(newValue) + "|" + newValue;
+ }
+
+ changes.firePropertyChange(Constants.changeClassNodeAttribute, null, newValueStr);
+
+ if (collaborationType.equals(Constants.collaborationTypeSynchronous)
+ || transmit ) {
+ remoteChanges.firePropertyChange(Constants.changeClassNodeAttribute, null, newValueStr);
+ }
+ }
+
+ public void setOperationsStr(List pOperation) {
+ logger.debug("setOperations(List)");
+ operations = pOperation;
+ }
+
+ public void setOperations(List pOperation) {
+ logger.debug("setOperations(List)");
+ operations.clear();
+ for(Operation operation: pOperation) {
+ operations.add(operation.toString());
+ }
+ }
+
+ public void setOperationOnly(int index, Operation newValue){
+ logger.debug("setOperationOnly()");
+ if (index == -1) {
+ removeOperation(newValue);
+ } else {
+ boolean found = false;
+ for(String oldValueStr: operations) {
+ Operation oldValue = new Operation("");
+ oldValue.toString(oldValueStr);
+ if (oldValue.getXmiId().equals(newValue.getXmiId())) {
+ found = true;
+ operations.remove(oldValueStr);
+ try {
+ operations.add(index, newValue.toString());
+ } catch(Exception e) {
+ operations.add(newValue.toString());
+ }
+ break;
+ }
+ }
+ if (!found) {
+ try {
+ operations.add(index, newValue.toString());
+ } catch(Exception e) {
+ operations.add(newValue.toString());
+ }
+ }
+ }
+ }
+
+ public void setOperation(int index, Operation newValue, boolean transmit, String collaborationType){
+ logger.debug("setOperation()");
+ if (operations == null) {
+ operations = new ArrayList<>();
+ }
+ setOperationOnly(index, newValue);
+ String newValueStr;
+ if (index == -1) {
+ newValueStr = index + "|" + newValue;
+ } else {
+ newValueStr = indexOfOperation(newValue) + "|" + newValue;
+ }
+
+ changes.firePropertyChange(Constants.changeClassNodeOperation, null, newValueStr);
+
+ if (collaborationType.equals(Constants.collaborationTypeSynchronous)
+ || transmit) {
+ remoteChanges.firePropertyChange(Constants.changeClassNodeOperation, null, newValueStr);
+ }
}
- public void remoteSetAttributes(String pAttributes){
- attributes = pAttributes;
- changes.firePropertyChange(Constants.changeClassNodeAttributes, null, attributes);
+ public void remoteSetAttribute(String[] dataArray, String collaborationType) {
+ logger.debug("remoteSetAttributes()");
+ if (collaborationType.equals(Constants.collaborationTypeSynchronous)) {
+ String newValueStr = (String) dataArray[2];
+ int index = Integer.parseInt(newValueStr.substring(0, newValueStr.indexOf("|")));
+ Attribute newValue = new Attribute("");
+ newValue.toString(newValueStr.substring(newValueStr.indexOf("|")+1));
+ for(String oldValueStr: attributes) {
+ Attribute oldValue = new Attribute("");
+ oldValue.toString(oldValueStr);
+ if (oldValue.getXmiId().equals(newValue.getXmiId())) {
+ attributes.remove(oldValueStr);
+ try {
+ attributes.add(index, newValue.toString());
+ } catch(Exception e) {
+ attributes.add(newValue.toString());
+ }
+ break;
+ }
+ }
+ }
+ changes.firePropertyChange(Constants.changeClassNodeAttribute, null, dataArray);
}
- public void remoteSetOperations(String pOperations){
- operations = pOperations;
- changes.firePropertyChange(Constants.changeClassNodeOperations, null, operations);
+ public void remoteSetOperation(Object[] dataArray, String collaborationType){
+ logger.debug("remoteSetOperations()");
+ if (collaborationType.equals(Constants.collaborationTypeSynchronous)) {
+ String newValueStr = (String) dataArray[2];
+ int index = Integer.parseInt(newValueStr.substring(0, newValueStr.indexOf("|")));
+ Operation newValue = new Operation("");
+ newValue.toString(newValueStr.substring(newValueStr.indexOf("|")+1));
+ for(String oldValueStr: operations) {
+ Operation oldValue = new Operation("");
+ oldValue.toString(oldValueStr);
+ if (oldValue.getXmiId().equals(newValue.getXmiId())) {
+ operations.remove(oldValueStr);
+ try {
+ operations.add(index, newValue.toString());
+ } catch(Exception e) {
+ operations.add(newValue.toString());
+ }
+ break;
+ }
+ }
+ }
+ changes.firePropertyChange(Constants.changeClassNodeOperation, null, dataArray);
}
- public String getAttributes(){
- return attributes;
+ public List getAttributes(){
+ List list = new ArrayList<>();
+ if (attributes != null) {
+ for (String string: attributes) {
+ Attribute attribute = new Attribute("");
+ attribute.toString(string);
+ list.add(attribute);
+ }
+ }
+ return list;
}
- public String getOperations(){
- return operations;
+ public List getOperations(){
+ List list = new ArrayList<>();
+ if (operations != null) {
+ for (String string: operations) {
+ Operation operation = new Operation("");
+ operation.toString(string);
+ list.add(operation);
+ }
+ }
+ return list;
}
@Override
public ClassNode copy(){
+ logger.debug("copy()");
ClassNode newCopy = new ClassNode(this.getX(), this.getY(), this.getWidth(), this.getHeight());
newCopy.setTranslateX(this.getTranslateX());
newCopy.setTranslateY(this.getTranslateY());
@@ -60,14 +288,14 @@ public ClassNode copy(){
newCopy.setScaleY(this.getScaleY());
if(this.getTitle() != null){
- newCopy.setTitle(this.getTitle());
+ newCopy.setTitle(this.getTitle(),false, null);
}
if(this.attributes != null){
- newCopy.setAttributes(this.attributes);
+ newCopy.setAttributesStr(this.attributes);
}
if(this.operations != null){
- newCopy.setOperations(operations);
+ newCopy.setOperationsStr(this.operations);
}
newCopy.setTranslateX(this.getTranslateX());
newCopy.setTranslateY(this.getTranslateY());
@@ -76,24 +304,28 @@ public ClassNode copy(){
@Override
public void setHeight(double height) {
+ logger.debug("setHeight()");
this.height = height < CLASS_MIN_HEIGHT ? CLASS_MIN_HEIGHT : height;
super.setHeight(height);
}
@Override
public void setWidth(double width) {
+ logger.debug("setWidth()");
this.width = width < CLASS_MIN_WIDTH ? CLASS_MIN_WIDTH : width;
super.setWidth(width);
}
@Override
public void remoteSetHeight(double height) {
+ logger.debug("remoteSetHeight()");
this.height = height < CLASS_MIN_HEIGHT ? CLASS_MIN_HEIGHT : height;
super.remoteSetHeight(height);
}
@Override
public void remoteSetWidth(double width) {
+ logger.debug("remoteSetWidth()");
this.width = width < CLASS_MIN_WIDTH ? CLASS_MIN_WIDTH : width;
super.remoteSetWidth(width);
}
@@ -102,9 +334,11 @@ public void remoteSetWidth(double width) {
* No-arg constructor for JavaBean convention
*/
public ClassNode(){
+ logger.debug("ClassNode()");
}
public String getType(){
+ logger.debug("getType()");
return TYPE;
}
}
diff --git a/src/model/nodes/IdentifiedTextField.java b/src/model/nodes/IdentifiedTextField.java
new file mode 100644
index 0000000..62ae476
--- /dev/null
+++ b/src/model/nodes/IdentifiedTextField.java
@@ -0,0 +1,94 @@
+package model.nodes;
+
+import javafx.geometry.Insets;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.layout.CornerRadii;
+import javafx.scene.paint.Color;
+import javafx.scene.text.Font;
+
+public class IdentifiedTextField extends TextField {
+
+ public static final String SEPARATOR = "|";
+
+ private String xmiId;
+
+ public IdentifiedTextField(String text) {
+ int index;
+
+ if (!text.isEmpty()) {
+ // Remove index of VBox
+ index = text.indexOf(";");
+ if (index != -1) {
+ text = text.substring(index+1);
+ }
+ // Split xmiId and text
+ index = text.indexOf(SEPARATOR);
+ if (index != -1) {
+ xmiId = text.substring(0, index);
+ setText(text.substring(index+1));
+ } else {
+ setText(text);
+ }
+ }
+ BackgroundFill backgroundFill = new BackgroundFill(Color.LIGHTSKYBLUE, CornerRadii.EMPTY, Insets.EMPTY);
+ Background background = new Background(backgroundFill);
+ setPadding(new Insets(0));
+ setBackground(background);
+ setFont(Font.font("Verdana", 10));
+ setStyle("-fx-prompt-text-fill: white");
+ }
+
+ public String getXmiId() {
+ return xmiId;
+ }
+
+ public void setXmiId(String xmiId) {
+ this.xmiId = xmiId;
+ }
+
+ // Make UUIDs short for log purposes
+ private String getShortXmiId() {
+ String leftside, rightside;
+
+ if (xmiId.contains("-")) {
+ leftside = xmiId.substring(0, xmiId.indexOf("-")-4);
+ rightside = xmiId.substring(xmiId.indexOf("-")+24);
+ } else {
+ return xmiId;
+ }
+ return leftside + ".." + rightside;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof IdentifiedTextField) {
+ IdentifiedTextField aux = (IdentifiedTextField) obj;
+ if (xmiId != null) {
+ if (xmiId.equals(aux.getXmiId()) && getText().equals(aux.getText())) {
+ return true;
+ }
+ } else {
+ if (getText().equals(aux.getText())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public String toStringShort() {
+ return getShortXmiId() + SEPARATOR + getText();
+ }
+
+ public String toString() {
+ return getXmiId() + "|" + getText();
+ }
+
+ public IdentifiedTextField toString(String value) {
+ setXmiId(value.substring(0, value.indexOf("|")));
+ setText(value.substring(value.indexOf("|")+1));
+ return this;
+ }
+}
diff --git a/src/model/nodes/Node.java b/src/model/nodes/Node.java
index 91f30e5..cabad67 100644
--- a/src/model/nodes/Node.java
+++ b/src/model/nodes/Node.java
@@ -26,7 +26,7 @@ public interface Node extends GraphElement {
String getTitle();
- void setTitle(String title);
+ void setTitle(String title, boolean transmit, String collaborationType);
String getType();
}
diff --git a/src/model/nodes/Operation.java b/src/model/nodes/Operation.java
new file mode 100644
index 0000000..c6b265c
--- /dev/null
+++ b/src/model/nodes/Operation.java
@@ -0,0 +1,14 @@
+package model.nodes;
+
+import util.GlobalVariables;
+
+public class Operation extends IdentifiedTextField {
+
+ public Operation(String text) {
+ super(text);
+ setPromptText(GlobalVariables.getString("typeIt")
+ + ": + " + GlobalVariables.getString("name")
+ + "(" + GlobalVariables.getString("arguments") + ")"
+ + " : " + GlobalVariables.getString("type"));
+ }
+}
diff --git a/src/model/nodes/PackageNode.java b/src/model/nodes/PackageNode.java
index 98cb897..222d3a0 100644
--- a/src/model/nodes/PackageNode.java
+++ b/src/model/nodes/PackageNode.java
@@ -85,7 +85,7 @@ public PackageNode copy(){
newCopy.setScaleY(this.getScaleY());
if(this.getTitle() != null){
- newCopy.setTitle(this.getTitle());
+ newCopy.setTitle(this.getTitle(), false, null);
}
/*if(this.getChildNodes() != null){
diff --git a/src/model/nodes/Title.java b/src/model/nodes/Title.java
new file mode 100644
index 0000000..9d710e6
--- /dev/null
+++ b/src/model/nodes/Title.java
@@ -0,0 +1,16 @@
+package model.nodes;
+
+import javafx.scene.control.TextField;
+
+public class Title extends TextField {
+
+ private String setPreviousTitle;
+
+ public String getSetPreviousTitle() {
+ return setPreviousTitle;
+ }
+
+ public void setSetPreviousTitle(String setPreviousTitle) {
+ this.setPreviousTitle = setPreviousTitle;
+ }
+}
diff --git a/src/resources/messages.properties b/src/resources/messages.properties
new file mode 100644
index 0000000..527649e
--- /dev/null
+++ b/src/resources/messages.properties
@@ -0,0 +1,53 @@
+accept=Accept
+accepted=Accepted
+addAttribute=Add Attribute
+addOperation=Add Operation
+and=and
+arguments=arguments
+argumentsModifiedTo=argument(s)
+by=by
+clearAll=Clear all
+clientMode=Client mode
+clients=clients
+collaborationType=Collaboration type
+connectToServerTitle=Connect to server
+connectToServerHeaderText=Enter server IP and port number and user name
+conflict=Conflict(s)
+deleteAttribute=Delete attribute
+deleteOperation=Delete operation
+discardedRemoteVersionMatchsLocalVersion=Discarded (remote version matchs local version)
+elementDeleted=element deleted
+historic=History
+in=in
+launchServerTitle=Launch Server
+launchServerHeaderText=Enter server port, collaboration type and, optional, a user name
+localChangesNotSented=LOCAL CHANGES NOT SENTED!
+localChangesSented=Local changes sented
+remoteUpdateConfictsWithLocalDelete=remote update conficts with local delete
+merged=Merged
+movedDown=moved down
+moveDown=Move down
+movedUp=moved up
+moveUp=Move up
+name=name
+nameModifiedTo=name
+newElement=newElement
+port=Port
+positions=position(s)
+reject=Reject
+rejected=Rejected
+returnTypeModifiedTo=return type
+sendFailed=Send Failed
+sentedSuccessfully=Sented Successfully
+server=Server
+serverMode=Server mode
+synchronous=Synchronous
+user=User
+userName=User name
+updatedTo=updated to
+type:type
+typeIt:Type it
+typeModifiedTo=type
+withoutLocalChanges=Without local changes to send
+visibilityModifiedTo=visibility
+umlcollab=UMLCollab
\ No newline at end of file
diff --git a/src/resources/messages_es_ES.properties b/src/resources/messages_es_ES.properties
new file mode 100644
index 0000000..b9dbcc5
--- /dev/null
+++ b/src/resources/messages_es_ES.properties
@@ -0,0 +1,53 @@
+accept=Aceptar
+accepted=Aceptado
+addAttribute=Agregar atributo
+addOperation=Agregar operación
+and=y
+arguments=argumentos
+argumentsModifiedTo=argumento(s)
+by=por
+clearAll=Borrar todo
+clientMode=Modo cliente
+clients=clientes
+collaborationType=Tipo de colaboración
+connectToServerTitle=Conexión al servidor
+connectToServerHeaderText=Introduzca el número de IP y el puerto del servidor y su nombre
+conflict=Conflicto(s)
+deleteAttribute=Eliminar atributo
+deleteOperation=Eliminar operación
+discardedRemoteVersionMatchsLocalVersion=Descartado (versión remota corresponde a la versión local)
+elementDeleted=elemento eliminado
+historic=Histórico
+in=en
+launchServerTitle=Configuración del modo servidor
+launchServerHeaderText=Introduzca el puerto del servidor, el tipo de colaboración y, opcionalmente, un nombre de usuario
+localChangesNotSented=CAMBIOS LOCALES NO ENVIADAS!
+localChangesSented=Cambios locales enviados
+remoteUpdateConfictsWithLocalDelete=remoción remota en conflicto con cambio local
+merged=Merge
+movedDown=movido hacia abajo
+moveDown=Abajo
+movedUp=movido hacia arriba
+moveUp=Hasta
+name=nombre
+nameModifiedTo=nombre
+newElement=nuevo elemento
+port=Puerto
+positions=posición(s)
+reject=Rechazar
+rejected=Rechazadas
+returnTypeModifiedTo=tipo de retorno
+sendFailed=Error de envío
+sentedSuccessfully=Envío con éxito
+server=Servidor
+serverMode=Modo servidor
+synchronous=Sincrónico
+user=Usuário
+userName=Nombre de usuario
+updatedTo=actualizado para
+type:tipo
+typeIt:Introduzca
+typeModifiedTo=tipo
+withoutLocalChanges=No hay cambios locales a enviar
+visibilityModifiedTo=visibilidad
+umlcollab=UMLCollab
diff --git a/src/resources/messages_pt_BR.properties b/src/resources/messages_pt_BR.properties
new file mode 100644
index 0000000..74e7f0f
--- /dev/null
+++ b/src/resources/messages_pt_BR.properties
@@ -0,0 +1,53 @@
+accept=Aceitar
+accepted=Aceito
+addAttribute=Adicionar atributo
+addOperation=Adicionar operação
+and=e
+arguments=argumentos
+argumentsModifiedTo=argumento(s)
+by=por
+clearAll=Limpar tudo
+clientMode=Modo cliente
+clients=clientes
+collaborationType=Tipo de colaboração
+connectToServerTitle=Conexão ao servidor
+connectToServerHeaderText=Informe o número do IP e porta do servidor e o seu nome
+conflict=Conflito(s)
+deleteAttribute=Remover atributo
+deleteOperation=Remover operação
+discardedRemoteVersionMatchsLocalVersion=Descartado (versão remota corresponde à versão local)
+elementDeleted=elemento removido
+historic=Histórico
+in=em
+launchServerTitle=Configuração do modo servidor
+launchServerHeaderText=Informe a porta do servidor, tipo de colaboração e, opcionalmente, um nome de usuário
+localChangesNotSented=ALTERAÇÕES LOCAIS NÃO ENVIADAS!
+localChangesSented=Alterações locais enviadas
+remoteUpdateConfictsWithLocalDelete=remoção remota conflita com alteração local
+merged=Merge
+movedDown=movido para baixo
+moveDown=Descer
+movedUp=movido para cima
+moveUp=Subir
+name=nome
+nameModifiedTo=nome
+newElement=novo elemento
+port=Porta
+positions=posição(ões)
+reject=Rejeitar
+rejected=Rejeitado
+returnTypeModifiedTo=tipo de retorno
+sendFailed=Falha no envio
+sentedSuccessfully=Envio com sucesso
+server=Servidor
+serverMode=Modo servidor
+synchronous=Síncrono
+user=Usuário
+userName=Nome do usuário
+updatedTo=atualizado para
+type:tipo
+typeIt:Digite
+typeModifiedTo=tipo
+withoutLocalChanges=Sem alterações locais a enviar
+visibilityModifiedTo=visibilidade
+umlcollab=UMLCollab
diff --git a/src/util/Change.java b/src/util/Change.java
new file mode 100644
index 0000000..90a1f38
--- /dev/null
+++ b/src/util/Change.java
@@ -0,0 +1,39 @@
+package util;
+
+public class Change {
+
+ // Constants
+ public static String delete = "delete";
+ public static String remoteUpdateWithLocalDelete = "remoteUpdateWithLocalDelete";
+ public static String newElement = "newElement";
+
+ public static String visibility = "visibility";
+ public static String name = "name";
+ public static String arguments = "arguments";
+ public static String type = "type";
+ public static String moved = "moved";
+
+ private String changeType;
+ private Object change;
+
+ public Change(String changeType, Object change) {
+ this.changeType = changeType;
+ this.change = change;
+ }
+
+ public String getChangeType() {
+ return changeType;
+ }
+
+ public void setChangeType(String changeType) {
+ this.changeType = changeType;
+ }
+
+ public Object getChange() {
+ return change;
+ }
+
+ public void setChange(Object change) {
+ this.change = change;
+ }
+}
diff --git a/src/util/Constants.java b/src/util/Constants.java
index 16b3435..3964dd1 100644
--- a/src/util/Constants.java
+++ b/src/util/Constants.java
@@ -12,9 +12,12 @@ public class Constants {
public static int GRID_DISTANCE = 20;
+ public static String collaborationTypeSynchronous = "synchronous";
+ public static String collaborationTypeUMLCollab = "umlcollab";
//--------------------- Network Constants -----------------------------------
public static String requestGraph = "RequestGraph";
+ public static String changeCollaborationType = "ChangeCollaborationType";
public static String NodeAdd = "NodeAdd";
public static String NodeRemove = "NodeRemove";
public static String EdgeAdd = "EdgeAdd";
@@ -31,8 +34,8 @@ public class Constants {
public static String changeNodeScaleX = "NodeScaleX";
public static String changeNodeScaleY = "NodeScaleY";
public static String changeNodeTitle = "NodeTitle";
- public static String changeClassNodeAttributes = "ClassNodeAttributes";
- public static String changeClassNodeOperations = "ClassNodeOperations";
+ public static String changeClassNodeAttribute = "ClassNodeAttributes";
+ public static String changeClassNodeOperation = "ClassNodeOperations";
public static String changeNodeIsChild = "ClassNodeIsChild";
public static String changeLifelineLength = "LifelineLength";
diff --git a/src/util/GlobalVariables.java b/src/util/GlobalVariables.java
new file mode 100644
index 0000000..dd61b98
--- /dev/null
+++ b/src/util/GlobalVariables.java
@@ -0,0 +1,36 @@
+package util;
+
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+public class GlobalVariables {
+
+ private static Locale locale = Locale.getDefault();
+ private static ResourceBundle bundle = ResourceBundle.getBundle("resources/messages", locale);
+
+ public static Locale getLocale() {
+ return locale;
+ }
+
+ public static void setLocale(Locale locale) {
+ GlobalVariables.locale = locale;
+ }
+
+ public static String getString(String key) {
+ return bundle.getString(key);
+ }
+
+ public static String getKey(String value) {
+ String result = "";
+ Enumeration keys = bundle.getKeys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ String aux = bundle.getString(key);
+ if (aux.equals(value)) {
+ result = key;
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/util/NetworkUtils.java b/src/util/NetworkUtils.java
index f056b2c..3215a34 100644
--- a/src/util/NetworkUtils.java
+++ b/src/util/NetworkUtils.java
@@ -2,6 +2,7 @@
import controller.ClientController;
import javafx.application.Platform;
+import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
@@ -15,11 +16,11 @@
*/
public class NetworkUtils {
- public static String[] queryServerPort() {
+ public static String[] clientConfigDialog() {
// Create the custom dialog.
- Dialog> dialog = new Dialog<>();
- dialog.setTitle("Connect to server");
- dialog.setHeaderText("Enter server IP and port number");
+ Dialog dialog = new Dialog<>();
+ dialog.setTitle(GlobalVariables.getString("connectToServerTitle"));
+ dialog.setHeaderText(GlobalVariables.getString("connectToServerHeaderText"));
ButtonType okButtonType = new ButtonType("Ok", ButtonBar.ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().addAll(okButtonType, ButtonType.CANCEL);
@@ -29,34 +30,111 @@ public static String[] queryServerPort() {
grid.setVgap(10);
grid.setPadding(new Insets(20, 150, 10, 10));
- TextField serverIP = new TextField();
- serverIP.setText("127.0.0.1");
+ TextField ip = new TextField();
+ ip.setText("127.0.0.1");
TextField port = new TextField();
port.setText("54555");
+ TextField userName = new TextField();
+ userName.setText(System.getProperty("user.name"));
- Platform.runLater(() -> serverIP.requestFocus());
+ Platform.runLater(() -> ip.requestFocus());
- grid.add(new Label("Server IP:"), 0, 0);
- grid.add(serverIP, 1, 0);
- grid.add(new Label("Port number:"), 0, 1);
+ grid.add(new Label("IP:"), 0, 0);
+ grid.add(ip, 1, 0);
+ grid.add(new Label(GlobalVariables.getString("port")+":"), 0, 1);
grid.add(port, 1, 1);
+ grid.add(new Label(GlobalVariables.getString("userName")+":"), 0, 2);
+ grid.add(userName, 1, 2);
dialog.getDialogPane().setContent(grid);
// Convert the result to a username-password-pair when the login button is clicked.
dialog.setResultConverter(dialogButton -> {
if (dialogButton == okButtonType) {
- return new Pair<>(serverIP.getText(), port.getText());
+ return new String[] {
+ ip.getText(), port.getText(), userName.getText()
+ };
}
return null;
});
- Optional> result = dialog.showAndWait();
+ Optional result = dialog.showAndWait();
- String[] s = new String[2];
- if (result.isPresent() && validateIP(result.get().getKey()) && Integer.parseInt(result.get().getValue()) >= 1024 && Integer.parseInt(result.get().getValue()) <= 65535) {
- s[0] = result.get().getKey();
- s[1] = result.get().getValue();
+ String[] s = new String[3];
+ if (result.isPresent()
+ && validateIP(result.get()[0])
+ && Integer.parseInt(result.get()[1]) >= 1024
+ && Integer.parseInt(result.get()[1]) <= 65535
+ && !(result.get()[2].isEmpty())) {
+ s[0] = result.get()[0];
+ s[1] = result.get()[1];
+ s[2] = result.get()[2];
+ } else {
+ s = null;
+ Alert alert = new Alert(Alert.AlertType.WARNING);
+ alert.setTitle("Invalid input");
+ alert.setHeaderText("Invalip input. \nClosing diagram.");
+ alert.showAndWait();
+ }
+ return s;
+ }
+
+ public static String[] ServerConfigDialog() {
+ // Create the custom dialog.
+ Dialog dialog = new Dialog<>();
+ dialog.setTitle(GlobalVariables.getString("launchServerTitle"));
+ dialog.setHeaderText(GlobalVariables.getString("launchServerHeaderText"));
+
+ ButtonType okButtonType = new ButtonType("Ok", ButtonBar.ButtonData.OK_DONE);
+ dialog.getDialogPane().getButtonTypes().addAll(okButtonType, ButtonType.CANCEL);
+
+ GridPane grid = new GridPane();
+ grid.setHgap(10);
+ grid.setVgap(10);
+ grid.setPadding(new Insets(20, 150, 10, 10));
+
+ TextField port = new TextField();
+ port.setText("54555");
+ ChoiceBox collaborationType = new ChoiceBox(FXCollections.observableArrayList(
+ GlobalVariables.getString("synchronous"), "UMLCollab")
+ );
+ collaborationType.setValue(GlobalVariables.getString("synchronous"));
+
+ TextField userName = new TextField();
+ userName.setText(GlobalVariables.getString("server"));
+
+ Platform.runLater(() -> collaborationType.requestFocus());
+
+ grid.add(new Label(GlobalVariables.getString("port") + ":"), 0, 0);
+ grid.add(port, 1, 0);
+ grid.add(new Label(GlobalVariables.getString("collaborationType") + ":"), 0, 1);
+ grid.add(collaborationType, 1, 1);
+ grid.add(new Label(GlobalVariables.getString("userName") + ":"), 0, 2);
+ grid.add(userName, 1, 2);
+ dialog.getDialogPane().setContent(grid);
+
+ // Convert the result to a username-password-pair when the login button is clicked.
+ dialog.setResultConverter(dialogButton -> {
+ if (dialogButton == okButtonType) {
+ return new String[] {
+ port.getText(),
+ (String) collaborationType.getSelectionModel().getSelectedItem(),
+ userName.getText()
+ };
+ }
+ return null;
+ });
+ Optional result = dialog.showAndWait();
+
+ String[] s = new String[3];
+ if (result.isPresent()
+ && Integer.parseInt(result.get()[0]) >= 1024
+ && Integer.parseInt(result.get()[0]) <= 65535
+ && !(result.get()[1].isEmpty())
+ && !(result.get()[2].isEmpty())) {
+ s[0] = result.get()[0];
+ s[1] = result.get()[1];
+ s[2] = result.get()[2];
} else {
s = null;
Alert alert = new Alert(Alert.AlertType.WARNING);
@@ -67,6 +145,57 @@ public static String[] queryServerPort() {
return s;
}
+ public static String[] changeCollaborationTypeDialog() {
+ // Create the custom dialog.
+ Dialog dialog = new Dialog<>();
+ dialog.setTitle("Change collaboration type");
+ dialog.setHeaderText("Warning: All clients models with be descarted and replaced for server model");
+
+ ButtonType okButtonType = new ButtonType("Ok", ButtonBar.ButtonData.OK_DONE);
+ dialog.getDialogPane().getButtonTypes().addAll(okButtonType, ButtonType.CANCEL);
+
+ GridPane grid = new GridPane();
+ grid.setHgap(10);
+ grid.setVgap(10);
+ grid.setPadding(new Insets(20, 150, 10, 10));
+
+ ChoiceBox collaborationType = new ChoiceBox(FXCollections.observableArrayList(
+ "Synchronous", "UMLCollab")
+ );
+ collaborationType.setValue("Synchronous");
+
+ Platform.runLater(() -> collaborationType.requestFocus());
+
+ grid.add(new Label("Collaboration type:"), 0, 1);
+ grid.add(collaborationType, 1, 1);
+ dialog.getDialogPane().setContent(grid);
+
+ // Convert the result to a username-password-pair when the login button is clicked.
+ dialog.setResultConverter(dialogButton -> {
+ if (dialogButton == okButtonType) {
+ return new String[] {
+ (String) collaborationType.getSelectionModel().getSelectedItem()
+ };
+ }
+ return null;
+ });
+
+ Optional result = dialog.showAndWait();
+
+ String[] s = new String[3];
+ if (result.isPresent()
+ && !(result.get()[0].isEmpty())) {
+ s[0] = result.get()[0];
+ } else {
+ s = null;
+ Alert alert = new Alert(Alert.AlertType.WARNING);
+ alert.setTitle("Invalid input");
+ alert.setHeaderText("Invalip input. \nClosing diagram.");
+ alert.showAndWait();
+ }
+ return s;
+ }
+
//Regex for IPv4-pattern, found: http://stackoverflow.com/questions/5667371/validate-ipv4-address-in-java
private static final Pattern PATTERN = Pattern.compile(
"^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
diff --git a/src/util/commands/SetNodeAttributeCommand.java b/src/util/commands/SetNodeAttributeCommand.java
index a4014f1..e751460 100644
--- a/src/util/commands/SetNodeAttributeCommand.java
+++ b/src/util/commands/SetNodeAttributeCommand.java
@@ -3,15 +3,19 @@
import model.nodes.ClassNode;
import model.nodes.Node;
+import java.util.List;
+
+import model.nodes.Attribute;
+
/**
* Created by chalmers on 2016-08-29.
*/
public class SetNodeAttributeCommand implements Command {
private ClassNode node;
- private String newAttribute;
- private String oldAttribute;
+ private List newAttribute;
+ private List oldAttribute;
- public SetNodeAttributeCommand(ClassNode pNode, String pNewAttribute, String pOldAttribute){
+ public SetNodeAttributeCommand(ClassNode pNode, List pNewAttribute, List pOldAttribute){
node = pNode;
newAttribute = pNewAttribute;
oldAttribute = pOldAttribute;
@@ -31,11 +35,11 @@ public Node getNode() {
return node;
}
- public String getNewAttribute() {
+ public List getNewAttribute() {
return newAttribute;
}
- public String getOldAttribute() {
+ public List getOldAttribute() {
return oldAttribute;
}
}
diff --git a/src/util/commands/SetNodeOperationsCommand.java b/src/util/commands/SetNodeOperationsCommand.java
index d47145e..ee92acf 100644
--- a/src/util/commands/SetNodeOperationsCommand.java
+++ b/src/util/commands/SetNodeOperationsCommand.java
@@ -1,17 +1,20 @@
package util.commands;
+import java.util.List;
+
import model.nodes.ClassNode;
import model.nodes.Node;
+import model.nodes.Operation;
/**
* Created by chalmers on 2016-08-29.
*/
public class SetNodeOperationsCommand implements Command {
private ClassNode node;
- private String newOperations;
- private String oldOperations;
+ private List newOperations;
+ private List oldOperations;
- public SetNodeOperationsCommand(ClassNode pNode, String pNewOperations, String pOldOperations){
+ public SetNodeOperationsCommand(ClassNode pNode, List pNewOperations, List pOldOperations){
node = pNode;
newOperations = pNewOperations;
oldOperations = pOldOperations;
@@ -31,11 +34,11 @@ public Node getNode() {
return node;
}
- public String getNewOperations() {
+ public List getNewOperations() {
return newOperations;
}
- public String getOldOperations() {
+ public List getOldOperations() {
return oldOperations;
}
}
diff --git a/src/util/commands/SetNodeTitleCommand.java b/src/util/commands/SetNodeTitleCommand.java
index 175bef1..7ff8a8a 100644
--- a/src/util/commands/SetNodeTitleCommand.java
+++ b/src/util/commands/SetNodeTitleCommand.java
@@ -19,12 +19,12 @@ public SetNodeTitleCommand(Node pNode, String pNewTitle, String pOldTitle){
@Override
public void undo() {
- node.setTitle(oldTitle);
+ node.setTitle(oldTitle,false, null);
}
@Override
public void execute() {
- node.setTitle(newTitle);
+ node.setTitle(newTitle,false,null);
}
public Node getNode() {
diff --git a/src/util/persistence/PersistenceManager.java b/src/util/persistence/PersistenceManager.java
index 35e0b5d..2d63c75 100644
--- a/src/util/persistence/PersistenceManager.java
+++ b/src/util/persistence/PersistenceManager.java
@@ -1,30 +1,44 @@
package util.persistence;
import javafx.scene.shape.LineTo;
+
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathElement;
import model.*;
import model.edges.*;
import model.nodes.AbstractNode;
+import model.nodes.Attribute;
import model.nodes.ClassNode;
+import model.nodes.IdentifiedTextField;
+import model.nodes.Operation;
import model.nodes.PackageNode;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
import java.io.*;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.UUID;
/**
* Class with static methods for importing and exporting xmi models.
@@ -39,9 +53,11 @@ public static void exportXMI(Graph pGraph, String path){
DOMSource source = new DOMSource(createXmi(pGraph));
StreamResult result = new StreamResult(new File(path));
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.transform(source, result);
} catch (TransformerException tfe) {
- tfe.printStackTrace();
+ tfe.printStackTrace();
}
}
@@ -149,9 +165,10 @@ public static Document createXmi(Graph pGraph){
Element associationConnection = doc.createElement("UML:Association.connection");
umlAssociation.appendChild(associationConnection);
-
- addAssociatonEnd(edge.getStartNode().getId(), associationConnection, doc, "true");
- addAssociatonEnd(edge.getEndNode().getId(), associationConnection, doc, "false");
+
+ AbstractEdge abstractEdge = (AbstractEdge) edge;
+ addAssociatonEnd(edge.getStartNode().getId(), abstractEdge.getStartMultiplicity(), associationConnection, doc, "true");
+ addAssociatonEnd(edge.getEndNode().getId(), abstractEdge.getEndMultiplicity(), associationConnection, doc, "false");
umlNamespace.appendChild(umlAssociation);
@@ -194,6 +211,7 @@ public static Document createXmi(Graph pGraph){
}
private static void addClassNode(Document doc, ClassNode node, Element parent, Graph pGraph, boolean isChild){
+ IdentifiedTextField textField;
Element umlClass = doc.createElement("UML:Class");
if(isChild){
umlClass.setAttribute("namespace", ((Element)parent.getParentNode()).getAttribute("xmi.id"));
@@ -205,30 +223,44 @@ private static void addClassNode(Document doc, ClassNode node, Element parent, G
Element classifierFeature = doc.createElement("UML:Classifier.feature");
umlClass.appendChild(classifierFeature);
- int attIdCount = 0;
- int opIdCount = 0;
if(node.getAttributes() != null){
- String attributes[] = node.getAttributes().split("\\r?\\n");
- for(String att : attributes){
- Element attribute = doc.createElement("UML:Attribute");
- attribute.setAttribute("name", att);
- attribute.setAttribute("xmi.id", "att" + ++attIdCount + "_" + node.getId());
- classifierFeature.appendChild(attribute);
+ for(Attribute tf : node.getAttributes()){
+ Element element = doc.createElement("UML:Attribute");
+ element.setAttribute("name", tf.getText());
+ if (tf.getXmiId().contains("-")) {
+ if (tf.getXmiId().contains("_")) {
+ // Remove old id node suffix
+ element.setAttribute("xmi.id", tf.getXmiId().substring(0,tf.getXmiId().indexOf("_")));
+ } else {
+ element.setAttribute("xmi.id", tf.getXmiId());
+ }
+ } else {
+ element.setAttribute("xmi.id", "att" + UUID.randomUUID().toString());
+ }
+ classifierFeature.appendChild(element);
}
}
if(node.getOperations() != null){
- String operations[] = node.getOperations().split("\\r?\\n");
- for(String op : operations) {
- Element operation = doc.createElement("UML:Operation");
- operation.setAttribute("name", op);
- operation.setAttribute("xmi.id", "oper" + ++opIdCount + "_" + node.getId());
- classifierFeature.appendChild(operation);
+ for(Operation tf : node.getOperations()){
+ Element element = doc.createElement("UML:Operation");
+ element.setAttribute("name", tf.getText());
+ if (tf.getXmiId().contains("-")) {
+ if (tf.getXmiId().contains("_")) {
+ // Remove old id node suffix
+ element.setAttribute("xmi.id", tf.getXmiId().substring(0,tf.getXmiId().indexOf("_")));
+ } else {
+ element.setAttribute("xmi.id", tf.getXmiId());
+ }
+ } else {
+ element.setAttribute("xmi.id", "oper" + UUID.randomUUID().toString());
+ }
+ classifierFeature.appendChild(element);
}
}
parent.appendChild(umlClass);
}
-
- private static void addAssociatonEnd(String nodeId, Element association, Document doc, String isStart){
+
+ private static void addAssociatonEnd(String nodeId, String multiplicityRange, Element association, Document doc, String isStart){
Element associationEnd = doc.createElement("UML:AssociationEnd");
associationEnd.setAttribute("xmi.id", "end0");
associationEnd.setAttribute("type", nodeId);
@@ -241,8 +273,19 @@ private static void addAssociatonEnd(String nodeId, Element association, Documen
Element multiplicityRange1 = doc.createElement("UML:Multiplicity.range");
multiplicity1.appendChild(multiplicityRange1);
Element multiplicityRange11 = doc.createElement("UML:MultiplicityRange");
- multiplicityRange11.setAttribute("upper", ""); //TODO
- multiplicityRange11.setAttribute("lower", "");
+ // Split multiplicityRange string into upper and lower attributes and add to element.
+ if (multiplicityRange != null) {
+ if (multiplicityRange.contains(".")) {
+ multiplicityRange11.setAttribute("lower", multiplicityRange.substring(0, multiplicityRange.indexOf(".")));
+ multiplicityRange11.setAttribute("upper", multiplicityRange.substring(multiplicityRange.lastIndexOf(".")+1));
+ } else {
+ multiplicityRange11.setAttribute("lower", multiplicityRange); // TODO: Is correct set to lower?
+ multiplicityRange11.setAttribute("upper", "");
+ }
+ } else {
+ multiplicityRange11.setAttribute("lower", "");
+ multiplicityRange11.setAttribute("upper", "");
+ }
multiplicityRange1.appendChild(multiplicityRange11);
association.appendChild(associationEnd);
}
@@ -259,6 +302,20 @@ public static Graph importXMIFromPath(String path){
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
+ // Remove indentation to avoid errors.
+ XPathFactory xfact = XPathFactory.newInstance();
+ XPath xpath = xfact.newXPath();
+ try {
+ NodeList empty =
+ (NodeList)xpath.evaluate("//text()[normalize-space(.) = '']",
+ doc, XPathConstants.NODESET);
+ for (int i = 0; i < empty.getLength(); i++) {
+ Node node = empty.item(i);
+ node.getParentNode().removeChild(node);
+ }
+ } catch (XPathExpressionException e) {
+ e.printStackTrace();
+ }
return importXMI(doc);
}
public static Graph importXMI(Document doc){
@@ -271,6 +328,7 @@ public static Graph importXMI(Document doc){
Element umlModel = ((Element)nList.item(0));
graph.setName(umlModel.getAttribute("name"));
String modelNamespace = umlModel.getAttribute("xmi.id");
+ graph.setId(Integer.parseInt(modelNamespace.substring(modelNamespace.indexOf("_")+1)));
//Import packages
nList = doc.getElementsByTagName("UML:Package");
@@ -282,6 +340,15 @@ public static Graph importXMI(Document doc){
if(viewElement.getAttribute("subject").equals(modelElement.getAttribute("xmi.id"))){
Boolean isChild = !modelElement.getAttribute("namespace").equals(modelNamespace);
AbstractNode node = createAbstractNode(viewElement, modelElement, isChild, true);
+ String id;
+ try {
+ // If id is a int type (for old files), replace for UUID
+ Integer.parseInt(modelElement.getAttribute("xmi.id").substring(modelElement.getAttribute("xmi.id").indexOf("_")+1));
+ id = UUID.randomUUID().toString();
+ } catch (Exception e) {
+ id = modelElement.getAttribute("xmi.id").substring(modelElement.getAttribute("xmi.id").indexOf("_")+1);
+ }
+ node.setId(id);
idMap.put(modelElement.getAttribute("xmi.id"), node);
graph.addNode(node, false);
}
@@ -298,6 +365,15 @@ public static Graph importXMI(Document doc){
if(viewElement.getAttribute("subject").equals(modelElement.getAttribute("xmi.id"))){
Boolean isChild = !modelElement.getAttribute("namespace").equals(modelNamespace);
AbstractNode node = createAbstractNode(viewElement, modelElement, isChild, false);
+ String id;
+ try {
+ // If id is a int type (for old files), replace for UUID
+ Integer.parseInt(modelElement.getAttribute("xmi.id").substring(modelElement.getAttribute("xmi.id").indexOf("_")+1));
+ id = UUID.randomUUID().toString();
+ } catch (Exception e) {
+ id = modelElement.getAttribute("xmi.id").substring(modelElement.getAttribute("xmi.id").indexOf("_")+1);
+ }
+ node.setId(id);
idMap.put(modelElement.getAttribute("xmi.id"), node);
graph.addNode(node, false);
}
@@ -329,12 +405,35 @@ public static Graph importXMI(Document doc){
} else { //Standard is Assocation
edge = new AssociationEdge(idMap.get(startNodeId), idMap.get(endNodeId));
}
+ // Recovering lower and upper multiplicity
+ NodeList nList2 = associationElement.getElementsByTagName("UML:AssociationEnd");
+ for(int i2 = 0; i2 < nList2.getLength(); i2++) {
+ Element associationEndElement = (Element) nList2.item(i2);
+ NodeList nList3 = associationEndElement.getElementsByTagName("UML:MultiplicityRange");
+ Element multiplicityRangeElement = (Element) nList3.item(0);
+ String multiplicityRange = multiplicityRangeElement.getAttribute("lower");
+ if (!multiplicityRangeElement.getAttribute("upper").isEmpty()) {
+ multiplicityRange = multiplicityRange + ".." + multiplicityRangeElement.getAttribute("upper");
+ }
+ String isStart = associationEndElement.getAttribute("isStart");
+ if (isStart.equals("true")){
+ edge.setStartMultiplicity(multiplicityRange);
+ } else {
+ edge.setEndMultiplicity(multiplicityRange);
+ }
+ }
graph.addEdge(edge, false);
+ String id;
+ try {
+ // If id is a int type (for old files), replace for UUID
+ Integer.parseInt(associationElement.getAttribute("xmi.id").substring(associationElement.getAttribute("xmi.id").indexOf("_")+1));
+ id = UUID.randomUUID().toString();
+ } catch (Exception e) {
+ id = associationElement.getAttribute("xmi.id").substring(associationElement.getAttribute("xmi.id").indexOf("_")+1);
+ }
+ edge.setId(id);
}
-
-
-
//Import sketches
nList = doc.getElementsByTagName("Sketch");
for(int i = 0; i < nList.getLength(); i++) {
@@ -365,29 +464,48 @@ private static AbstractNode createAbstractNode(Element view, Element model, bool
double y = Double.parseDouble(geometry[1]);
double width = Double.parseDouble(geometry[2]) - x;
double height = Double.parseDouble(geometry[3]) - y;
+ int attributesCont, operationsCont;
AbstractNode abstractNode;
if(!isPackage){
abstractNode = new ClassNode(x, y, width, height);
NodeList attsOps = model.getChildNodes().item(0).getChildNodes();
- String attributes = "";
- String operations = "";
+ List attributes = new ArrayList<>();
+ attributesCont = 0;
for(int i = 0; i < attsOps.getLength(); i++){
Element item = ((Element)attsOps.item(i));
+ String name = item.getAttribute("name");
+ String xmiId = item.getAttribute("xmi.id");
if(item.getNodeName().equals("UML:Attribute")){
- String att = item.getAttribute("name");
- attributes = attributes + att + System.getProperty("line.separator");
- } else if(item.getNodeName().equals("UML:Operation")){
- String op = item.getAttribute("name");
- operations = operations + op + System.getProperty("line.separator");
+ Attribute tf = new Attribute(name);
+ tf.setXmiId(xmiId);
+ attributes.add(tf);
+ attributesCont++;
+ }
+ }
+ if (attributesCont > 0) {
+ ((ClassNode)abstractNode).setAttributes(attributes);
+ }
+ List operations = new ArrayList<>();
+ operationsCont = 0;
+ for(int i = 0; i < attsOps.getLength(); i++){
+ Element item = ((Element)attsOps.item(i));
+ String name = item.getAttribute("name");
+ String xmiId = item.getAttribute("xmi.id");
+ if(item.getNodeName().equals("UML:Operation")){
+ Operation tf = new Operation(name);
+ tf.setXmiId(xmiId);
+ operations.add(tf);
+ operationsCont++;
}
}
- ((ClassNode)abstractNode).setAttributes(attributes);
- ((ClassNode)abstractNode).setOperations(operations);
+ if (operationsCont > 0) {
+ ((ClassNode)abstractNode).setOperations(operations);
+ }
} else {
abstractNode = new PackageNode(x, y, width, height);
}
- abstractNode.setTitle(model.getAttribute("name"));
+ abstractNode.setTitle(model.getAttribute("name"),false, null);
abstractNode.setIsChild(isChild);
return abstractNode;
diff --git a/src/view/fxml/classDiagramView.fxml b/src/view/fxml/classDiagramView.fxml
index 380d267..2736993 100644
--- a/src/view/fxml/classDiagramView.fxml
+++ b/src/view/fxml/classDiagramView.fxml
@@ -34,6 +34,9 @@
+
+
+
diff --git a/src/view/fxml/mainView.fxml b/src/view/fxml/mainView.fxml
index 6836b17..f452d75 100644
--- a/src/view/fxml/mainView.fxml
+++ b/src/view/fxml/mainView.fxml
@@ -19,10 +19,6 @@
-
-
-
-
@@ -45,6 +41,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/view/nodes/ClassNodeView.java b/src/view/nodes/ClassNodeView.java
index 7399a56..39157cc 100644
--- a/src/view/nodes/ClassNodeView.java
+++ b/src/view/nodes/ClassNodeView.java
@@ -1,10 +1,41 @@
package view.nodes;
+import java.beans.PropertyChangeEvent;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import controller.AbstractDiagramController;
+import controller.TabController;
+import javafx.application.Platform;
+import javafx.collections.ObservableList;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
-import javafx.scene.control.Label;
+import javafx.scene.Node;
+import javafx.scene.control.ContextMenu;
+import javafx.scene.control.Menu;
+import javafx.scene.control.MenuItem;
import javafx.scene.control.Separator;
+import javafx.scene.control.Tab;
+import javafx.scene.control.TextField;
+import javafx.scene.control.TextInputControl;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
@@ -13,24 +44,29 @@
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
+import model.nodes.Attribute;
import model.nodes.ClassNode;
+import model.nodes.IdentifiedTextField;
+import model.nodes.Operation;
+import model.nodes.Title;
import util.Constants;
-
-import java.beans.PropertyChangeEvent;
+import util.GlobalVariables;
+import util.Change;
/**
* Visual representation of ClassNode class.
*/
public class ClassNodeView extends AbstractNodeView implements NodeView {
-
- private Label title;
- private Label attributes;
- private Label operations;
-
+
+ private static Logger logger = LoggerFactory.getLogger(ClassNodeView.class);
+
+ private Map localChangedValues = new HashMap();
+ private Map localRemovedValues = new HashMap();
+ private Map> remoteChangedValues = new HashMap>();
+
private Rectangle rectangle;
private StackPane container;
- private StackPane titlePane;
private VBox vbox;
private Separator firstLine;
@@ -40,9 +76,19 @@ public class ClassNodeView extends AbstractNodeView implements NodeView {
private Line longHandleLine;
private final int STROKE_WIDTH = 1;
+
+ private Title title;
+
+ private AbstractDiagramController abstractDiagramController;
+
+ private boolean commited = true;
- public ClassNodeView(ClassNode node) {
- super(node);
+ public ClassNodeView(ClassNode node, AbstractDiagramController abstractDiagramController) {
+ super(node);
+ logger.debug("ClassNodeView()");
+
+ this.abstractDiagramController = abstractDiagramController;
+
//setChangeListeners();
container = new StackPane();
@@ -62,11 +108,10 @@ public ClassNodeView(ClassNode node) {
this.setTranslateX(node.getTranslateX());
this.setTranslateY(node.getTranslateY());
createHandles();
-
-
}
private void createRectangles(){
+ logger.debug("createRectangles()");
ClassNode node = (ClassNode) getRefNode();
changeHeight(node.getHeight());
changeWidth(node.getWidth());
@@ -75,11 +120,13 @@ private void createRectangles(){
}
private void changeHeight(double height){
+ logger.debug("changeHeight()");
setHeight(height);
rectangle.setHeight(height);
}
private void changeWidth(double width){
+ logger.debug("changeWidth()");
setWidth(width);
rectangle.setWidth(width);
container.setMaxWidth(width);
@@ -92,18 +139,19 @@ private void changeWidth(double width){
secondLine.setMaxWidth(width);
secondLine.setPrefWidth(width);
- title.setMaxWidth(width);
- title.setPrefWidth(width);
-
- attributes.setMaxWidth(width);
- attributes.setPrefWidth(width);
-
- operations.setMaxWidth(width);
- operations.setPrefWidth(width);
+ for(Node node: vbox.getChildren()) {
+ if (node instanceof Attribute
+ || node instanceof Operation
+ || node instanceof Title) {
+ TextField tf = (TextField) node;
+ tf.setMaxWidth(width);
+ tf.setPrefWidth(width);
+ }
+ }
}
private void createHandles(){
-
+ logger.debug("createHandles()");
shortHandleLine = new Line();
longHandleLine = new Line();
@@ -117,54 +165,112 @@ private void createHandles(){
longHandleLine.endYProperty().bind(rectangle.heightProperty().subtract(15));
this.getChildren().addAll(shortHandleLine, longHandleLine);
+
+ title.setOnKeyReleased(new EventHandler() {
+ public void handle(KeyEvent ke) {
+ ((ClassNode)getRefNode()).setTitle(title.getText(),false, abstractDiagramController.getCollaborationType());
+ }
+ });
+
+ for(Node node: vbox.getChildren()) {
+ if (node instanceof Attribute) {
+ createHandlesAttributesOperations((Attribute) node);
+ }
+ else if (node instanceof Operation) {
+ createHandlesAttributesOperations((Operation) node);
+ }
+ }
}
private void initVBox(){
+ logger.debug("initVBox()");
ClassNode node = (ClassNode) getRefNode();
vbox.setPadding(new Insets(5, 0, 5, 0));
vbox.setSpacing(5);
- titlePane = new StackPane();
-
firstLine = new Separator();
firstLine.setMaxWidth(node.getWidth());
secondLine = new Separator();
secondLine.setMaxWidth(node.getWidth());
- title = new Label();
+ title = new Title();
title.setFont(Font.font("Verdana", FontWeight.BOLD, 12));
if(node.getTitle() != null) {
title.setText(node.getTitle());
}
title.setAlignment(Pos.CENTER);
+
+ // Set add attribute and operation context menus
+ MenuItem cmItemAddAttribute;
+ cmItemAddAttribute = new MenuItem(GlobalVariables.getString("addAttribute"));
+ cmItemAddAttribute.setOnAction(event -> {
+ addAttribute();
+ });
+ MenuItem cmItemAddOperation;
+ cmItemAddOperation = new MenuItem(GlobalVariables.getString("addOperation"));
+ cmItemAddOperation.setOnAction(event -> {
+ addOperation();
+ });
+ ContextMenu contextMenu = new ContextMenu();
+ contextMenu.getItems().addAll(cmItemAddAttribute,cmItemAddOperation);
+ // Add context menu for collaboration type UMLCollab
+ Menu cmHistory = new Menu (GlobalVariables.getString("historic"));
+ // Add context menu item "Clear all"
+ MenuItem cmItemClearAll = new MenuItem(GlobalVariables.getString("clearAll"));
+ cmItemClearAll.setOnAction(event -> {
+ while (cmHistory.getItems().size() > 1) {
+ cmHistory.getItems().remove(cmHistory.getItems().get(1));
+ }
+ if (title.getContextMenu().getItems().size() == 3) {
+ title.setStyle("-fx-text-inner-color: black;");
+ }
+ });
+ cmHistory.getItems().add(cmItemClearAll);
+ contextMenu.getItems().addAll(cmHistory);
+ title.setContextMenu(contextMenu);
- attributes = new Label(node.getAttributes());
- attributes.setFont(Font.font("Verdana", 10));
+ vbox.getChildren().addAll(title, firstLine);
+
+ if (node.getAttributes() != null) {
+ Iterator i = node.getAttributes().iterator();
+ while (i.hasNext()) {
+ Attribute attribute = i.next();
+ vbox.getChildren().add(attribute);
+ }
+ }
- operations = new Label(node.getOperations());
- operations.setFont(Font.font("Verdana", 10));
+ vbox.getChildren().addAll(secondLine);
+ if (node.getOperations() != null) {
+ Iterator i = node.getOperations().iterator();
+ while (i.hasNext()) {
+ Operation operation = i.next();
+ vbox.getChildren().add(operation);
+ }
+ }
- if(operations.getText() == null || operations.getText().equals("")){
+ if (operationsSize() > 0) {
+ secondLine.setVisible(true);
+ } else {
secondLine.setVisible(false);
}
-
- titlePane.getChildren().add(title);
- vbox.getChildren().addAll(titlePane, firstLine, attributes, secondLine, operations);
}
private void initLooks(){
+ logger.debug("initLooks()");
rectangle.setStrokeWidth(STROKE_WIDTH);
rectangle.setFill(Color.LIGHTSKYBLUE);
rectangle.setStroke(Color.BLACK);
+ BackgroundFill backgroundFill = new BackgroundFill(Color.LIGHTSKYBLUE, CornerRadii.EMPTY, Insets.EMPTY);
+ Background background = new Background(backgroundFill);
StackPane.setAlignment(title, Pos.CENTER);
- VBox.setMargin(attributes, new Insets(5,0,0,5));
- VBox.setMargin(operations, new Insets(5,0,0,5));
+ title.setBackground(background);
}
public void setSelected(boolean selected){
+ logger.debug("setSelected()");
if(selected){
rectangle.setStrokeWidth(2);
setStroke(Constants.selected_color);
@@ -175,25 +281,1157 @@ public void setSelected(boolean selected){
}
public void setStrokeWidth(double scale){
+ logger.debug("setStrokeWidth()");
rectangle.setStrokeWidth(scale);
}
public void setFill(Paint p) {
+ logger.debug("setFill()");
rectangle.setFill(p);
}
public void setStroke(Paint p) {
+ logger.debug("setStroke()");
rectangle.setStroke(p);
}
public Bounds getBounds(){
return container.getBoundsInParent();
}
+
+ private int attributesSize() {
+ int cont = 0;
+ for(Node node: vbox.getChildren()) {
+ if (node instanceof Attribute) {
+ cont++;
+ }
+ }
+ return cont;
+ }
+
+ private List getAttributes() {
+ List list = new ArrayList<>();
+ for(Node node: vbox.getChildren()) {
+ if (node instanceof Attribute) {
+ list.add((Attribute)node);
+ }
+ }
+ return list;
+ }
+
+ private int operationsSize() {
+ int cont = 0;
+ for(Node node: vbox.getChildren()) {
+ if (node instanceof Operation) {
+ cont++;
+ }
+ }
+ return cont;
+ }
+ private List getOperations() {
+ List list = new ArrayList<>();
+ for(Node node: vbox.getChildren()) {
+ if (node instanceof Operation) {
+ list.add((Operation)node);
+ }
+ }
+ return list;
+ }
+
+ private int indexOf(IdentifiedTextField tf) {
+ if (tf instanceof Attribute) {
+ return vbox.getChildren().indexOf(tf)-2;
+ } else if (tf instanceof Operation) {
+ return vbox.getChildren().indexOf(tf)-3-attributesSize();
+ }
+ return -1;
+ }
+
+ private void addAttributeOperationToVbox(int index, IdentifiedTextField newValue) {
+ if (newValue instanceof Attribute) {
+ index = index + 2;
+ if (index > 2 + attributesSize() || index < 2) {
+ index = 2 + attributesSize();
+ }
+ vbox.getChildren().add(index,newValue);
+ } else if (newValue instanceof Operation) {
+ index = index + 3 + attributesSize();
+ if (index > 3 + attributesSize() + operationsSize() || index < 3 + attributesSize() ) {
+ index = 3 + attributesSize() + operationsSize();
+ }
+ vbox.getChildren().add(index,newValue);
+ }
+ }
+
+ private void createHandlesAttributesOperations(IdentifiedTextField textfield) {
+ logger.debug("createHandlesAttributesOperations()");
+ textfield.setOnKeyReleased(new EventHandler() {
+ public void handle(KeyEvent ke) {
+ if (textfield instanceof Attribute) {
+ ((ClassNode)getRefNode()).setAttribute(indexOf(textfield), (Attribute)textfield, false, abstractDiagramController.getCollaborationType());
+ } else if (textfield instanceof Operation) {
+ ((ClassNode)getRefNode()).setOperation(indexOf(textfield), (Operation)textfield, false, abstractDiagramController.getCollaborationType());
+ }
+ }
+ });
+
+ MenuItem cmItemMoveUp;
+ cmItemMoveUp = new MenuItem(GlobalVariables.getString("moveUp"));
+ cmItemMoveUp.setUserData(textfield);
+ cmItemMoveUp.setOnAction(new EventHandler() {
+ public void handle(ActionEvent e) {
+ IdentifiedTextField modifiedTextField = (IdentifiedTextField) ((MenuItem) e.getSource()).getUserData();
+ int index = vbox.getChildren().indexOf(modifiedTextField);
+ if (modifiedTextField instanceof Attribute && index > 2) {
+ index--;
+ Attribute tf = (Attribute) modifiedTextField;
+ vbox.getChildren().remove(tf);
+ vbox.getChildren().add(index,tf);
+ ((ClassNode)getRefNode()).setAttribute(indexOf(tf), tf, false, abstractDiagramController.getCollaborationType());
+ } else if (textfield instanceof Operation && index > (3+attributesSize())) {
+ index--;
+ Operation tf = (Operation) modifiedTextField;
+ vbox.getChildren().remove(tf);
+ vbox.getChildren().add(index,tf);
+ ((ClassNode)getRefNode()).setOperation(indexOf(tf), tf, false, abstractDiagramController.getCollaborationType());
+ }
+ }
+ });
+ MenuItem cmItemMoveDown;
+ cmItemMoveDown = new MenuItem(GlobalVariables.getString("moveDown"));
+ cmItemMoveDown.setUserData(textfield);
+ cmItemMoveDown.setOnAction(new EventHandler() {
+ public void handle(ActionEvent e) {
+ IdentifiedTextField modifiedTextField = (IdentifiedTextField) ((MenuItem) e.getSource()).getUserData();
+ int index = vbox.getChildren().indexOf(modifiedTextField);
+ if (textfield instanceof Attribute && index < (1+attributesSize())) {
+ index++;
+ Attribute tf = (Attribute) textfield;
+ vbox.getChildren().remove(tf);
+ vbox.getChildren().add(index,tf);
+ ((ClassNode)getRefNode()).setAttribute(indexOf(tf), tf, false, abstractDiagramController.getCollaborationType());
+ } else if (textfield instanceof Operation && index < (2+attributesSize()+operationsSize())) {
+ index++;
+ Operation tf = (Operation) textfield;
+ vbox.getChildren().remove(tf);
+ vbox.getChildren().add(index,tf);
+ ((ClassNode)getRefNode()).setOperation(indexOf(tf), tf, false, abstractDiagramController.getCollaborationType());
+ }
+ }
+ });
+ MenuItem cmItemDelete;
+ if (textfield instanceof Attribute) {
+ cmItemDelete = new MenuItem(GlobalVariables.getString("deleteAttribute"));
+ } else {
+ cmItemDelete = new MenuItem(GlobalVariables.getString("deleteOperation"));
+ }
+ cmItemDelete.setUserData(textfield);
+ cmItemDelete.setOnAction(new EventHandler() {
+ public void handle(ActionEvent e) {
+ IdentifiedTextField modifiedTextField = (IdentifiedTextField) ((MenuItem) e.getSource()).getUserData();
+ vbox.getChildren().remove(modifiedTextField);
+ if (modifiedTextField instanceof Attribute) {
+ Attribute tf = (Attribute) modifiedTextField;
+ ((ClassNode)getRefNode()).setAttribute(-1,tf, false, abstractDiagramController.getCollaborationType());
+ } else {
+ Operation tf = (Operation) modifiedTextField;
+ ((ClassNode)getRefNode()).setOperation(-1,tf, false, abstractDiagramController.getCollaborationType());
+ if (operationsSize() > 0) {
+ secondLine.setVisible(true);
+ } else {
+ secondLine.setVisible(false);
+ }
+ }
+ }
+ });
+
+ ContextMenu contextMenu = new ContextMenu();
+ contextMenu.getItems().addAll(cmItemMoveUp,cmItemMoveDown,cmItemDelete);
+ // Add context menu for collaboration type UMLCollab
+ Menu cmHistory = new Menu (GlobalVariables.getString("historic"));
+ // Add context menu item "Clear all"
+ MenuItem cmItemClearAll = new MenuItem(GlobalVariables.getString("clearAll"));
+ cmItemClearAll.setOnAction(event -> {
+ while (cmHistory.getItems().size() > 1) {
+ cmHistory.getItems().remove(cmHistory.getItems().get(1));
+ }
+ if (textfield.getContextMenu().getItems().size() == 4) {
+ textfield.setStyle("-fx-text-inner-color: black;");
+ }
+ });
+ cmHistory.getItems().add(cmItemClearAll);
+ contextMenu.getItems().addAll(cmHistory);
+ textfield.setContextMenu(contextMenu);
+ }
+
+ public void addAttribute() {
+ logger.debug("addAttribute()");
+ Attribute textField = new Attribute("");
+ textField.setXmiId("att" + UUID.randomUUID().toString());
+ createHandlesAttributesOperations(textField);
+ vbox.getChildren().add(attributesSize()+2,textField);
+ ((ClassNode)getRefNode()).setAttribute(indexOf(textField),textField, false, abstractDiagramController.getCollaborationType());
+ }
+
+ public void addOperation() {
+ logger.debug("addOperation()");
+ Operation textField = new Operation("");
+ textField.setXmiId("oper" + UUID.randomUUID().toString());
+ createHandlesAttributesOperations(textField);
+ vbox.getChildren().add(attributesSize()+operationsSize()+3,textField);
+ ((ClassNode)getRefNode()).setOperation(indexOf(textField),textField, false, abstractDiagramController.getCollaborationType());
+ secondLine.setVisible(true);
+ }
+
+ private Menu getHistoryMenu (TextField textField) {
+ // Record conflict decision to history
+ if (textField.getContextMenu() != null) {
+ ObservableList list = textField.getContextMenu().getItems();
+ for (int i = 0; i < list.size(); i++) {
+ if (list.get(i).getText().equals(GlobalVariables.getString("historic"))) {
+ return (Menu) list.get(i);
+ }
+ }
+ }
+ return null;
+ }
+
+ private String getDateTimeUserSuffixString(String userName) {
+ Date currentDate = new Date();
+ String dateTimeUserSuffixString = "(" + GlobalVariables.getString("by") + " " + userName +
+ " " + GlobalVariables.getString("in") + " " + new SimpleDateFormat("dd/MM/yy HH:mm:ss").format(currentDate) + ")";
+ return dateTimeUserSuffixString;
+ }
+
+ private String replaceAttributeOperationSubElement(Object obj, int index, String subElement) {
+ List list;
+ String value;
+ if (obj instanceof Attribute) {
+ list = split((Attribute) obj);
+ } else {
+ list = split((Operation) obj);
+ }
+ list.remove(index);
+ list.add(index, subElement);
+
+ // Adding visibility, name and arguments/type
+ value = list.get(0) + list.get(1) + list.get(2);
+ // Adding return type
+ if (obj instanceof Operation) {
+ value = value + list.get(3);
+ }
+ return value;
+ }
+
+ private List split(Attribute element) {
+ String aux = element.getText().trim();
+ String visibility = "", name = "", returnType = "";
+ List list = new ArrayList<>();
+
+ // Remove duplicate spaces before compare.
+ while (aux.contains(" ")) {
+ aux = aux.replace(" ", " ");
+ }
+
+ //Get visibility;
+ if (aux.contains("-")) {
+ if ( (aux.indexOf("-")+1) < aux.length() ) {
+ for(int i = aux.indexOf("-")+1; i < aux.length(); i++) {
+ if (!aux.substring(i, i+1).equals(" ")) {
+ visibility = aux.substring(0,i);
+ aux = aux.substring(i);
+ break;
+ }
+ }
+ } else {
+ visibility = aux;
+ aux = "";
+ }
+ } else if (aux.contains("+")) {
+ if ( (aux.indexOf("+")+1) < aux.length() ) {
+ for(int i = aux.indexOf("+")+1; i < aux.length(); i++) {
+ if (!aux.substring(i, i+1).equals(" ")) {
+ visibility = aux.substring(0,i);
+ aux = aux.substring(i);
+ break;
+ }
+ }
+ } else {
+ visibility = aux;
+ aux = "";
+ }
+ }
+ list.add(visibility);
+
+ //Get name and return type;
+ if (aux.contains(":")) {
+ name = aux.substring(0, aux.indexOf(":"));
+ returnType = aux.substring(aux.indexOf(":"));
+ } else {
+ name = aux;
+ returnType = "";
+ }
+ list.add(name);
+ list.add(returnType);
+ return list;
+ }
+
+ private List split(Operation element) {
+ String aux = element.getText().trim();
+ String visibility = "", name = "", arguments = "", returnType = "";
+ List list = new ArrayList<>();
+
+ // Remove duplicate spaces before compare.
+ while (aux.contains(" ")) {
+ aux = aux.replace(" ", " ");
+ }
+ //Get visibility
+ if (aux.contains("-")) {
+ if ( (aux.indexOf("-")+1) < aux.length() ) {
+ for(int i = aux.indexOf("-")+1; i < aux.length(); i++) {
+ if (!aux.substring(i, i+1).equals(" ")) {
+ visibility = aux.substring(0,i);
+ aux = aux.substring(i);
+ break;
+ }
+ }
+ } else {
+ visibility = aux;
+ aux = "";
+ }
+ } else if (aux.contains("+")) {
+ if ( (aux.indexOf("+")+1) < aux.length() ) {
+ for(int i = aux.indexOf("+")+1; i < aux.length(); i++) {
+ if (!aux.substring(i, i+1).equals(" ")) {
+ visibility = aux.substring(0,i);
+ aux = aux.substring(i);
+ break;
+ }
+ }
+ } else {
+ visibility = aux;
+ aux = "";
+ }
+ }
+ list.add(visibility);
+
+ //Get name
+ if (aux.contains("(")) {
+ name = aux.substring(0, aux.indexOf("("));
+ aux = aux.substring(aux.indexOf("("));
+ } else if (aux.contains(":")) {
+ name = aux.substring(0, aux.indexOf(":"));
+ aux = aux.substring(aux.indexOf(":"));
+ } else {
+ name = aux;
+ aux = "";
+ }
+ list.add(name);
+
+ //Get arguments
+ if ( aux.contains("(") ) {
+ if ( aux.contains(")") ) {
+ arguments = aux.substring(aux.indexOf("("), aux.indexOf(")")+1);
+ if ( (aux.indexOf(")")+1) < aux.length() ) {
+ returnType = aux.substring(aux.indexOf(")")+1);
+ }
+ } else {
+ arguments = aux.substring(aux.indexOf("("));
+ }
+ } else {
+ arguments = "";
+ returnType = aux;
+ }
+ list.add(arguments);
+ list.add(returnType);
+ return list;
+ }
+
+ private String extractNameFromAttributeOperation(IdentifiedTextField element) {
+ List list;
+ if (element instanceof Attribute) {
+ list = split((Attribute)element);
+ } else {
+ list = split((Operation)element);
+ }
+ return list.get(1).trim();
+ }
+
+ private IdentifiedTextField getAttributeOperation(IdentifiedTextField oldValue) {
+ // Get by xmiId
+ for (int i = 0; i < vbox.getChildren().size(); i++) {
+ Node node = vbox.getChildren().get(i);
+ if ( node instanceof Attribute || node instanceof Operation ) {
+ IdentifiedTextField tf = (IdentifiedTextField) node;
+ if (tf.getXmiId().equals(oldValue.getXmiId())) {
+ return tf;
+ }
+ }
+ }
+ // Get by name
+ for (int i = 0; i < vbox.getChildren().size(); i++) {
+ Node node = vbox.getChildren().get(i);
+ if ( node instanceof Attribute || node instanceof Operation ) {
+ IdentifiedTextField tf = (IdentifiedTextField) node;
+ if (extractNameFromAttributeOperation(tf)
+ .equals(extractNameFromAttributeOperation(oldValue))) {
+ return tf;
+ }
+ }
+ }
+ return null;
+ }
+
+ public boolean isCommited() {
+ return commited;
+ }
+
+ private void setCommited(boolean salvo) {
+ // Update tab name
+ commited = salvo;
+ Set keys = TabController.getTabMap().keySet();
+ for (Tab tab: keys)
+ {
+ AbstractDiagramController value = TabController.getTabMap().get(tab);
+ if (value == abstractDiagramController) {
+ String graphName = abstractDiagramController.getGraphModel().getName();
+ if (salvo) {
+ Platform.runLater(() -> tab.setText(graphName));
+ } else {
+ Platform.runLater(() -> tab.setText(graphName + " (" + GlobalVariables.getString("localChangesNotSented") + ")" ));
+ }
+ }
+ }
+ }
+
+ public boolean elementUpdated(PropertyChangeEvent evt, int index, TextField oldValue, TextField newValue) {
+ logger.debug("elementUpdated()");
+ // Remove duplicate spaces and trim() before compare.
+ String oldValueStr = "", newValueStr = "";
+ if (oldValue != null) {
+ oldValueStr = oldValue.getText().trim();
+ while (oldValueStr.contains(" ")) {
+ oldValueStr = oldValueStr.replace(" ", " ");
+ }
+ }
+ // Get new value text
+ if (newValue != null) {
+ newValueStr = newValue.getText();
+ }
+ // If it is a title
+ if (newValue instanceof Title) {
+ // Compare old value with new value
+ if ( !oldValueStr.equals(newValueStr) ) {
+ return true;
+ }
+ }
+ // It is a attribute or operation
+ else {
+ // It is a deleted value
+ if (index == -1) {
+ return true;
+ }
+ // Special case when received a attribute or operation that was deleted locally
+ else if (index == -2) {
+ return true;
+ }
+ // It is a new or updated value
+ else {
+ // It is a new value
+ if (oldValue == null) {
+ return true;
+ }
+ // Is it a updated value?
+ else {
+ // Update text if it was altered
+ if ( !oldValueStr.equals(newValueStr) ) {
+ return true;
+ }
+ // If moved upper or down
+ if ( indexOf(((IdentifiedTextField)oldValue)) != index ) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public String getUpdateTypeString(PropertyChangeEvent evt, int index,
+ Object oldValue, Object newValue, String id, String remoteUserName) {
+ logger.debug("elementUpdated()");
+ List updateTypeStringList = new ArrayList();
+ ArrayList remoteChangeList = new ArrayList<>();
+ String updateTypeString = "";
+ // Remove duplicate spaces and trim() before compare.
+ String oldValueStr = "";
+ if (oldValue != null) {
+ oldValueStr = ((TextField)oldValue).getText().trim();
+ while (oldValueStr.contains(" ")) {
+ oldValueStr = oldValueStr.replace(" ", " ");
+ }
+ }
+ // If it is a title
+ if (evt.getPropertyName().equals(Constants.changeNodeTitle)) {
+ if (!oldValueStr.equals(((TextField)newValue).getText()) ) {
+ updateTypeStringList.add(GlobalVariables.getString("updatedTo") +
+ " '" + ((TextField)newValue).getText() + "'");
+ remoteChangeList.add(new Change(Change.name, ((TextField)newValue).getText()));
+ }
+ }
+ // It is a attribute or operation
+ else {
+ // It is a deleted value
+ if (index == -1) {
+ updateTypeStringList.add(GlobalVariables.getString("elementDeleted"));
+ remoteChangeList.add(new Change(Change.delete, null));
+ }
+ // Special case when received a attribute or operation that was deleted locally
+ else if (index == -2) {
+ updateTypeStringList.add(GlobalVariables.getString("remoteUpdateConfictsWithLocalDelete"));
+ remoteChangeList.add(new Change(Change.remoteUpdateWithLocalDelete, newValue));
+ }
+ // It is a new or updated value
+ else {
+ // It is a new value
+ if (oldValue == null) {
+ updateTypeStringList.add(GlobalVariables.getString("newElement"));
+ Object[] dataArray = {index, newValue};
+ remoteChangeList.add(new Change(Change.newElement, dataArray));
+ }
+ // It is a updated value
+ else {
+ // Update text if it was altered
+ if (!oldValueStr.equals(((TextField)newValue).getText())) {
+ List oldValueList;
+ List newValueList;
+ if (oldValue instanceof Attribute) {
+ oldValueList = split((Attribute)oldValue);
+ newValueList = split((Attribute)newValue);
+ } else {
+ oldValueList = split((Operation)oldValue);
+ newValueList = split((Operation)newValue);
+ }
+ if ( !oldValueList.get(0).equals(newValueList.get(0)) ) {
+ updateTypeStringList.add( GlobalVariables.getString("visibilityModifiedTo") +
+ " '" + newValueList.get(0) + "'" );
+ remoteChangeList.add(new Change(Change.visibility, newValueList.get(0)));
+ }
+ if ( !oldValueList.get(1).equals(newValueList.get(1)) ) {
+ updateTypeStringList.add( GlobalVariables.getString("nameModifiedTo") +
+ " '" + newValueList.get(1) + "'" );
+ remoteChangeList.add(new Change(Change.name, newValueList.get(1)));
+ }
+ if (oldValue instanceof Attribute) {
+ if ( !oldValueList.get(2).equals(newValueList.get(2)) ) {
+ updateTypeStringList.add( GlobalVariables.getString("typeModifiedTo") +
+ " '" + newValueList.get(2) + "'" );
+ remoteChangeList.add(new Change(Change.type, newValueList.get(2)));
+ }
+ } else {
+ if ( !oldValueList.get(2).equals(newValueList.get(2)) ) {
+ updateTypeStringList.add( GlobalVariables.getString("argumentsModifiedTo") +
+ " '" + newValueList.get(2) + "'" );
+ remoteChangeList.add(new Change(Change.arguments, newValueList.get(2)));
+ }
+ if ( !oldValueList.get(3).equals(newValueList.get(3)) ) {
+ updateTypeStringList.add( GlobalVariables.getString("returnTypeModifiedTo") +
+ " '" + newValueList.get(3) + "'" );
+ remoteChangeList.add(new Change(Change.type, newValueList.get(3)));
+ }
+ }
+ }
+ // If moved upper or down
+ if (indexOf(((IdentifiedTextField)oldValue)) != index) {
+ if (indexOf(((IdentifiedTextField)oldValue)) < index) {
+ updateTypeStringList.add(GlobalVariables.getString("movedDown") +
+ " " + (index-indexOf(((IdentifiedTextField)oldValue))) +
+ " " + GlobalVariables.getString("positions") );
+ } else if (indexOf(((IdentifiedTextField)oldValue)) > index) {
+ updateTypeStringList.add( GlobalVariables.getString("movedUp") +
+ " " + (indexOf(((IdentifiedTextField)oldValue))-index) +
+ " " + GlobalVariables.getString("positions") );
+ }
+ remoteChangeList.add(new Change(Change.moved, index));
+ }
+ }
+ }
+ }
+
+ if (updateTypeStringList.size() > 0) {
+ updateTypeString = updateTypeStringList.get(0);
+ for(int cont = 1; cont < updateTypeStringList.size()-1; cont++) {
+ updateTypeString = updateTypeString + ", " + updateTypeStringList.get(cont);
+ }
+ if (updateTypeStringList.size() > 1) {
+ updateTypeString = updateTypeString + " " + GlobalVariables.getString("and") + " " +
+ updateTypeStringList.get(updateTypeStringList.size()-1);
+ }
+ remoteChangedValues.put(id + "|" + remoteUserName, remoteChangeList);
+ } else {
+ logger.warn("No update string found.");
+ }
+ return updateTypeString;
+ }
+
+ public boolean updateTextField(PropertyChangeEvent evt, int index, Object oldValue, Object newValue) {
+ logger.debug("updateAttributeOperation()");
+ boolean updated = false;
+ if (evt.getPropertyName().equals(Constants.changeNodeTitle)) {
+ if (!((TextField)oldValue).getText().equals(((TextField)newValue).getText()) ) {
+ ((TextField)oldValue).setText(((TextField)newValue).getText());
+ updated = true;
+ logger.debug("old value updated");
+ }
+ } else {
+ // It is a deleted value
+ if (index == -1 || index == -2 || oldValue == null) {
+ if (index == -1) {
+ vbox.getChildren().remove(oldValue);
+ updated = true;
+ logger.debug("old removed");
+ }
+ // Special case when received a attribute or operation that was deleted locally and now rejected
+ else if (index == -2) {
+ vbox.getChildren().remove(newValue);
+ updated = true;
+ logger.debug("new value removed");
+ }
+ // It is a new value
+ else if (oldValue == null) {
+ createHandlesAttributesOperations(((IdentifiedTextField)newValue));
+ addAttributeOperationToVbox(index,((IdentifiedTextField)newValue));
+ updated = true;
+ logger.debug("new value created");
+ }
+ if (evt.getPropertyName().equals(Constants.changeClassNodeOperation)) {
+ if (operationsSize() > 0) {
+ secondLine.setVisible(true);
+ } else {
+ secondLine.setVisible(false);
+ }
+ }
+ }
+ // It is a updated value
+ else {
+ // Update text if it was altered
+ if (!((TextField)oldValue).getText().equals(((TextField)newValue).getText())) {
+ ((TextField)oldValue).setText(((TextField)newValue).getText());
+ updated = true;
+ logger.debug("old value updated");
+ }
+ // If moved up or down
+ if (indexOf(((IdentifiedTextField)oldValue)) != index) {
+ vbox.getChildren().remove(oldValue);
+ addAttributeOperationToVbox(index,(IdentifiedTextField)oldValue);
+ updated = true;
+ logger.debug("old value moved up or down");
+ }
+ }
+ }
+ return updated;
+ }
+
+ public boolean updateTextField(PropertyChangeEvent evt, TextField oldValue, String id, String remoteUserName) {
+ logger.debug("updateAttributeOperation()");
+ boolean updated = false;
+ List remoteChangesList = remoteChangedValues.get(id + "|" + remoteUserName);
+ if (remoteChangesList != null || remoteChangesList.size() > 0) {
+ if (evt.getPropertyName().equals(Constants.changeNodeTitle)) {
+ oldValue.setText((String)remoteChangesList.get(0).getChange());
+ updated = true;
+ } else {
+ // It is a deleted value
+ if (remoteChangesList.get(0).getChangeType().equals(Change.delete)) {
+ vbox.getChildren().remove(oldValue);
+ updated = true;
+ }
+ // Special case when received a attribute or operation that was deleted locally and now rejected
+ else if (remoteChangesList.get(0).getChangeType().equals(Change.remoteUpdateWithLocalDelete)) {
+ vbox.getChildren().remove(remoteChangesList.get(0).getChange());
+ updated = true;
+ logger.debug("new value removed");
+ }
+ // It is a new value
+ else if (remoteChangesList.get(0).getChangeType().equals(Change.newElement)) {
+ Object[] dataArray = (Object[]) remoteChangesList.get(0).getChange();
+ createHandlesAttributesOperations((IdentifiedTextField) dataArray[1]);
+ addAttributeOperationToVbox((int) dataArray[0], (IdentifiedTextField) dataArray[1]);
+ updated = true;
+ logger.debug("new value created");
+ }
+ // It is a updated value
+ else {
+ for(Change change: remoteChangesList) {
+ // Update text if it was altered
+ if ( change.getChangeType().equals(Change.visibility) ) {
+ ((TextField)oldValue).setText( replaceAttributeOperationSubElement(oldValue, 0, (String)change.getChange()) );
+ updated = true;
+ }
+ else if ( change.getChangeType().equals(Change.name) ) {
+ ((TextField)oldValue).setText( replaceAttributeOperationSubElement(oldValue, 1, (String)change.getChange()) );
+ updated = true;
+ }
+ else if ( change.getChangeType().equals(Change.arguments) ) {
+ ((TextField)oldValue).setText( replaceAttributeOperationSubElement(oldValue, 2, (String)change.getChange()) );
+ updated = true;
+ }
+ else if ( change.getChangeType().equals(Change.type) ) {
+ if (evt.getPropertyName().equals(Constants.changeClassNodeAttribute)) {
+ ((TextField)oldValue).setText( replaceAttributeOperationSubElement(oldValue, 2, (String)change.getChange()) );
+ } else {
+ ((TextField)oldValue).setText( replaceAttributeOperationSubElement(oldValue, 3, (String)change.getChange()) );
+ }
+ updated = true;
+ }
+ else if ( change.getChangeType().equals(Change.moved) &&
+ (indexOf(((IdentifiedTextField)oldValue)) != ((int)change.getChange())) ) {
+ vbox.getChildren().remove(oldValue);
+ addAttributeOperationToVbox((int)change.getChange(),(IdentifiedTextField)oldValue);
+ updated = true;
+ }
+ }
+ }
+ if (evt.getPropertyName().equals(Constants.changeClassNodeOperation)) {
+ if (operationsSize() > 0) {
+ secondLine.setVisible(true);
+ } else {
+ secondLine.setVisible(false);
+ }
+ }
+ }
+ }
+ return updated;
+ }
+
+ public boolean updateModel(PropertyChangeEvent evt, int index, Object oldValue, Object newValue) {
+ logger.debug("notifyModel()");
+ boolean updated = false;
+ if (evt.getPropertyName().equals(Constants.changeNodeTitle)) {
+ ((ClassNode)getRefNode()).setTitleOnly(((TextField)newValue).getText());
+ } else {
+ if (newValue instanceof Attribute) {
+ ((ClassNode)getRefNode()).setAttributeOnly(index,(Attribute)newValue);
+ } else {
+ ((ClassNode)getRefNode()).setOperationOnly(index,(Operation)newValue);
+ }
+ }
+ return updated;
+ }
+
+ // Record change
+ private void recordChange(Object newValue, boolean removed, String oldId) {
+ Object change;
+ String id;
+
+ // If old id is provided, record change for new id only if it was recorded for old id
+ if (oldId != null && !(oldId.isEmpty())) {
+ if (localChangedValues.get(oldId) == null &&
+ localRemovedValues.get(oldId) == null) {
+ return;
+ } else {
+ localChangedValues.remove(oldId);
+ localRemovedValues.remove(oldId);
+ }
+ }
+
+ if (newValue instanceof Title) {
+ id = ((ClassNode)getRefNode()).getId();
+ } else {
+ id = ((IdentifiedTextField)newValue).getXmiId();
+ }
+ if (removed) {
+ localChangedValues.remove(id);
+ localRemovedValues.put(id, newValue);
+ } else {
+ localChangedValues.put(id, newValue);
+ localRemovedValues.remove(id);
+ }
+ }
+
+ private void removeRemoteChangesFromSameUser(TextField oldValue, String userName) {
+ if (oldValue != null) {
+ for (int i = 0; i < oldValue.getContextMenu().getItems().size(); i++) {
+ if (oldValue.getContextMenu().getItems().get(i).getText().contains(userName)) {
+ logger.debug("New remote change frow same user, removing old value from pending evaluation dispatch queue");
+ oldValue.getContextMenu().getItems().remove(oldValue.getContextMenu().getItems().get(i));
+ }
+ }
+ }
+ }
+
+ private void clearPendingEvaluationDispatchQueue(TextField oldValue) {
+ if (oldValue instanceof Title) {
+ while (oldValue.getContextMenu().getItems().size() > 3) {
+ oldValue.getContextMenu().getItems().remove(oldValue.getContextMenu().getItems().get(2));
+ }
+ } else if (oldValue instanceof Attribute
+ || oldValue instanceof Operation) {
+ while (oldValue.getContextMenu().getItems().size() > 4) {
+ oldValue.getContextMenu().getItems().remove(oldValue.getContextMenu().getItems().get(3));
+ }
+ }
+ }
+
+ private void removeConflictIndicationWhenEmptyPendingEvaluationDispatchQueue(TextField oldValue) {
+ if (oldValue instanceof Title) {
+ if (oldValue.getContextMenu().getItems().size() == 3) {
+ oldValue.setStyle("-fx-text-inner-color: black;");
+ }
+ } else {
+ if (oldValue.getContextMenu().getItems().size() == 4) {
+ oldValue.setStyle("-fx-text-inner-color: black;");
+ }
+ }
+ }
+
+
+ private void RemoteChangeToLocalChangeConflict(PropertyChangeEvent evt, TextField oldValue, TextField newValue,
+ int index, String id, String remoteUserName) {
+ // Remove remote changes from same user from conflicting pending evaluation dispatch queue
+ removeRemoteChangesFromSameUser(oldValue, remoteUserName);
+ // Get conflict string
+ Menu cmChange = new Menu(GlobalVariables.getString("conflict") + ": " +
+ getUpdateTypeString(evt, index, oldValue, newValue, id, remoteUserName) + " " +
+ getDateTimeUserSuffixString(remoteUserName));
+
+ // Create conflict record
+ if (newValue instanceof Title) {
+ ((TextField)oldValue).getContextMenu().getItems().add(2,cmChange);
+ } else {
+ ((TextField)oldValue).getContextMenu().getItems().add(3,cmChange);
+ }
+ // Create aprove option
+ MenuItem cmItemActionAprove = new MenuItem(GlobalVariables.getString("accept"));
+ cmItemActionAprove.setUserData(index);
+ cmItemActionAprove.setOnAction(event -> {
+ // Update old value
+ updateTextField(evt, oldValue, id, remoteUserName);
+ // Update model
+ updateModel(evt, (int)cmItemActionAprove.getUserData(), oldValue, newValue);
+ // Clear pending evaluation dispatch queue
+ clearPendingEvaluationDispatchQueue(oldValue);
+ // Record conflict decision to history
+ Menu cmHistory = getHistoryMenu(((TextField)oldValue));
+ MenuItem cmChangeAproved = new MenuItem(cmChange.getText() +
+ ". " + GlobalVariables.getString("accepted") + ".");
+ cmHistory.getItems().add(1, cmChangeAproved);
+ // Records the change
+ if ((int)cmItemActionAprove.getUserData() == -1) {
+ if (oldValue != null) {
+ recordChange(oldValue, true, null);
+ } else {
+ recordChange(newValue, true, null);
+ }
+ } else {
+ if (oldValue != null) {
+ recordChange(oldValue, false, null);
+ } else {
+ recordChange(newValue, false, null);
+ }
+ }
+ // Remove conflict indication
+ removeConflictIndicationWhenEmptyPendingEvaluationDispatchQueue(oldValue);
+ setCommited(false);
+ });
+ // Create reject option
+ MenuItem cmItemActionReject = new MenuItem(GlobalVariables.getString("reject"));
+ cmItemActionReject.setUserData(index);
+ cmItemActionReject.setOnAction(event -> {
+ // Remove conflict from pending evaluation dispatch queue
+ ((TextField)oldValue).getContextMenu().getItems().remove(cmChange);
+ // Record conflict decision to history
+ Menu cmHistory = getHistoryMenu(((TextField)oldValue));
+ MenuItem cmChangeRejected = new MenuItem(cmChange.getText() +
+ ". " + GlobalVariables.getString("rejected") + ".");
+ cmHistory.getItems().add(1, cmChangeRejected);
+ // Remove conflict indication
+ removeConflictIndicationWhenEmptyPendingEvaluationDispatchQueue(oldValue);
+ setCommited(false);
+ });
+ cmChange.getItems().addAll(cmItemActionAprove,cmItemActionReject);
+ // Indicates the conflict
+ if (oldValue != null) {
+ ((TextField)oldValue).setStyle("-fx-text-inner-color: red;");
+ } else if (newValue != null) {
+ ((TextField)newValue).setStyle("-fx-text-inner-color: red;");
+ }
+ }
+
+ public void umlCollab(PropertyChangeEvent evt) {
+ // *** Get new value ***
+ int index = 0;
+ String newValueStr, remoteUserName = null;
+ String[] dataArray = null;
+ Object newValue;
+ if (evt.getPropertyName().equals(Constants.changeNodeTitle)) {
+ newValue = new Title();
+ } else if (evt.getPropertyName().equals(Constants.changeClassNodeAttribute)) {
+ newValue = new Attribute("");
+ } else {
+ newValue = new Operation("");
+ }
+ // From local change
+ if (evt.getNewValue() instanceof String) {
+ newValueStr = (String) evt.getNewValue();
+ }
+ // From remote change
+ else {
+ dataArray = (String[]) evt.getNewValue();
+ newValueStr = (String) dataArray[2];
+ // Get remote user name
+ remoteUserName = dataArray[3];
+ }
+ if (newValue instanceof Title) {
+ ((TextField)newValue).setText(newValueStr);
+ } else {
+ index = Integer.parseInt(newValueStr.substring(0, newValueStr.indexOf("|")));
+ ((IdentifiedTextField)newValue).toString(newValueStr.substring(newValueStr.indexOf("|")+1));
+ newValueStr = ((IdentifiedTextField)newValue).getText();
+ }
+
+ // *** Get old value ***
+ Object oldValue;
+ if (evt.getPropertyName().equals(Constants.changeNodeTitle)) {
+ oldValue = title;
+ } else {
+ // Get old value by id is already exist
+ oldValue = getAttributeOperation((IdentifiedTextField)newValue);
+ }
+
+ // *** Synchronous collaboration type ***
+ if (abstractDiagramController.getCollaborationType().equals(Constants.collaborationTypeSynchronous)) {
+ logger.debug("The type of collaboration is synchronous, performed simple update");
+ // Update old value
+ updateTextField(evt, index, oldValue, newValue);
+ updateModel(evt, index, oldValue, newValue);
+ }
+
+ // *** UMLCollab collaboration type ***
+ else {
+
+ // *** Local change ***
+ if (evt.getNewValue() instanceof String) {
+ logger.debug("Local change, update already done, only updating model and recording the change");
+ // Update model
+ updateModel(evt, index, oldValue, newValue);
+ // Records the change
+ if (index == -1) {
+ if (oldValue != null) {
+ recordChange(oldValue, true, null);
+ } else {
+ recordChange(newValue, true, null);
+ }
+ } else {
+ if (oldValue != null) {
+ recordChange(oldValue, false, null);
+ } else {
+ recordChange(newValue, false, null);
+ }
+ }
+ setCommited(false);
+ }
+
+ // *** Remote change ***
+ else {
+
+ // Get proper id for the object
+ String id;
+ if (evt.getPropertyName().equals(Constants.changeNodeTitle)) {
+ id = ((ClassNode)getRefNode()).getId();
+ } else {
+ id = ((IdentifiedTextField)newValue).getXmiId();
+ }
+
+
+ // *** NO CHANGES, REMOTE ELEMENT EQUALS LOCAL ELEMENT ***
+ if (!elementUpdated(evt, index, (TextField)oldValue, (TextField)newValue)) {
+ logger.info(abstractDiagramController.getUserName() +
+ ":\nReceived new value: '" + ((TextField)newValue).getText() + "' from " + remoteUserName +
+ "\nOld value: '" + oldValue + "'" +
+ "\nNo changes, remote element equals local element.");
+
+ // Only remove conflicts if it is not case of a remote change with a local delete
+ if (localRemovedValues.get(id) == null) {
+ boolean oldConflictsRemoved = false;
+ // Remove remote changes from same user from conflicting pending evaluation dispatch queue
+ if (oldValue != null) {
+ for (int i = 0; i < ((TextField)oldValue).getContextMenu().getItems().size(); i++) {
+ if (((TextField)oldValue).getContextMenu().getItems().get(i).getText().contains(remoteUserName)) {
+ logger.debug("New remote change frow same user, removing old value from pending evaluation dispatch queue");
+ oldConflictsRemoved = true;
+ // Record conflict decision to history
+ Menu cmHistory = getHistoryMenu(((TextField)oldValue));
+ MenuItem cmChange = new MenuItem(((TextField)oldValue).getContextMenu().getItems().get(i).getText() +
+ ". " + GlobalVariables.getString("discardedRemoteVersionMatchsLocalVersion") + ".");
+ cmHistory.getItems().add(1, cmChange);
+ // Removing old value from pending evaluation dispatch queue
+ ((TextField)oldValue).getContextMenu().getItems().remove(((TextField)oldValue).getContextMenu().getItems().get(i));
+ }
+ }
+ }
+ // Remove conflict indication
+ // TODO: When it is green, should not be removed the conflict indication
+ if (oldConflictsRemoved) {
+ removeConflictIndicationWhenEmptyPendingEvaluationDispatchQueue((TextField)oldValue);
+ }
+ }
+
+ // If old value id differ from newValue id then the new value have the same
+ // name of old value. In this case only a id update is needed
+ if (oldValue != null &&
+ (oldValue instanceof Attribute || oldValue instanceof Operation) &&
+ (!((IdentifiedTextField)oldValue).getXmiId().equals(((IdentifiedTextField)newValue).getXmiId())) ) {
+ logger.info("Remote new element name matchs local element name without changes.");
+ String oldId = ((IdentifiedTextField)oldValue).getXmiId();
+ ((IdentifiedTextField)oldValue).setXmiId(((IdentifiedTextField)newValue).getXmiId());
+ // Replace the record of the change of old id for new one
+ if (index == -1) {
+ recordChange(oldValue, true, oldId);
+ } else {
+ recordChange(oldValue, false, oldId);
+ }
+ }
+ }
+
+ // CONFLICT, REMOTE NEW ELEMENT NAME MATCHS LOCAL ELEMENT NAME WITH CHANGES
+ else if (oldValue != null &&
+ (oldValue instanceof Attribute || oldValue instanceof Operation) &&
+ (!((IdentifiedTextField)oldValue).getXmiId().equals(((IdentifiedTextField)newValue).getXmiId())) ) {
+ logger.info(abstractDiagramController.getUserName() +
+ ":\nReceived new value: '" + ((TextField)newValue).getText() + "' from " + remoteUserName +
+ "\nOld value: '" + oldValue + "'" +
+ "\nConflict, remote new element name matchs local element name with changes.");
+ String oldId = ((IdentifiedTextField)oldValue).getXmiId();
+ ((IdentifiedTextField)oldValue).setXmiId(((IdentifiedTextField)newValue).getXmiId());
+ // Replace the record of the change of old id for new one
+ if (index == -1) {
+ recordChange(oldValue, true, oldId);
+ } else {
+ recordChange(oldValue, false, oldId);
+ }
+ RemoteChangeToLocalChangeConflict(evt, (TextField) oldValue, (TextField) newValue, index, id, remoteUserName);
+ }
+
+ // CONFLICT, REMOTE CHANGE WITH LOCAL DELETE
+ else if (localRemovedValues.get(id) != null && index != -1) {
+ logger.info(abstractDiagramController.getUserName() +
+ ":\nReceived new value: '" + ((TextField)newValue).getText() + "' from " + remoteUserName +
+ "\nOld value: '" + oldValue + "'" +
+ "\nConflict, remote change with local delete");
+ // We need to recreate removed element again
+ if (!evt.getPropertyName().equals(Constants.changeNodeTitle)) {
+ createHandlesAttributesOperations(((IdentifiedTextField)newValue));
+ addAttributeOperationToVbox(index,((IdentifiedTextField)newValue));
+ // Records the change
+ recordChange(newValue, true, null);
+ }
+ // Get conflict string
+ Menu cmChange = new Menu(GlobalVariables.getString("conflict") + ": " +
+ getUpdateTypeString(evt, -2, oldValue, newValue, id, remoteUserName) + " " +
+ getDateTimeUserSuffixString(remoteUserName));
+ // Create conflict record
+ if (newValue instanceof Title) {
+ ((TextField)newValue).getContextMenu().getItems().add(2,cmChange);
+ } else {
+ ((TextField)newValue).getContextMenu().getItems().add(3,cmChange);
+ }
+ // Create aprove option
+ MenuItem cmItemActionAprove = new MenuItem(GlobalVariables.getString("accept"));
+ cmItemActionAprove.setUserData(index);
+ cmItemActionAprove.setOnAction(event -> {
+ // Remove conflict from pending evaluation dispatch queue
+ ((TextField)newValue).getContextMenu().getItems().remove(cmChange);
+ // Record conflict decision to history
+ Menu cmHistory = getHistoryMenu(((TextField)newValue));
+ MenuItem cmChangeRejected = new MenuItem(cmChange.getText() +
+ ". " + GlobalVariables.getString("accepted") + ".");
+ cmHistory.getItems().add(1, cmChangeRejected);
+ // Records the change
+ recordChange(newValue, false, null);
+ // Remove conflict indication
+ removeConflictIndicationWhenEmptyPendingEvaluationDispatchQueue((TextField)newValue);
+ setCommited(false);
+ });
+ // Create reject option
+ MenuItem cmItemActionReject = new MenuItem(GlobalVariables.getString("reject"));
+ cmItemActionReject.setOnAction(event -> {
+ // Remove new value
+ updateTextField(evt, -2, oldValue, newValue);
+ // Records the change
+ recordChange(newValue, true, null);
+ setCommited(false);
+ });
+ cmChange.getItems().addAll(cmItemActionAprove,cmItemActionReject);
+ ((TextField)newValue).setStyle("-fx-text-inner-color: red;");
+ }
+
+ // SIMPLE MERGE, REMOTE CHANGE WITHOUT LOCAL CHANGES
+ else if (localChangedValues.get(id) == null && localRemovedValues.get(id) == null && index != -1) {
+ logger.info(abstractDiagramController.getUserName() +
+ ":\nReceived new value: '" + ((TextField)newValue).getText() + "' from " + remoteUserName +
+ "\nOld value: '" + oldValue + "'" +
+ "\nSimple merge, remote change without local change");
+ // Get merge string
+ MenuItem cmChange = new MenuItem(GlobalVariables.getString("merged") + ": " +
+ getUpdateTypeString(evt, index, oldValue, newValue, id, remoteUserName) + " " +
+ getDateTimeUserSuffixString(remoteUserName));
+ // Update old value
+ updateTextField(evt, index, oldValue, newValue);
+ // Update model
+ updateModel(evt, index, oldValue, newValue);
+ // Add new merge history
+ Menu cmHistory = null;
+ if (oldValue != null) {
+ cmHistory = getHistoryMenu((TextField)oldValue);
+ } else if (newValue != null) {
+ cmHistory = getHistoryMenu((TextField)newValue);
+ }
+ if (cmHistory != null) {
+ cmHistory.getItems().add(1, cmChange);
+ }
+ // Indicates the automatic merge
+ if (oldValue != null) {
+ ((TextField)oldValue).setStyle("-fx-text-inner-color: green;");
+ } else if (newValue != null) {
+ ((TextField)newValue).setStyle("-fx-text-inner-color: green;");
+ }
+ }
+
+ // CONFLICT, REMOTE DELETE WITH/WITHOUT LOCAL CHANGE
+ else if (index == -1) {
+ String logMessage = abstractDiagramController.getUserName() +
+ ":\nReceived new value: '" + ((TextField)newValue).getText() + "' from " + remoteUserName +
+ "\nOld value: '" + oldValue + "'";
+ if (localChangedValues.get(id) != null) {
+ logger.info(logMessage + "\nRemote delete with local change, recording conflict");
+ } else {
+ logger.info(logMessage + "\nRemote delete without local change, recording conflict");
+ }
+ // Old value will be null if the a previous conflict was accepted
+ if (oldValue != null) {
+ RemoteChangeToLocalChangeConflict(evt, (TextField) oldValue, (TextField) newValue, index, id, remoteUserName);
+ }
+ }
+
+ // CONFLICT, REMOTE CHANGE WITH LOCAL CHANGE
+ else if (localChangedValues.get(id) != null) {
+ String logMessage = abstractDiagramController.getUserName() +
+ ":\nReceived new value: '" + ((TextField)newValue).getText() + "' from " + remoteUserName +
+ "\nOld value: '" + oldValue + "'";
+ logger.info(logMessage + "\nRemote change with Local change, recording conflict");
+ RemoteChangeToLocalChangeConflict(evt, (TextField) oldValue, (TextField) newValue, index, id, remoteUserName);
+ }
+ }
+ }
+ }
+
@Override
public void propertyChange(PropertyChangeEvent evt) {
-
+ logger.debug("propertyChange()");
+
super.propertyChange(evt);
if (evt.getPropertyName().equals(Constants.changeNodeX)) {
setX((double) evt.getNewValue());
@@ -203,22 +1441,70 @@ public void propertyChange(PropertyChangeEvent evt) {
changeWidth((double) evt.getNewValue());
} else if (evt.getPropertyName().equals(Constants.changeNodeHeight)) {
changeHeight((double) evt.getNewValue());
- } else if (evt.getPropertyName().equals(Constants.changeNodeTitle)) {
- title.setText((String) evt.getNewValue());
- if (title.getText() == null || title.getText().equals("")) {
- firstLine.setVisible(false);
- } else {
- firstLine.setVisible(true);
- }
- } else if (evt.getPropertyName().equals(Constants.changeClassNodeAttributes)) {
- attributes.setText((String) evt.getNewValue());
- } else if (evt.getPropertyName().equals(Constants.changeClassNodeOperations)) {
- operations.setText((String) evt.getNewValue());
- if (operations.getText() == null || operations.getText().equals("")) {
- secondLine.setVisible(false);
- } else {
- secondLine.setVisible(true);
- }
+ } else if (evt.getPropertyName().equals(Constants.changeNodeTitle)
+ || evt.getPropertyName().equals(Constants.changeClassNodeAttribute)
+ || evt.getPropertyName().equals(Constants.changeClassNodeOperation)) {
+ umlCollab(evt);
}
}
+
+ // Transmit all changes made by local user or from a remote change but accepted by local user
+ public boolean commitChanges(){
+ logger.debug("handleMenuActionCommit()");
+ boolean success = false;
+ if (!commited) {
+ // Removed duplicate spaces and trim() before send changes
+ for (int i = 0; i < vbox.getChildren().size(); i++) {
+ Node node = vbox.getChildren().get(i);
+ if (node instanceof Title
+ || node instanceof Attribute
+ || node instanceof Operation) {
+ TextField tf = (TextField) node;
+ tf.setText(tf.getText().trim());
+ while (tf.getText().contains(" ")) {
+ tf.setText(tf.getText().replace(" ", " "));
+ }
+ }
+ }
+ // Send changed values
+ Set ids = localChangedValues.keySet();
+ for (String id : ids)
+ {
+ Object newValue = localChangedValues.get(id);
+ if (newValue instanceof Title) {
+ ((ClassNode)getRefNode()).setTitle(((Title)newValue).getText(),true, abstractDiagramController.getCollaborationType());
+ }
+ else if (newValue instanceof Attribute){
+ Attribute attribute = (Attribute) getAttributeOperation((Attribute)newValue);
+ ((ClassNode)getRefNode()).setAttribute(indexOf(attribute), attribute, true, abstractDiagramController.getCollaborationType());
+ }
+ else if (newValue instanceof Operation){
+ Operation operation = (Operation) getAttributeOperation((Operation)newValue);
+ ((ClassNode)getRefNode()).setOperation(indexOf(operation), operation, true, abstractDiagramController.getCollaborationType());
+ }
+ }
+ // Send removed values
+ ids = localRemovedValues.keySet();
+ for (String id : ids)
+ {
+ Object newValue = localRemovedValues.get(id);
+ if (newValue instanceof Attribute){
+ Attribute attribute = (Attribute) newValue;
+ ((ClassNode)getRefNode()).setAttribute(-1, attribute, true, abstractDiagramController.getCollaborationType());
+ }
+ else if (newValue instanceof Operation){
+ Operation operation = (Operation) newValue;
+ ((ClassNode)getRefNode()).setOperation(-1, operation, true, abstractDiagramController.getCollaborationType());
+ }
+ }
+ setCommited(true);
+ success = true;
+ }
+ return success;
+ }
+
+ private void dismissAutomaticMerge(MenuItem cmItemChange) {
+ // TODO Auto-generated method stub
+
+ }
}
diff --git a/tests/view/ClassNodeViewTest.java b/tests/view/ClassNodeViewTest.java
index 4c8cf91..bcb636c 100644
--- a/tests/view/ClassNodeViewTest.java
+++ b/tests/view/ClassNodeViewTest.java
@@ -2,6 +2,8 @@
import model.nodes.ClassNode;
import org.junit.Test;
+
+import controller.AbstractDiagramController;
import view.nodes.ClassNodeView;
import static org.junit.Assert.assertEquals;
@@ -12,7 +14,7 @@ public class ClassNodeViewTest {
public void testNodes() {
double delta = 0.001d;
ClassNode mNode = new ClassNode(0, 0, 0, 0);
- ClassNodeView vNode = new ClassNodeView(mNode);
+ ClassNodeView vNode = new ClassNodeView(mNode, null);
assert vNode.getX() == mNode.getX();
mNode.setX(5);
mNode.setY(10.555);