Added support for closing projects. Fixed some bugs with editing existing links.

This commit is contained in:
AccentuSoft
2022-01-20 22:18:39 +02:00
parent 3bdbafc58d
commit 15d1ae3f58
5 changed files with 73 additions and 33 deletions

View File

@@ -115,7 +115,7 @@ class EntitiesDB:
self.mainWindow.updateEntityNodeLabelsOnCanvases(entity['uid'], entity[list(entity)[1]])
self.dbLock.release()
if not fromServer:
self.mainWindow.sendLocalDatabaseUpdateToServer(entity, True)
self.mainWindow.sendLocalDatabaseUpdateToServer(entity, 1)
self.mainWindow.populateEntitiesWidget(returnValue, add=True)
if updateTimeline:
@@ -149,7 +149,7 @@ class EntitiesDB:
# Update canvases if the node already exists.
self.mainWindow.updateEntityNodeLabelsOnCanvases(entity['uid'], entity[list(entity)[1]])
if not fromServer:
self.mainWindow.sendLocalDatabaseUpdateToServer(entity, True)
self.mainWindow.sendLocalDatabaseUpdateToServer(entity, 1)
self.mainWindow.populateEntitiesWidget(entity, add=True)
self.dbLock.release()
@@ -157,10 +157,11 @@ class EntitiesDB:
return returnValue
def addLink(self, linkJson: dict, fromServer=False):
def addLink(self, linkJson: dict, fromServer: bool = False, overwrite: bool = False):
"""
Add a link between two entities in the database.
:param overwrite:
:param linkJson:
:param fromServer:
:return:
@@ -180,8 +181,14 @@ class EntitiesDB:
newRes = link.get('Resolution')
newNotes = link.get('Notes')
if newRes and newRes != exists['Resolution']:
link['Resolution'] = exists['Resolution'] + ' | ' + newRes
if newNotes and newNotes != exists['Notes']:
if overwrite:
link['Resolution'] = newRes
else:
link['Resolution'] = exists['Resolution'] + ' | ' + newRes
if newNotes and newNotes != exists['Notes'] and newNotes != 'None':
if overwrite:
link['Notes'] = str(newNotes)
else:
link['Notes'] = exists['Notes'] + '\n\n' + str(newNotes)
exists.update(link)
link.update(exists)
@@ -194,7 +201,10 @@ class EntitiesDB:
self.dbLock.release()
if not fromServer:
self.mainWindow.sendLocalDatabaseUpdateToServer(link, True)
if overwrite:
self.mainWindow.sendLocalDatabaseUpdateToServer(link, 3)
else:
self.mainWindow.sendLocalDatabaseUpdateToServer(link, 1)
return link
def getEntity(self, uid: str):
@@ -291,7 +301,7 @@ class EntitiesDB:
if ent is not None:
self.mainWindow.handleGroupNodeUpdateAfterEntityDeletion(uid) # Blocking - locks the db.
if not fromServer:
self.mainWindow.sendLocalDatabaseUpdateToServer(ent, False)
self.mainWindow.sendLocalDatabaseUpdateToServer(ent, 2)
if updateTimeLine:
self.updateTimeline(ent, False)
@@ -305,7 +315,7 @@ class EntitiesDB:
self.database.remove_edge(uid[0], uid[1])
self.dbLock.release()
if not fromServer:
self.mainWindow.sendLocalDatabaseUpdateToServer({"uid": uid}, False)
self.mainWindow.sendLocalDatabaseUpdateToServer({"uid": uid}, 2)
def doesEntityExist(self, primaryAttr: str):
"""

View File

@@ -55,7 +55,7 @@ class CommunicationsHandler(QtCore.QObject):
close_project_signal = QtCore.Signal()
open_project_canvas_signal = QtCore.Signal(str)
close_project_canvas_signal = QtCore.Signal(str)
receive_project_database_update = QtCore.Signal(dict, bool)
receive_project_database_update = QtCore.Signal(dict, int)
receive_project_canvas_update_node = QtCore.Signal(str, str)
receive_project_canvas_update_link = QtCore.Signal(str, tuple)
receive_sync_database = QtCore.Signal(dict, dict)
@@ -88,7 +88,7 @@ class CommunicationsHandler(QtCore.QObject):
self.receive_project_canvases_list_signal.connect(self.mainWindow.receiveProjectCanvasesListListener)
self.open_project_signal.connect(self.mainWindow.openServerProjectListener)
self.open_project_canvas_signal.connect(self.mainWindow.openServerCanvasListener)
self.close_project_signal.connect(self.mainWindow.closeCurrentServerProject)
self.close_project_signal.connect(self.mainWindow.closeServerProjectListener)
self.close_project_canvas_signal.connect(self.mainWindow.closeServerCanvasListener)
self.receive_project_database_update.connect(self.mainWindow.receiveServerDatabaseUpdate)
self.receive_project_canvas_update_node.connect(self.mainWindow.receiveServerCanvasUpdate)
@@ -150,17 +150,19 @@ class CommunicationsHandler(QtCore.QObject):
self.mainWindow.MESSAGEHANDLER.warning("Server did not reply in the expected manner to "
"password authentication.", popUp=True)
except ConnectionRefusedError:
self.mainWindow.MESSAGEHANDLER.error("Did not connect: Server not running.", popUp=True, exc_info=False)
except Exception as exception:
self.mainWindow.MESSAGEHANDLER.error("Did not connect: " + str(exception))
try:
if self.sock is not None:
self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close()
self.sock = None
except OSError:
# This would typically occur if the socket is already closed.
self.mainWindow.MESSAGEHANDLER.info('Tried to close socket that was already closed.')
# This would typically occur if the socket is already shut down.
self.mainWindow.MESSAGEHANDLER.debug('Tried to shutdown socket that was already shut down.')
self.sock.close()
self.sock = None
return False
@@ -447,14 +449,14 @@ class CommunicationsHandler(QtCore.QObject):
# to a particular canvas.
# Being verbose is better than prematurely optimizing for a few kbps of
# network traffic.
def receiveDatabaseUpdateEvent(self, entity_json: dict, add: bool):
def receiveDatabaseUpdateEvent(self, entity_json: dict, add: int):
try:
entity_json['Icon'] = QtCore.QByteArray(b64decode(entity_json['Icon']))
except KeyError:
pass
self.receive_project_database_update.emit(entity_json, add)
def sendDatabaseUpdateEvent(self, project_name: str, entity_json: dict, add: bool):
def sendDatabaseUpdateEvent(self, project_name: str, entity_json: dict, add: int):
try:
entity_json['Icon'] = entity_json['Icon'].toBase64().data()
except KeyError:

View File

@@ -481,14 +481,16 @@ class TabbedPane(QtWidgets.QTabWidget):
scene.rearrangeGraph()
# self.mainWindow.syncCanvasByName(canvas)
def serverLinkAddHelper(self, linkJson: dict) -> None:
def serverLinkAddHelper(self, linkJson: dict, overwrite: bool = False) -> None:
"""
Assumes that the 'uid' field is a tuple.
:param overwrite:
:param linkJson:
:return:
"""
linkUID = linkJson['uid']
lJson = self.entityDB.addLink(linkJson, fromServer=True)
lJson = self.entityDB.addLink(linkJson, fromServer=True, overwrite=overwrite)
for canvas in self.canvasTabs:
if self.canvasTabs[canvas].scene().sceneGraph.nodes.get(linkUID[0]) is not None:
if self.canvasTabs[canvas].scene().sceneGraph.nodes.get(linkUID[1]) is None:
@@ -1543,7 +1545,7 @@ class CanvasScene(QtWidgets.QGraphicsScene):
pEditor = PropertiesEditor(self, linkJSON)
if pEditor.exec_():
# Adding link with the same UID just overwrites properties.
self.parent().entityDB.addLink(pEditor.objectJson)
self.parent().entityDB.addLink(pEditor.objectJson, overwrite=True)
self.parent().messageHandler.info('Edited link: ' + str(pEditor.objectJson['uid']) + ' | ' +
pEditor.objectJson['Resolution'])

View File

@@ -227,6 +227,11 @@ class MenuBar(QtWidgets.QMenuBar):
triggered=self.serverOpenOrCreateProject)
serverMenu.addAction(createOrOpenProjectAction)
closeCurrentProjectAction = QtGui.QAction("Close Current Project", self,
statusTip="Close the Server project that is currently open.",
triggered=self.serverCloseProject)
serverMenu.addAction(closeCurrentProjectAction)
deleteProjectAction = QtGui.QAction("Delete Current Project", self,
statusTip="Delete the Server project that is currently opened.",
triggered=self.serverDeleteProject)
@@ -686,6 +691,9 @@ class MenuBar(QtWidgets.QMenuBar):
self.parent().MESSAGEHANDLER.warning('Not Connected to Server!', popUp=True)
self.parent().setStatus('Must connect to a server before opening a project.')
def serverCloseProject(self) -> None:
self.parent().closeCurrentServerProject()
def serverDeleteProject(self) -> None:
if self.parent().FCOM.isConnected():
current_project = self.parent().SETTINGS.value("Project/Server/Project")

View File

@@ -1108,6 +1108,8 @@ class MainWindow(QtWidgets.QMainWindow):
self.RESOLUTIONMANAGER.removeServerResolutions()
self.dockbarOne.resolutionsPalette.loadAllResolutions()
self.closeServerProjectListener()
with self.serverProjectsLock:
self.serverProjects = []
self.setStatus("Disconnected from server.")
self.dockbarThree.serverStatus.updateStatus("Not connected to a server")
@@ -1139,6 +1141,7 @@ class MainWindow(QtWidgets.QMainWindow):
with self.serverProjectsLock:
try:
self.serverProjects.remove(deleted_project)
self.closeServerProjectListener()
except ValueError:
# If the client doesn't know about the deleted project, nothing to do.
pass
@@ -1154,23 +1157,29 @@ class MainWindow(QtWidgets.QMainWindow):
self.MESSAGEHANDLER.info("Opened Server Project: " + project_name, popUp=True)
def closeCurrentServerProject(self) -> None:
current_project = self.SETTINGS.value("Project/Server/Project")
if current_project != "":
self.FCOM.closeProject(current_project)
if self.FCOM.isConnected():
current_project = self.SETTINGS.value("Project/Server/Project")
if current_project != "":
self.FCOM.closeProject(current_project)
else:
self.MESSAGEHANDLER.warning('No Server Project to close.', popUp=True)
else:
self.MESSAGEHANDLER.warning('Not connected to a Server.', popUp=True)
def closeServerProjectListener(self) -> None:
project_name = self.SETTINGS.value("Project/Server/Project")
server = self.SETTINGS.value("Project/Server")
self.SETTINGS.setValue("Project/Server/Project", "")
self.FCOM.receiveFileAbortAll(project_name)
self.FCOM.sendFileAbortAll(project_name)
self.unSyncCanvasByName()
self.setStatus("Closed Server project: " + project_name)
self.dockbarThree.serverStatus.updateStatus("Connected to server: " +
self.SETTINGS.value("Project/Server"))
if server is not None:
statusMessage = "Closed Server project: " + str(project_name)
self.MESSAGEHANDLER.info(statusMessage)
self.setStatus(statusMessage)
self.dockbarThree.serverStatus.updateStatus("Connected to server: " + server)
self.dockbarOne.documentsList.updateFileListFromServer(None)
with self.serverProjectsLock:
self.serverProjects = []
with self.syncedCanvasesLock:
self.syncedCanvases = []
@@ -1233,8 +1242,14 @@ class MainWindow(QtWidgets.QMainWindow):
if project_name != '':
self.FCOM.closeCanvas(project_name, canvasName)
if canvasName is not None:
self.setStatus('Stopped syncing Canvas: ' + canvasName)
self.MESSAGEHANDLER.info('Stopped syncing Canvas: ' + canvasName)
statusMessage = 'Stopped syncing Canvas: ' + canvasName
self.setStatus(statusMessage)
self.MESSAGEHANDLER.info(statusMessage)
else:
statusMessage = 'Stopped syncing all Canvases.'
self.setStatus(statusMessage)
self.MESSAGEHANDLER.info(statusMessage)
def receiveSyncCanvasListener(self, canvas_name: str, canvas_nodes: dict, canvas_edges: dict) -> None:
if canvas_name in self.centralWidget().tabbedPane.canvasTabs:
@@ -1279,7 +1294,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.MESSAGEHANDLER.debug('Received update to canvas: ' + canvas_name + ' for entity / link: ' +
str(entity_or_link_uid))
def sendLocalDatabaseUpdateToServer(self, entityJson: dict, add: bool) -> None:
def sendLocalDatabaseUpdateToServer(self, entityJson: dict, add: int) -> None:
"""
Called by the database when a local item event occurs.
If connected to a server, the event is propagated to all other connected clients.
@@ -1292,11 +1307,11 @@ class MainWindow(QtWidgets.QMainWindow):
self.MESSAGEHANDLER.debug('Sent database update to server: ' + str(entityJson) + ' - Operation: ' +
str(add))
def receiveServerDatabaseUpdate(self, entityJson, add) -> None:
def receiveServerDatabaseUpdate(self, entityJson: dict, add: int) -> None:
# Check that the JSON received is not empty.
if entityJson:
uid = entityJson['uid']
if add:
if add == 1:
# Add item
if isinstance(uid, str):
# Add Entity
@@ -1304,7 +1319,7 @@ class MainWindow(QtWidgets.QMainWindow):
else:
# Add Link
self.centralWidget().tabbedPane.serverLinkAddHelper(entityJson)
else:
elif add == 2:
# Remove item
if isinstance(uid, str):
# Remove Entity
@@ -1314,6 +1329,9 @@ class MainWindow(QtWidgets.QMainWindow):
# Remove Link
self.centralWidget().tabbedPane.linkRemoveAllHelper(uid)
self.LENTDB.removeLink(uid, fromServer=True)
elif add == 3:
# Overwrite existing link
self.centralWidget().tabbedPane.serverLinkAddHelper(entityJson, overwrite=True)
self.MESSAGEHANDLER.debug('Received database update from server: ' + str(entityJson) + ' - Operation: ' +
str(add))