736 lines
32 KiB
Python
736 lines
32 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import inspect
|
|
import os
|
|
from specklepy_qt_ui.widget_custom_crs import CustomCRSDialog
|
|
|
|
from specklepy_qt_ui.widget_transforms import MappingSendDialog
|
|
from specklepy_qt_ui.LogWidget import LogWidget
|
|
from specklepy_qt_ui.logger import logToUser
|
|
from specklepy_qt_ui.DataStorage import DataStorage
|
|
from specklepy_qt_ui.global_resources import (
|
|
COLOR_HIGHLIGHT,
|
|
SPECKLE_COLOR, SPECKLE_COLOR_LIGHT,
|
|
ICON_LOGO, ICON_SEARCH, ICON_DELETE, ICON_DELETE_BLUE,
|
|
ICON_SEND, ICON_RECEIVE, ICON_SEND_BLACK, ICON_RECEIVE_BLACK,
|
|
ICON_SEND_BLUE, ICON_RECEIVE_BLUE,
|
|
COLOR, BACKGR_COLOR, BACKGR_COLOR_LIGHT,
|
|
ICON_XXL, ICON_RASTER, ICON_POLYGON, ICON_LINE, ICON_POINT, ICON_GENERIC,
|
|
)
|
|
from specklepy.logging.exceptions import (SpeckleException, GraphQLException)
|
|
from specklepy.logging import metrics
|
|
|
|
|
|
from PyQt5 import QtWidgets, uic
|
|
from PyQt5.QtGui import QIcon, QPixmap
|
|
from PyQt5.QtWidgets import QCheckBox, QListWidgetItem, QHBoxLayout, QWidget
|
|
from PyQt5 import QtCore
|
|
from PyQt5.QtCore import pyqtSignal
|
|
|
|
|
|
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
|
|
FORM_CLASS, _ = uic.loadUiType(
|
|
os.path.join(os.path.dirname(__file__), os.path.join("ui", "dockwidget_main.ui") )
|
|
)
|
|
|
|
class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
|
|
|
|
closingPlugin = pyqtSignal()
|
|
streamList: QtWidgets.QComboBox
|
|
sendModeButton: QtWidgets.QPushButton
|
|
receiveModeButton: QtWidgets.QPushButton
|
|
streamBranchDropdown: QtWidgets.QComboBox
|
|
layerSendModeDropdown: QtWidgets.QComboBox
|
|
commitDropdown: QtWidgets.QComboBox
|
|
layersWidget: QtWidgets.QListWidget
|
|
saveLayerSelection: QtWidgets.QPushButton
|
|
runButton: QtWidgets.QPushButton
|
|
setMapping: QtWidgets.QPushButton
|
|
experimental: QCheckBox
|
|
msgLog: LogWidget = None
|
|
dataStorage: DataStorage = None
|
|
mappingSendDialog = None
|
|
custom_crs_modal = None
|
|
|
|
signal_1 = pyqtSignal(object)
|
|
signal_2 = pyqtSignal(object)
|
|
signal_3 = pyqtSignal(object)
|
|
signal_4 = pyqtSignal(object)
|
|
|
|
def __init__(self, parent=None):
|
|
"""Constructor."""
|
|
super(SpeckleQGISDialog, self).__init__(parent)
|
|
# Set up the user interface from Designer through FORM_CLASS.
|
|
# After self.setupUi() you can access any designer object by doing
|
|
# self.<objectname>, and you can use autoconnect slots - see
|
|
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
|
|
# #widgets-and-dialogs-with-auto-connect
|
|
self.setupUi(self)
|
|
|
|
self.streamBranchDropdown.setMaxCount(100)
|
|
self.commitDropdown.setMaxCount(100)
|
|
|
|
self.streams_add_button.setFlat(True)
|
|
self.streams_remove_button.setFlat(True)
|
|
#self.saveSurveyPoint.setFlat(True)
|
|
self.saveLayerSelection.setFlat(True)
|
|
self.reloadButton.setFlat(True)
|
|
self.closeButton.setFlat(True)
|
|
|
|
# https://stackoverflow.com/questions/67585501/pyqt-how-to-use-hover-in-button-stylesheet
|
|
#color = f"color: rgb{str(SPECKLE_COLOR)};"
|
|
#backgr_color = f"background-color: rgb{str(SPECKLE_COLOR)};"
|
|
#backgr_color_light = f"background-color: rgb{str(SPECKLE_COLOR_LIGHT)};"
|
|
backgr_image_del = f"border-image: url({ICON_DELETE_BLUE});"
|
|
self.streams_add_button.setIcon(QIcon(ICON_SEARCH))
|
|
self.streams_add_button.setMaximumWidth(25)
|
|
self.streams_add_button.setStyleSheet("QPushButton {padding:3px;padding-left:5px;border: none; text-align: left;} QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + f"{COLOR}" + " }")
|
|
self.streams_remove_button.setIcon(QIcon(ICON_DELETE))
|
|
self.streams_remove_button.setMaximumWidth(25)
|
|
self.streams_remove_button.setStyleSheet("QPushButton {padding:3px;padding-left:5px;border: none; text-align: left; image-position:right} QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + f"{COLOR}" + " }") #+ f"{backgr_image_del}"
|
|
|
|
self.saveLayerSelection.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
|
#self.saveSurveyPoint.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
|
self.reloadButton.setStyleSheet("QPushButton {text-align: left;} QPushButton:hover { " + f"{COLOR}" + " }")
|
|
self.closeButton.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
|
|
|
|
|
self.sendModeButton.setStyleSheet("QPushButton {padding: 10px; border: 0px; " + f"color: rgb{str(SPECKLE_COLOR)};"+ "} QPushButton:hover { " + "}" )
|
|
self.sendModeButton.setIcon(QIcon(ICON_SEND_BLUE))
|
|
|
|
self.receiveModeButton.setFlat(True)
|
|
self.receiveModeButton.setStyleSheet("QPushButton {padding: 10px; border: 0px;}"+ "QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + "}" )
|
|
self.receiveModeButton.setIcon(QIcon(ICON_RECEIVE_BLACK))
|
|
|
|
self.runButton.setStyleSheet("QPushButton {color: white;border: 0px;border-radius: 17px;padding: 10px;"+ f"{BACKGR_COLOR}" + "} QPushButton:hover { "+ f"{BACKGR_COLOR_LIGHT}" + " }")
|
|
#self.runButton.setGeometry(0, 0, 150, 30)
|
|
self.runButton.setMaximumWidth(200)
|
|
self.runButton.setIcon(QIcon(ICON_SEND))
|
|
|
|
# insert checkbox
|
|
l = self.verticalLayout
|
|
#l_item = None
|
|
|
|
#for i in reversed(range(self.verticalLayout.count())):
|
|
# l_item = self.verticalLayout.itemAt(i).widget()
|
|
|
|
# add row with "experimental" checkbox
|
|
r'''
|
|
box = QWidget()
|
|
box.layout = QHBoxLayout(box)
|
|
btn = QtWidgets.QCheckBox("Send/receive in the background (experimental!)")
|
|
btn.setStyleSheet("QPushButton {color: black; border: 0px;padding: 0px;height: 40px;text-align: left;}")
|
|
box.layout.addWidget(btn)
|
|
box.layout.setContentsMargins(65, 0, 0, 0)
|
|
self.formLayout.insertRow(10,box)
|
|
self.experimental = btn
|
|
self.experimental.setChecked(True)
|
|
'''
|
|
|
|
|
|
def runSetup(self, plugin):
|
|
|
|
#self.addDataStorage(plugin)
|
|
self.addLabel(plugin)
|
|
self.addProps(plugin)
|
|
#self.createMappingDialog()
|
|
|
|
def addProps(self, plugin):
|
|
|
|
# add widgets that will only show on event trigger
|
|
logWidget = LogWidget(parent=self)
|
|
self.layout().addWidget(logWidget)
|
|
self.msgLog = logWidget
|
|
self.msgLog.dockwidget = self
|
|
|
|
self.msgLog.active_account = plugin.dataStorage.active_account
|
|
self.msgLog.speckle_version = plugin.version
|
|
|
|
# add Transforms button
|
|
r'''
|
|
box = QWidget()
|
|
box.layout = QHBoxLayout(box)
|
|
btn = QtWidgets.QPushButton("Apply transformations on Send")
|
|
btn.setFlat(True)
|
|
btn.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
|
box.layout.addWidget(btn)
|
|
box.layout.setContentsMargins(65, 0, 0, 0)
|
|
self.formLayout.insertRow(9,box)
|
|
self.setMapping = btn
|
|
'''
|
|
|
|
self.setMapping.setFlat(True)
|
|
self.setMapping.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
|
|
|
self.crsSettings.setFlat(True)
|
|
self.crsSettings.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
|
|
|
def addDataStorage(self, plugin):
|
|
self.dataStorage = plugin.dataStorage
|
|
self.dataStorage.project = plugin.qgis_project
|
|
|
|
def createMappingDialog(self):
|
|
#root = self.dataStorage.project.layerTreeRoot()
|
|
#self.dataStorage.all_layers = getAllLayers(root)
|
|
|
|
if self.mappingSendDialog is None:
|
|
self.mappingSendDialog = MappingSendDialog(None)
|
|
self.mappingSendDialog.dataStorage = self.dataStorage
|
|
|
|
self.mappingSendDialog.runSetup()
|
|
|
|
def showMappingDialog(self):
|
|
# updata DataStorage
|
|
self.mappingSendDialog.runSetup()
|
|
self.mappingSendDialog.show()
|
|
|
|
def addLabel(self, plugin):
|
|
try:
|
|
exitIcon = QPixmap(ICON_LOGO)
|
|
#scaledExitIcon = exitIcon.scaled(QtCore.QSize(100, 31))
|
|
exitActIcon = QIcon(exitIcon)
|
|
|
|
# create a label
|
|
text_label = QtWidgets.QPushButton(" for QGIS")
|
|
text_label.setStyleSheet("border: 0px;"
|
|
"color: white;"
|
|
f"{BACKGR_COLOR}"
|
|
"top-margin: 40 px;"
|
|
"padding: 10px;"
|
|
"padding-left: 20px;"
|
|
"font-size: 15px;"
|
|
"height: 30px;"
|
|
"text-align: left;"
|
|
)
|
|
text_label.setIcon(exitActIcon)
|
|
text_label.setIconSize(QtCore.QSize(300, 93))
|
|
text_label.setMinimumSize(QtCore.QSize(100, 40))
|
|
text_label.setMaximumWidth(200)
|
|
|
|
version = ""
|
|
try:
|
|
if isinstance(plugin.version, str): version = str(plugin.version)
|
|
except: pass
|
|
|
|
|
|
version_label = QtWidgets.QPushButton(version)
|
|
version_label.setStyleSheet("border: 0px;"
|
|
"color: white;"
|
|
f"{BACKGR_COLOR}"
|
|
"padding-top: 15px;"
|
|
"padding-left: 0px;"
|
|
"margin-left: 0px;"
|
|
"font-size: 10px;"
|
|
"height: 30px;"
|
|
"text-align: left;"
|
|
)
|
|
|
|
widget = QWidget()
|
|
widget.setStyleSheet(f"{BACKGR_COLOR}")
|
|
connect_box = QHBoxLayout(widget)
|
|
connect_box.addWidget(text_label) #, alignment=Qt.AlignCenter)
|
|
connect_box.addWidget(version_label)
|
|
connect_box.setContentsMargins(0, 0, 0, 0)
|
|
self.setTitleBarWidget(widget)
|
|
except Exception as e:
|
|
logToUser(e)
|
|
|
|
def resizeEvent(self, event):
|
|
try:
|
|
#print("resize")
|
|
QtWidgets.QDockWidget.resizeEvent(self, event)
|
|
if self.msgLog.size().height() != 0: # visible
|
|
self.msgLog.setGeometry(0, 0, self.msgLog.parentWidget.frameSize().width(), self.msgLog.parentWidget.frameSize().height()) #.resize(self.frameSize().width(), self.frameSize().height())
|
|
except Exception as e:
|
|
#logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def clearDropdown(self):
|
|
try:
|
|
#self.streamIdField.clear()
|
|
self.streamBranchDropdown.clear()
|
|
self.commitDropdown.clear()
|
|
#self.layerSendModeDropdown.clear()
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def reloadDialogUI(self, plugin):
|
|
try:
|
|
|
|
#logToUser("long errror something something msg1", level=2, plugin= plugin)
|
|
|
|
self.clearDropdown()
|
|
self.populateUI(plugin)
|
|
self.enableElements(plugin)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
|
|
def run(self, plugin):
|
|
try:
|
|
# Setup events on first load only!
|
|
self.setupOnFirstLoad(plugin)
|
|
# Connect streams section events
|
|
self.completeStreamSection(plugin)
|
|
# Populate the UI dropdowns
|
|
self.populateUI(plugin)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def closeEvent(self, event):
|
|
try:
|
|
self.closingPlugin.emit()
|
|
event.accept()
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def addMsg(self, text:str, level:int, url:str, blue:bool):
|
|
self.msgLog.addButton(text, level, url, blue)
|
|
|
|
def setupOnFirstLoad(self, plugin):
|
|
try:
|
|
|
|
self.msgLog.sendMessage.connect(self.addMsg)
|
|
self.setMapping.clicked.connect(self.showMappingDialog)
|
|
|
|
self.streams_add_button.clicked.connect( plugin.onStreamAddButtonClicked )
|
|
self.reloadButton.clicked.connect(lambda: self.refreshClicked(plugin))
|
|
self.closeButton.clicked.connect(lambda: self.closeClicked(plugin))
|
|
|
|
self.crsSettings.clicked.connect(self.customCRSDialogCreate)
|
|
#self.saveSurveyPoint.clicked.connect(plugin.set_survey_point)
|
|
|
|
self.sendModeButton.clicked.connect(lambda: self.setSendMode(plugin))
|
|
self.layerSendModeDropdown.currentIndexChanged.connect( lambda: self.layerSendModeChange(plugin) )
|
|
self.receiveModeButton.clicked.connect(lambda: self.setReceiveMode(plugin))
|
|
|
|
self.streamBranchDropdown.currentIndexChanged.connect( lambda: self.runBtnStatusChanged(plugin) )
|
|
self.commitDropdown.currentIndexChanged.connect( lambda: self.runBtnStatusChanged(plugin) )
|
|
|
|
self.closingPlugin.connect(plugin.onClosePlugin)
|
|
return
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def refreshClicked(self, plugin):
|
|
try:
|
|
try:
|
|
metrics.track("Connector Action", plugin.dataStorage.active_account, {"name": "Refresh", "connector_version": str(plugin.version)})
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=plugin.dockwidget )
|
|
|
|
plugin.reloadUI()
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def closeClicked(self, plugin):
|
|
try:
|
|
try:
|
|
metrics.track("Connector Action", plugin.dataStorage.active_account, {"name": "Close", "connector_version": str(plugin.version)})
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=plugin.dockwidget )
|
|
|
|
plugin.onClosePlugin()
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def setSendMode(self, plugin):
|
|
try:
|
|
plugin.btnAction = 0 # send
|
|
color = f"color: rgb{str(SPECKLE_COLOR)};"
|
|
self.sendModeButton.setStyleSheet("border: 0px;"
|
|
f"color: rgb{str(SPECKLE_COLOR)};"
|
|
"padding: 10px;")
|
|
self.sendModeButton.setIcon(QIcon(ICON_SEND_BLUE))
|
|
self.sendModeButton.setFlat(False)
|
|
self.receiveModeButton.setFlat(True)
|
|
self.receiveModeButton.setStyleSheet("QPushButton {border: 0px; color: black; padding: 10px; } QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + " };")
|
|
self.receiveModeButton.setIcon(QIcon(ICON_RECEIVE_BLACK))
|
|
#self.receiveModeButton.setFlat(True)
|
|
self.runButton.setProperty("text", " SEND")
|
|
self.runButton.setIcon(QIcon(ICON_SEND))
|
|
|
|
# enable sections only if in "saved streams" mode
|
|
if self.layerSendModeDropdown.currentIndex() == 1: self.layersWidget.setEnabled(True)
|
|
#if self.layerSendModeDropdown.currentIndex() == 1:
|
|
self.saveLayerSelection.setEnabled(True)
|
|
self.commitLabel.setEnabled(False)
|
|
self.commitDropdown.setEnabled(False)
|
|
self.messageLabel.setEnabled(True)
|
|
self.messageInput.setEnabled(True)
|
|
self.layerSendModeDropdown.setEnabled(True)
|
|
self.setMapping.setEnabled(True)
|
|
|
|
self.runBtnStatusChanged(plugin)
|
|
return
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def setReceiveMode(self, plugin):
|
|
try:
|
|
plugin.btnAction = 1 # receive
|
|
color = f"color: rgb{str(SPECKLE_COLOR)};"
|
|
self.receiveModeButton.setStyleSheet("border: 0px;"
|
|
f"color: rgb{str(SPECKLE_COLOR)};"
|
|
"padding: 10px;")
|
|
self.sendModeButton.setIcon(QIcon(ICON_SEND_BLACK))
|
|
self.sendModeButton.setStyleSheet("QPushButton {border: 0px; color: black; padding: 10px;} QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + " };")
|
|
self.receiveModeButton.setIcon(QIcon(ICON_RECEIVE_BLUE))
|
|
self.sendModeButton.setFlat(True)
|
|
self.receiveModeButton.setFlat(False)
|
|
#self.sendModeButton.setFlat(True)
|
|
self.runButton.setProperty("text", " RECEIVE")
|
|
self.runButton.setIcon(QIcon(ICON_RECEIVE))
|
|
#self.layerSendModeChange(plugin, 1)
|
|
self.commitLabel.setEnabled(True)
|
|
self.commitDropdown.setEnabled(True)
|
|
self.layersWidget.setEnabled(False)
|
|
self.messageLabel.setEnabled(False)
|
|
self.messageInput.setEnabled(False)
|
|
self.saveLayerSelection.setEnabled(False)
|
|
self.layerSendModeDropdown.setEnabled(False)
|
|
self.setMapping.setEnabled(False)
|
|
|
|
self.runBtnStatusChanged(plugin)
|
|
return
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def completeStreamSection(self, plugin):
|
|
try:
|
|
self.streams_remove_button.clicked.connect( lambda: self.onStreamRemoveButtonClicked(plugin) )
|
|
self.streamList.currentIndexChanged.connect( lambda: self.onActiveStreamChanged(plugin) )
|
|
self.streamBranchDropdown.currentIndexChanged.connect( lambda: self.populateActiveCommitDropdown(plugin) )
|
|
return
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def populateUI(self, plugin):
|
|
try:
|
|
|
|
self.populateLayerSendModeDropdown()
|
|
self.populateProjectStreams(plugin)
|
|
|
|
self.runBtnStatusChanged(plugin)
|
|
self.runButton.setEnabled(False)
|
|
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def runBtnStatusChanged(self, plugin):
|
|
try:
|
|
commitStr = str(self.commitDropdown.currentText())
|
|
branchStr = str(self.streamBranchDropdown.currentText())
|
|
|
|
if plugin.btnAction == 1: # on receive
|
|
if commitStr == "":
|
|
self.runButton.setEnabled(False)
|
|
else:
|
|
self.runButton.setEnabled(True)
|
|
|
|
if plugin.btnAction == 0: # on send
|
|
if branchStr == "":
|
|
self.runButton.setEnabled(False)
|
|
elif self.layerSendModeDropdown.currentIndex() == 1 and len(plugin.dataStorage.current_layers) == 0: # saved layers; but the list is empty
|
|
self.runButton.setEnabled(False)
|
|
else:
|
|
self.runButton.setEnabled(True)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
|
|
def layerSendModeChange(self, plugin, runMode = None):
|
|
try:
|
|
if self.layerSendModeDropdown.currentIndex() == 0 or runMode == 1: # by manual selection OR receive mode
|
|
#self.current_layers = []
|
|
#self.dataStorage.current_layers = []
|
|
self.layersWidget.setEnabled(False)
|
|
#self.saveLayerSelection.setEnabled(False)
|
|
|
|
elif self.layerSendModeDropdown.currentIndex() == 1 and (runMode == 0 or runMode is None): # by saved AND when Send mode
|
|
self.layersWidget.setEnabled(True)
|
|
#self.saveLayerSelection.setEnabled(True)
|
|
|
|
branchStr = str(self.streamBranchDropdown.currentText())
|
|
if self.layerSendModeDropdown.currentIndex() == 0:
|
|
if branchStr == "": self.runButton.setEnabled(False) # by manual selection
|
|
else: self.runButton.setEnabled(True) # by manual selection
|
|
elif self.layerSendModeDropdown.currentIndex() == 1: self.runBtnStatusChanged(plugin) # by saved
|
|
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def populateSavedLayerDropdown(self, plugin):
|
|
|
|
try:
|
|
print(self.dataStorage.saved_layers)
|
|
if not self: return
|
|
self.layersWidget.clear()
|
|
|
|
self.dataStorage.current_layers.clear()
|
|
layers = self.dataStorage.saved_layers
|
|
print(layers)
|
|
if not layers: return
|
|
|
|
for i, layer in enumerate(layers):
|
|
self.dataStorage.current_layers.append(layer)
|
|
listItem = self.fillLayerList(layer[0], layer[2])
|
|
self.layersWidget.addItem(listItem)
|
|
|
|
self.layersWidget.setIconSize(QtCore.QSize(20, 20))
|
|
self.runBtnStatusChanged(plugin)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def populateSelectedLayerDropdown(self, plugin):
|
|
|
|
try:
|
|
if not self: return
|
|
self.layersWidget.clear()
|
|
|
|
for layer_tuple in plugin.dataStorage.current_layers:
|
|
listItem = self.fillLayerList(layer_tuple[0], layer_tuple[2])
|
|
self.layersWidget.addItem(listItem)
|
|
|
|
self.layersWidget.setIconSize(QtCore.QSize(20, 20))
|
|
self.runBtnStatusChanged(plugin)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def fillLayerList(self, layer, layerType = "generic"):
|
|
try:
|
|
icon_xxl = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", " size-xxl.png")
|
|
listItem = QListWidgetItem(layer.name())
|
|
|
|
try: # if QGIS
|
|
from qgis.core import QgsVectorLayer, QgsRasterLayer, QgsIconUtils
|
|
|
|
if isinstance(layer, QgsRasterLayer) and layer.width()*layer.height() > 1000000:
|
|
listItem.setIcon(QIcon(icon_xxl))
|
|
|
|
elif isinstance(layer, QgsVectorLayer) and layer.featureCount() > 20000:
|
|
listItem.setIcon(QIcon(icon_xxl))
|
|
else:
|
|
from qgis.core import QgsIconUtils
|
|
icon = QgsIconUtils().iconForLayer(layer)
|
|
listItem.setIcon(icon)
|
|
print(icon)
|
|
except Exception as e:
|
|
print("e")
|
|
icons = {
|
|
"generic": ICON_GENERIC,
|
|
"polygon": ICON_POLYGON,
|
|
"point": ICON_POINT,
|
|
"line": ICON_LINE,
|
|
"raster": ICON_RASTER,
|
|
}
|
|
icon = QIcon(icons[layerType])
|
|
listItem.setIcon(icon)
|
|
|
|
return listItem
|
|
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
|
|
def enableElements(self, plugin):
|
|
try:
|
|
self.sendModeButton.setEnabled(plugin.is_setup)
|
|
self.receiveModeButton.setEnabled(plugin.is_setup)
|
|
self.runButton.setEnabled(plugin.is_setup)
|
|
self.streams_add_button.setEnabled(plugin.is_setup)
|
|
if plugin.is_setup is False: self.streams_remove_button.setEnabled(plugin.is_setup)
|
|
self.streamBranchDropdown.setEnabled(plugin.is_setup)
|
|
self.layerSendModeDropdown.setEnabled(plugin.is_setup)
|
|
self.commitLabel.setEnabled(False)
|
|
self.commitDropdown.setEnabled(False)
|
|
self.show()
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def customCRSDialogCreate(self):
|
|
try:
|
|
self.custom_crs_modal = CustomCRSDialog(None)
|
|
self.custom_crs_modal.dataStorage = self.dataStorage
|
|
self.custom_crs_modal.dialog_button_box.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.customCRSCreate)
|
|
#self.custom_crs_modal.handleBranchCreate.connect(self.handleBranchCreate)
|
|
self.custom_crs_modal.show()
|
|
#self.custom_crs_modal.populateSurveyPoint()
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
|
|
def customCRSApply(self):
|
|
index = self.custom_crs_modal.modeDropdown.currentIndex()
|
|
if index == 0: #create custom CRS
|
|
self.customCRSCreate()
|
|
if index == 1:
|
|
self.crsOffsetsApply()
|
|
|
|
def crsOffsetsApply(self):
|
|
try:
|
|
from speckle.utils.project_vars import set_crs_offsets_rotation
|
|
|
|
if float(self.custom_crs_modal.offsetX.text()) is not None and float(self.custom_crs_modal.offsetY.text()) is not None:
|
|
self.dataStorage.crs_offset_x = float(self.custom_crs_modal.offsetX.text())
|
|
self.dataStorage.crs_offset_y = float(self.custom_crs_modal.offsetY.text())
|
|
if float(self.custom_crs_modal.rotation.text()) is not None:
|
|
self.dataStorage.crs_rotation = float(self.custom_crs_modal.rotation.text())
|
|
set_crs_offsets_rotation(self.dataStorage, self)
|
|
self.custom_crs_modal.close()
|
|
except: pass
|
|
|
|
def customCRSCreate(self):
|
|
try:
|
|
vals =[ str(self.custom_crs_modal.surveyPointLat.text()), str(self.custom_crs_modal.surveyPointLon.text()) ]
|
|
custom_lat, custom_lon = [float(i.replace(" ","")) for i in vals]
|
|
if custom_lat>180 or custom_lat<-180 or custom_lon >180 or custom_lon<-180:
|
|
logToUser("LAT LON values must be within (-180, 180). You can right-click on the canvas location to copy coordinates in WGS 84", level = 1, plugin=self)
|
|
return True
|
|
|
|
from speckle.utils.project_vars import set_survey_point, setProjectReferenceSystem
|
|
self.dataStorage.custom_lat = custom_lat
|
|
self.dataStorage.custom_lon = custom_lon
|
|
set_survey_point(self.dataStorage, self)
|
|
setProjectReferenceSystem(self.dataStorage, self)
|
|
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def populateProjectStreams(self, plugin):
|
|
try:
|
|
from speckle.utils.project_vars import set_project_streams
|
|
if not self: return
|
|
self.streamList.clear()
|
|
for stream in plugin.current_streams:
|
|
self.streamList.addItems(
|
|
[f"Stream not accessible - {stream[0].stream_id}" if stream[1] is None or isinstance(stream[1], SpeckleException) else f"{stream[1].name}, {stream[1].id} | {stream[0].stream_url.split('/streams')[0]}"]
|
|
)
|
|
if len(plugin.current_streams)==0: self.streamList.addItems([""])
|
|
self.streamList.addItems(["Create New Stream"])
|
|
set_project_streams(plugin)
|
|
index = self.streamList.currentIndex()
|
|
if index == -1: self.streams_remove_button.setEnabled(False)
|
|
else: self.streams_remove_button.setEnabled(True)
|
|
|
|
if len(plugin.current_streams)>0: plugin.active_stream = plugin.current_streams[0]
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def onActiveStreamChanged(self, plugin):
|
|
try:
|
|
if not self: return
|
|
index = self.streamList.currentIndex()
|
|
if (len(plugin.current_streams) == 0 and index ==1) or (len(plugin.current_streams)>0 and index == len(plugin.current_streams)):
|
|
self.populateProjectStreams(plugin)
|
|
plugin.onStreamCreateClicked()
|
|
return
|
|
if len(plugin.current_streams) == 0: return
|
|
if index == -1: return
|
|
|
|
try: plugin.active_stream = plugin.current_streams[index]
|
|
except: plugin.active_stream = None
|
|
|
|
self.populateActiveStreamBranchDropdown(plugin)
|
|
self.populateActiveCommitDropdown(plugin)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def populateLayerSendModeDropdown(self):
|
|
if not self: return
|
|
try:
|
|
self.layerSendModeDropdown.clear()
|
|
self.layerSendModeDropdown.addItems(
|
|
["Send selected layers", "Send saved layers"]
|
|
)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def populateActiveStreamBranchDropdown(self, plugin):
|
|
if not self: return
|
|
try:
|
|
if plugin.active_stream is None: return
|
|
self.streamBranchDropdown.clear()
|
|
if isinstance(plugin.active_stream[1], SpeckleException):
|
|
logToUser("Some streams cannot be accessed", level = 1, plugin = self)
|
|
return
|
|
elif plugin.active_stream is None or plugin.active_stream[1] is None or plugin.active_stream[1].branches is None:
|
|
return
|
|
self.streamBranchDropdown.addItems(
|
|
[f"{branch.name}" for branch in plugin.active_stream[1].branches.items]
|
|
)
|
|
self.streamBranchDropdown.addItems(["Create New Branch"])
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|
|
def populateActiveCommitDropdown(self, plugin):
|
|
if not self: return
|
|
try:
|
|
self.commitDropdown.clear()
|
|
if plugin.active_stream is None: return
|
|
branchName = self.streamBranchDropdown.currentText()
|
|
if branchName == "": return
|
|
if branchName == "Create New Branch":
|
|
self.streamBranchDropdown.setCurrentText("main")
|
|
plugin.onBranchCreateClicked()
|
|
return
|
|
branch = None
|
|
if isinstance(plugin.active_stream[1], SpeckleException):
|
|
logToUser("Some streams cannot be accessed", level = 1, plugin = self)
|
|
return
|
|
elif plugin.active_stream[1]:
|
|
for b in plugin.active_stream[1].branches.items:
|
|
if b.name == branchName:
|
|
branch = b
|
|
break
|
|
|
|
self.commitDropdown.addItem("Latest commit from this branch")
|
|
self.commitDropdown.addItems(
|
|
[f"{commit.id}"+ " | " + f"{commit.message}" for commit in branch.commits.items]
|
|
)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
print(str(e) + "::" + str(inspect.stack()[0][3]))
|
|
return
|
|
|
|
def onStreamRemoveButtonClicked(self, plugin):
|
|
try:
|
|
from speckle.utils.project_vars import set_project_streams
|
|
if not self: return
|
|
index = self.streamList.currentIndex()
|
|
if len(plugin.current_streams) > 0: plugin.current_streams.pop(index)
|
|
plugin.active_stream = None
|
|
self.streamBranchDropdown.clear()
|
|
self.commitDropdown.clear()
|
|
#self.streamIdField.setText("")
|
|
|
|
set_project_streams(plugin)
|
|
self.populateProjectStreams(plugin)
|
|
except Exception as e:
|
|
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
|
return
|
|
|