Files
LinkScope_Client/Core/Interface/DockBarOne.py
AccentuSoft 7507990ca5 Push commits:
Move saved Resolutions parameters to global scope.

Move all Program settings to global scope.

Update & Refactor Settings Object.

Update Whats My Name - make detection more precise & add sites.

Update README.md

Update version number

Finalize importing tabs from TOR.

Change settings labels so they look better in menus. Add Tor browser path setting.

Fix bug with deselected entities when zooming out.

Transition to pyqtdarktheme for theme & styling.

Check if firefox snap exists if firefox package is not present.

Make sure that every file from the directories holding resolutions is present.

Refactor importing of tabs.
2023-02-07 18:04:19 +02:00

427 lines
17 KiB
Python

#!/usr/bin/env python3
from json import dumps
from Core.Interface.Entity import BaseNode
from PySide6 import QtWidgets, QtCore, QtGui
class DockBarOne(QtWidgets.QDockWidget):
def initialiseLayout(self) -> None:
childWidget = QtWidgets.QTabWidget()
nodeTabChildWidget = QtWidgets.QWidget()
docsTabChildWidget = QtWidgets.QWidget()
nodeTabChildWidget.setLayout(QtWidgets.QGridLayout())
docsTabChildWidget.setLayout(QtWidgets.QGridLayout())
self.setWidget(childWidget)
childWidget.addTab(nodeTabChildWidget, "Node Operations")
childWidget.addTab(docsTabChildWidget, "Documents")
nodeTabChildWidget.layout().addWidget(self.nodesPalette)
nodeTabChildWidget.layout().addWidget(self.resolutionsPalette)
docsTabChildWidget.layout().addWidget(self.documentsList)
docsTabChildWidget.layout().addWidget(self.existingEntitiesPalette)
worldDocToggle = ToggleWorldDocButton(self, self.parent())
docsTabChildWidget.layout().addWidget(worldDocToggle)
def __init__(self,
mainWindow,
resolutionManager,
resourceHandler,
entityDatabase,
title="DockBar One") -> None:
super(DockBarOne, self).__init__(parent=mainWindow)
self.resolutionManager = resolutionManager
self.resourceHandler = resourceHandler
self.lentDB = entityDatabase
self.setAllowedAreas(QtCore.Qt.DockWidgetArea.LeftDockWidgetArea |
QtCore.Qt.DockWidgetArea.RightDockWidgetArea)
self.setFeatures(QtWidgets.QDockWidget.DockWidgetFeature.DockWidgetMovable |
QtWidgets.QDockWidget.DockWidgetFeature.DockWidgetFloatable |
QtWidgets.QDockWidget.DockWidgetFeature.DockWidgetClosable)
self.setWindowTitle(title)
self.setObjectName(title)
self.nodesPalette = NodeList(self.resourceHandler, self)
self.resolutionsPalette = ResolutionList(self.resolutionManager,
self.lentDB,
self.parent(),
self)
self.documentsList = DocList(self.resourceHandler, self)
self.existingEntitiesPalette = EntityList(self.lentDB, self.parent(), self)
self.initialiseLayout()
class ToggleWorldDocButton(QtWidgets.QPushButton):
def __init__(self, parent=None, mainWindow=None) -> None:
super(ToggleWorldDocButton, self).__init__(parent=parent)
self.mainWindow = mainWindow
self.setText("Toggle Detailed View")
self.clicked.connect(self.buttonPressed)
def buttonPressed(self) -> None:
if self.mainWindow is not None:
self.mainWindow.toggleWorldDoc()
class EntityList(QtWidgets.QTreeWidget):
def __init__(self, entityDB, mainWindow, parent=None):
super(EntityList, self).__init__(parent=parent)
self.entityDB = entityDB
self.mainWindow = mainWindow
self.setDragEnabled(True)
self.setHeaderLabels(['Entity List'])
self.setAlternatingRowColors(False)
self.setMinimumWidth(200)
self.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)
self.menu = QtWidgets.QMenu()
actionDelete = QtGui.QAction('Delete Selected Items',
self.menu,
statusTip="Delete the selected entities from the database.",
triggered=self.deleteSelectedItems)
self.menu.addAction(actionDelete)
actionAddToCurrentCanvas = QtGui.QAction('Add Selected Items to Current Canvas',
self.menu,
statusTip="Add the selected entities to the current canvas.",
triggered=self.addItemsToCurrentCanvas)
self.menu.addAction(actionAddToCurrentCanvas)
self.entityCategories: dict = {}
self.entityTypes: dict = {}
self.loadEntities()
def loadEntities(self) -> None:
self.clear()
self.entityCategories = {}
self.entityTypes = {}
for category in self.mainWindow.RESOURCEHANDLER.getEntityCategories():
catTreeItem = QtWidgets.QTreeWidgetItem(self, [category])
self.entityCategories[category] = catTreeItem
for category in self.entityCategories:
for entityType in self.mainWindow.RESOURCEHANDLER.getAllEntitiesInCategory(category):
typeTreeItem = QtWidgets.QTreeWidgetItem(self.entityCategories[category], [entityType])
self.entityTypes[entityType] = typeTreeItem
allEntities = self.entityDB.getAllEntities()
for entity in allEntities:
topItem = self.entityTypes[entity['Entity Type']]
primaryAttr = entity[list(entity)[1]]
pixmapIcon = QtGui.QPixmap()
pixmapIcon.loadFromData(entity['Icon'])
EntityWidget(topItem,
entity['uid'],
QtGui.QIcon(pixmapIcon),
primaryAttr)
# Hide entity types and categories with no item instances (children):
for category in self.entityCategories:
childrenHidden = 0
for entityTypeIndex in range(self.entityCategories[category].childCount()):
entityTypeItem = self.entityCategories[category].child(entityTypeIndex)
if entityTypeItem.childCount() == 0:
entityTypeItem.setHidden(True)
childrenHidden += 1
if childrenHidden == self.entityCategories[category].childCount():
self.entityCategories[category].setHidden(True)
def addEntity(self, entityJson) -> None:
primaryAttr = entityJson[list(entityJson)[1]]
entityTypeItem = self.entityTypes[entityJson['Entity Type']]
for entityNo in range(entityTypeItem.childCount()):
child = entityTypeItem.child(entityNo)
if child.uid == entityJson['uid']:
child.setText(0, primaryAttr)
return
pixmapIcon = QtGui.QPixmap()
pixmapIcon.loadFromData(entityJson['Icon'])
EntityWidget(entityTypeItem,
entityJson['uid'],
QtGui.QIcon(pixmapIcon),
primaryAttr)
# Un-hide parents of item, if they were hidden.
if entityTypeItem.isHidden():
entityTypeItem.setHidden(False)
entityTypeItem.parent().setHidden(False)
def removeEntity(self, entityJson) -> None:
entityType = self.entityTypes[entityJson['Entity Type']]
for entityNo in range(entityType.childCount()):
child = entityType.child(entityNo)
if child.uid == entityJson['uid']:
entityType.removeChild(child)
del child
if entityType.childCount() == 0:
entityType.setHidden(True)
entityCategory = entityType.parent()
entityCategory.setHidden(True)
for childID in range(entityCategory.childCount()):
child = entityCategory.child(childID)
if not child.isHidden():
entityCategory.setHidden(False)
break
break
def mouseMoveEvent(self, event) -> None:
"""
Handle dragging of entities onto canvas.
"""
super().mouseMoveEvent(event)
if event.buttons() == QtCore.Qt.MouseButton.LeftButton:
itemDragged = self.itemAt(event.pos())
else:
return
# Categories & entity names don't have uids.
try:
if itemDragged.uid is None:
return
except Exception:
return
self.setCurrentItem(itemDragged)
drag = QtGui.QDrag(self)
mimeData = QtCore.QMimeData()
mimeData.setText(dumps({'uid': itemDragged.uid}))
drag.setMimeData(mimeData)
# All Entities should have icons, but you never know.
pixmap = None
if itemDragged.icon(0) is not None:
pixmap = itemDragged.icon(0).pixmap(40, 40)
drag.setPixmap(pixmap)
drag.setHotSpot(QtCore.QPoint(pixmap.rect().width() // 2, pixmap.rect().height() // 2))
drag.exec_()
def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
super(EntityList, self).mousePressEvent(event)
if event.button() == QtGui.Qt.MouseButton.RightButton:
itemDragged = self.itemAt(event.pos())
if isinstance(itemDragged, EntityWidget):
self.menu.exec(QtGui.QCursor.pos())
def deleteSelectedItems(self) -> None:
itemsToDel = [item.uid for item in self.selectedItems() if isinstance(item, EntityWidget)]
for itemUID in itemsToDel:
self.mainWindow.deleteSpecificEntity(itemUID)
def addItemsToCurrentCanvas(self) -> None:
currentScene = self.mainWindow.centralWidget().tabbedPane.getCurrentScene()
itemsToAdd = [item.uid for item in self.selectedItems() if isinstance(item, EntityWidget) and
item.uid not in currentScene.sceneGraph.nodes]
for itemUID in itemsToAdd:
if itemUID.endswith('@'):
newGroupEntity = self.mainWindow.copyGroupEntity(itemUID, currentScene)
if newGroupEntity is not None:
currentScene.addNodeProgrammatic(newGroupEntity['uid'], newGroupEntity['Child UIDs'])
else:
currentScene.addNodeProgrammatic(itemUID)
currentScene.rearrangeGraph()
class EntityWidget(QtWidgets.QTreeWidgetItem):
def __init__(self, parent, uid=None, icon=None, text="") -> None:
super(EntityWidget, self).__init__(parent, [text])
self.uid = uid
if icon is not None:
self.setIcon(0, icon)
class DocList(QtWidgets.QTreeWidget):
def __init__(self, resourceHandler, parent=None) -> None:
super(DocList, self).__init__(parent=parent)
self.resourceHandler = resourceHandler
self.setAlternatingRowColors(False)
self.setHeaderLabels(['Files Loaded'])
self.uploadingFileWidgets = []
self.uploadedFileWidgets = []
self.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)
def addUploadingFileToList(self, fileName: str) -> None:
newWidget = DocWidget(self,
QtGui.QIcon(self.resourceHandler.getIcon("uploading")), fileName)
self.uploadingFileWidgets.append(newWidget)
def finishUploadingFile(self, fileName: str) -> None:
# Remove uploading file. Server will send updated file list.
for doc in list(self.uploadingFileWidgets):
if doc.getFileName() == fileName:
self.takeTopLevelItem(self.indexOfTopLevelItem(doc))
self.uploadingFileWidgets.remove(doc)
break
def updateFileListFromServer(self, fileList) -> None:
# If disconnected from server, or project has an empty file list, clear the widget.
if not fileList:
self.clear()
self.uploadingFileWidgets = []
self.uploadedFileWidgets = []
return
for fileName in fileList:
if fileName in [uploadedFileWidget.getFileName() for uploadedFileWidget in self.uploadedFileWidgets]:
continue
newWidget = DocWidget(self, None, fileName)
self.uploadedFileWidgets.append(newWidget)
class DocWidget(QtWidgets.QTreeWidgetItem):
def __init__(self, parent, icon=None, text="") -> None:
super(DocWidget, self).__init__(parent, [text])
if icon is not None:
self.setIcon(0, icon)
def getFileName(self) -> str:
return self.text(0)
class ResolutionList(QtWidgets.QTreeWidget):
def __init__(self,
resolutionManager,
entityDatabase,
mainWindow,
parent=None) -> None:
super(ResolutionList, self).__init__(parent=parent)
self.resolutionManager = resolutionManager
self.lentDB = entityDatabase
self.mainWindow = mainWindow
self.setDragEnabled(True)
self.setHeaderLabels(['Resolutions'])
self.setAlternatingRowColors(False)
self.setMinimumWidth(200)
self.setSortingEnabled(True)
self.sortByColumn(0, QtCore.Qt.SortOrder.AscendingOrder)
self.loadAllResolutions()
def loadAllResolutions(self) -> None:
self.clear()
for category in self.resolutionManager.getResolutionCategories():
resTreeItem = QtWidgets.QTreeWidgetItem(self, [category])
resolutions = self.resolutionManager.getResolutionsInCategory(category)
for res in resolutions:
ResolutionWidget(resTreeItem, text=res)
def loadResolutionsForSelected(self, selected) -> None:
self.clear()
if len(selected) == 0:
self.loadAllResolutions()
return
entityTypes = set()
for item in selected:
if not isinstance(item, BaseNode):
continue
ent = self.lentDB.getEntity(item.uid)
entityTypes.add(ent['Entity Type'])
res = self.resolutionManager.getResolutionsForEntityTypesByCategory(entityTypes)
for category in res:
resolutions = res[category]
if len(resolutions) != 0:
resTreeItem = QtWidgets.QTreeWidgetItem(self, [category])
for resolution in resolutions:
ResolutionWidget(resTreeItem, text=resolution)
def mouseDoubleClickEvent(self, event) -> None:
super(ResolutionList, self).mouseDoubleClickEvent(event)
resItem = self.itemAt(event.pos())
if resItem is None or not isinstance(resItem, ResolutionWidget):
return
# Resolution Widgets should always have a parent, no need to check.
category = resItem.parent().text(0)
resolution = resItem.text(0)
if resolution not in self.resolutionManager.getResolutionsInCategory(category):
return
self.mainWindow.runResolution(f'{category}/{resolution}')
class ResolutionWidget(QtWidgets.QTreeWidgetItem):
def __init__(self, parent, icon=None, text="") -> None:
super(ResolutionWidget, self).__init__(parent, [text])
if icon is not None:
self.setIcon(0, icon)
class NodeList(QtWidgets.QTreeWidget):
def __init__(self, resourceHandler, parent=None) -> None:
super(NodeList, self).__init__(parent=parent)
self.resourceHandler = resourceHandler
self.setDragEnabled(True)
self.setHeaderLabels(['Entities'])
self.setAlternatingRowColors(False)
self.setSortingEnabled(True)
self.sortByColumn(0, QtCore.Qt.SortOrder.AscendingOrder)
self.allEntities = []
self.loadEntities()
def loadEntities(self) -> None:
self.clear()
self.allEntities = []
for category in self.resourceHandler.getEntityCategories():
catTreeItem = QtWidgets.QTreeWidgetItem(self, [category])
entities = self.resourceHandler.getAllEntityDetailsWithIconsInCategory(
category)
for entity in entities:
NodeWidget(catTreeItem,
QtGui.QIcon(entity[1]),
entity[0]['Entity Type'],
dumps(entity[0]))
self.allEntities = self.resourceHandler.getAllEntities()
def mouseMoveEvent(self, event) -> None:
"""
Handle dragging of entities onto canvas.
"""
if event.buttons() == QtCore.Qt.MouseButton.LeftButton:
itemDragged = self.itemAt(event.pos())
if itemDragged is None or \
itemDragged.text(0) not in self.allEntities:
return
self.setCurrentItem(itemDragged)
drag = QtGui.QDrag(self)
mimeData = QtCore.QMimeData()
mimeData.setText(itemDragged.entityJsonText)
drag.setMimeData(mimeData)
# All Entities should have icons, but you never know.
pixmap = None
if itemDragged.icon(0) is not None:
pixmap = itemDragged.icon(0).pixmap(40, 40)
drag.setPixmap(pixmap)
drag.setHotSpot(QtCore.QPoint(pixmap.rect().width() // 2, pixmap.rect().height() // 2))
drag.exec_()
class NodeWidget(QtWidgets.QTreeWidgetItem):
def __init__(self, parent, icon=None, name="", entityJsonText="") -> None:
super(NodeWidget, self).__init__(parent, [name])
if icon is not None:
self.setIcon(0, icon)
self.entityJsonText = entityJsonText