This commit is contained in:
KatKatKateryna
2023-06-13 17:55:56 +01:00
parent 94487ce8ea
commit 4f2b1a5545
27 changed files with 2455 additions and 1 deletions
+1
View File
@@ -0,0 +1 @@
*.pyc
+152
View File
@@ -0,0 +1,152 @@
import threading
import time
from typing import Any, List
from qgis.PyQt import QtCore
from qgis.PyQt.QtCore import QCoreApplication, QSettings, Qt, pyqtSignal, QTranslator, QRect, QObject
from qgis.PyQt.QtWidgets import QAction, QDockWidget, QVBoxLayout, QWidget, QPushButton
from qgis.PyQt import QtWidgets
from qgis.PyQt.QtGui import QPainter
import webbrowser
from specklepy.logging import metrics
from specklepy.api.credentials import Account
import inspect
SPECKLE_COLOR = (59,130,246)
SPECKLE_COLOR_LIGHT = (69,140,255)
BACKGR_COLOR = f"background-color: rgb{str(SPECKLE_COLOR)};"
BACKGR_COLOR_LIGHT = f"background-color: rgb{str(SPECKLE_COLOR_LIGHT)};"
BACKGR_COLOR_GREY = f"background-color: Gainsboro;"
class LogWidget(QWidget):
msgs: List[str] = []
used_btns: List[int] = []
btns: List[QPushButton]
max_msg: int
sendMessage = pyqtSignal(str, int, str, bool)
active_account: Account
speckle_version: str
dockwidget: Any
# constructor
def __init__(self, parent=None):
super(LogWidget, self).__init__(parent)
print("start LogWidget")
self.parentWidget = parent
print(self.parentWidget)
self.max_msg = 10
# create a temporary floating button
width = 0 #parent.frameSize().width()
height = 0 # parent.frameSize().height()
self.setAttribute(QtCore.Qt.WA_StyledBackground, True)
self.setStyleSheet("background-color: rgba(250,250,250,80);")
self.layout = QVBoxLayout(self)
self.layout.setContentsMargins(0, 60, 10, 20)
self.layout.setAlignment(Qt.AlignBottom)
self.setGeometry(0, 0, width, height)
# generate 100 buttons to use later
self.btns = []
for i in range(self.max_msg):
button = QPushButton(f"👌 Error") # to '{streamName}' Sent , v
button.setStyleSheet("QPushButton {color: black; border: 0px;border-radius: 17px;padding: 20px;height: 40px;text-align: left;"+ f"{BACKGR_COLOR_GREY}" + "}")
button.clicked.connect(lambda: self.openLink())
button.clicked.connect(lambda: self.hide())
self.btns.append(button)
self.hide()
# overriding the mouseReleaseEvent method
def mouseReleaseEvent(self, event):
print("Mouse Release Event")
self.hide()
#self.parentWidget.hideError()
def hide(self):
self.setGeometry(0, 0, 0, 0)
# remove all buttons
for i in reversed(range(self.layout.count())):
self.layout.itemAt(i).widget().setParent(None)
# remove list of used btns
self.used_btns.clear()
self.msgs.clear()
def addButton(self, text: str = "something went wrong", level: int = 2, url = "", blue = False):
print("Add button")
self.setGeometry(0, 0, self.parentWidget.frameSize().width(), self.parentWidget.frameSize().height())
# find index of the first unused button
btn, index = self.getNextBtn()
btn.setAccessibleName(url)
if url != "":
btn.setStyleSheet("QPushButton {color: white;border: 0px;border-radius: 17px;padding: 20px;height: 40px;text-align: left;"+ f"{BACKGR_COLOR}" + "} QPushButton:hover { "+ f"{BACKGR_COLOR_LIGHT}" + " }")
else:
if blue is False:
btn.setStyleSheet("QPushButton {color: black; border: 0px;border-radius: 17px;padding: 20px;height: 40px;text-align: left;"+ f"{BACKGR_COLOR_GREY}" + "}")
else:
btn.setStyleSheet("QPushButton {color: white;border: 0px;border-radius: 17px;padding: 20px;height: 40px;text-align: left;"+ f"{BACKGR_COLOR}" + "}")
btn.setText(text)
self.resizeToText(btn)
#btn.resize(btn.sizeHint())
self.layout.addWidget(btn) #, alignment=Qt.AlignCenter)
self.msgs.append(text)
self.used_btns.append(1)
def openLink(self, url = ""):
try:
btn = self.sender()
url = btn.accessibleName()
if url == "": return
webbrowser.open(url, new=0, autoraise=True)
try:
metrics.track("Connector Action", self.dataStorage.active_account, {"name": "Open In Web", "connector_version": str(self.speckle_version)})
except:
pass
self.hide()
except Exception as e:
pass #logger.logToUser(str(e), level=2, func = inspect.stack()[0][3])
def getNextBtn(self):
index = len(self.used_btns) # get the next "free" button
if index >= len(self.btns):
# remove first button
self.layout.itemAt(0).widget().setParent(None)
self.used_btns.clear()
index = 0
btn = self.btns[index]
return btn, index
def resizeToText(self, btn):
try:
text = btn.text()
#if len(text.split("\n"))>2:
height = len(text.split("\n"))*25 + 40
btn.setMinimumHeight(height)
return btn
except Exception as e:
print(e)
return btn
+3 -1
View File
@@ -1 +1,3 @@
# PyQt-UI
# pyqt_ui
Python-based Qt UI for Speckle connectors
+722
View File
@@ -0,0 +1,722 @@
# -*- coding: utf-8 -*-
"""
/***************************************************************************
SpeckleQGISDialog
A QGIS plugin
SpeckleQGIS Description
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2021-08-04
git sha : $Format:%H$
copyright : (C) 2021 by Speckle Systems
email : alan@speckle.systems
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
import inspect
import os
import threading
from pyqt_ui.widget_transforms import MappingSendDialog
from speckle.converter.layers import getAllLayers, getLayers
from speckle.DataStorage import DataStorage
from specklepy.objects.GIS.layers import RasterLayer, VectorLayer
from pyqt_ui.LogWidget import LogWidget
from pyqt_ui.logger import logToUser
#from speckle_qgis import SpeckleQGIS
import pyqt_ui.dockwidget_main
from qgis.core import Qgis, QgsProject, QgsFields, QgsSingleSymbolRenderer, QgsLayerTreeGroup, QgsVectorLayer, QgsRasterLayer, QgsIconUtils
from specklepy.logging.exceptions import (SpeckleException, GraphQLException)
from qgis.PyQt import QtWidgets, uic
from qgis.PyQt import QtGui
from qgis.PyQt.QtGui import QIcon, QPixmap
from qgis.PyQt.QtWidgets import QCheckBox, QListWidgetItem, QAction, QDockWidget, QVBoxLayout, QHBoxLayout, QWidget, QLabel
from qgis.PyQt import QtCore
from qgis.PyQt.QtCore import pyqtSignal, Qt
from speckle.utils.panel_logging import logger
from specklepy.api.credentials import get_local_accounts
from specklepy.api.wrapper import StreamWrapper
from specklepy.api.client import SpeckleClient
from specklepy.logging import metrics
from speckle.utils.validation import tryGetStream
# 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", "speckle_qgis_dialog_base.ui") )
)
COLOR_HIGHLIGHT = (210,210,210)
SPECKLE_COLOR = (59,130,246)
SPECKLE_COLOR_LIGHT = (69,140,255)
ICON_LOGO = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "logo-slab-white@0.5x.png")
ICON_SEARCH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "magnify.png")
ICON_DELETE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "delete.png")
ICON_DELETE_BLUE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "delete-blue.png")
ICON_SEND = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "cube-send.png")
ICON_RECEIVE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "cube-receive.png")
ICON_SEND_BLACK = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "cube-send-black.png")
ICON_RECEIVE_BLACK = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "cube-receive-black.png")
ICON_SEND_BLUE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "cube-send-blue.png")
ICON_RECEIVE_BLUE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", "cube-receive-blue.png")
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)};"
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
addLayerToGroup = pyqtSignal(str, str, str, str, VectorLayer, QgsFields, list)
addBimLayerToGroup = pyqtSignal(str, str, str, QgsFields, list)
addCadLayerToGroup = pyqtSignal(str, str, str, QgsFields, list)
addRasterLayerToGroup = pyqtSignal(str, str, str, RasterLayer)
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
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 row with "experimental" checkbox
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
def addDataStorage(self, plugin):
self.dataStorage = plugin.dataStorage
self.dataStorage.project = plugin.qgis_project
root = self.dataStorage.project.layerTreeRoot()
self.dataStorage.all_layers = getAllLayers(root)
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):
#t_name = threading.current_thread().getName()
#print(t_name)
self.msgLog.addButton(text, level, url, blue)
def setupOnFirstLoad(self, plugin):
try:
self.runButton.clicked.connect(plugin.onRunButtonClicked)
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.saveSurveyPoint.clicked.connect(plugin.set_survey_point)
self.saveLayerSelection.clicked.connect(lambda: self.populateLayerDropdown(plugin))
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.populateLayerDropdown(plugin, False)
#items = [self.layersWidget.item(x).text() for x in range(self.layersWidget.count())]
self.populateProjectStreams(plugin)
self.populateSurveyPoint(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 populateLayerDropdown(self, plugin, bySelection: bool = True):
try:
if not self: return
from speckle.utils.project_vars import set_project_layer_selection
self.layersWidget.clear()
nameDisplay = []
project = plugin.qgis_project
if bySelection is False: # read from project data
all_layers_ids = [l.id() for l in project.mapLayers().values()]
for layer_tuple in plugin.dataStorage.current_layers:
if layer_tuple[1].id() in all_layers_ids:
listItem = self.fillLayerList(layer_tuple[1])
self.layersWidget.addItem(listItem)
else: # read selected layers
# Fetch selected layers
#plugin.current_layers = []
self.dataStorage.current_layers.clear()
layers = getLayers(plugin, bySelection) # List[QgsLayerTreeNode]
for i, layer in enumerate(layers):
#plugin.current_layers.append((layer.name(), layer))
self.dataStorage.current_layers.append((layer.name(), layer))
listItem = self.fillLayerList(layer)
self.layersWidget.addItem(listItem)
set_project_layer_selection(plugin)
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):
try:
icon_xxl = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img", " size-xxl.png")
listItem = QListWidgetItem(layer.name())
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:
icon = QgsIconUtils().iconForLayer(layer)
listItem.setIcon(icon)
return listItem
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
return
def populateSurveyPoint(self, plugin):
if not self:
return
try:
self.surveyPointLat.clear()
self.surveyPointLat.setText(str(plugin.lat))
self.surveyPointLon.clear()
self.surveyPointLon.setText(str(plugin.lon))
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 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
print(branch)
#if len(branch.commits.items)>0:
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
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

+72
View File
@@ -0,0 +1,72 @@
import qgis.PyQt
from qgis.PyQt.QtWidgets import QMainWindow, QMessageBox, QPushButton, QPushButton, QLabel, QVBoxLayout, QWidget
from qgis.PyQt import QtCore
from plugin_utils.helpers import splitTextIntoLines
def logToUser(msg: str, func=None, level: int = 2, plugin = None, url = "", blue = False):
print("Log to user")
msg = str(msg)
dockwidget = plugin
try:
if url == "" and blue is False: # only for info messages
msg = addLevelSymbol(msg, level)
if func is not None:
msg += "::" + str(func)
from speckle.utils.panel_logging import logger
logger.writeToLog(msg, level)
if dockwidget is None: return
new_msg = splitTextIntoLines(msg)
dockwidget.msgLog.sendMessage.emit(new_msg, level, url, blue)
except Exception as e: print(e); return
def addLevelSymbol(msg: str, level: int):
if level == 0: msg = "🛈 " + msg
if level == 1: msg = "⚠️ " + msg
if level == 2: msg = "" + msg
return msg
def displayUserMsg(msg: str, func=None, level: int = 2):
try:
window = createWindow(msg, func, level)
window.exec_()
except Exception as e: print(e)
def createWindow(msg_old: str, func=None, level: int = 2):
print("Create window")
window = None
try:
# https://www.techwithtim.net/tutorials/pyqt5-tutorial/messageboxes/
window = QMessageBox()
msg = ""
if len(msg_old)>80:
msg = splitTextIntoLines(msg_old)
else:
msg = msg_old
window.setWindowFlag(QtCore.Qt.WindowStaysOnTopHint)
if level==0:
window.setWindowTitle("Info (Speckle)")
window.setIcon(QMessageBox.Icon.Information)
if level==1:
window.setWindowTitle("Warning (Speckle)")
window.setIcon(QMessageBox.Icon.Warning)
elif level==2:
window.setWindowTitle("Error (Speckle)")
window.setIcon(QMessageBox.Icon.Critical)
window.setFixedWidth(200)
if func is not None:
window.setText(str(msg + "\n" + str(func)))
else:
window.setText(str(msg))
print(window)
except Exception as e: print(e)
return window
+87
View File
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddStreamDialog</class>
<widget class="QWidget" name="AddStreamDialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<layout class="QFormLayout" name="search_form">
<item row="1" column="0">
<widget class="QLabel" name="search_label">
<property name="text">
<string>Search Stream by name or URL</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="search_text_field"/>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="search_button">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="accounts_dropdown"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="accounts_label">
<property name="text">
<string>Account</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="search_results_label">
<property name="text">
<string>Search Results</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="search_results_list">
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="dialog_button_box">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CreateStreamDialog</class>
<widget class="QWidget" name="AddBranchDialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<layout class="QFormLayout" name="search_form">
<item row="0" column="0">
<widget class="QLabel" name="name_label">
<property name="text">
<string>Branch Name</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="name_label">
<property name="text">
<string>Description</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="name_field"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="description_field"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="dialog_button_box">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+85
View File
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CreateStreamDialog</class>
<widget class="QWidget" name="AddStreamDialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<layout class="QFormLayout" name="search_form">
<item row="0" column="0">
<widget class="QLabel" name="accounts_label">
<property name="text">
<string>Account</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="name_label">
<property name="text">
<string>Stream Name</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="name_label">
<property name="text">
<string>Description</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="name_label">
<property name="text">
<string>Public</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="accounts_dropdown"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="name_field"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="description_field"/>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="public_toggle"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="dialog_button_box">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+329
View File
@@ -0,0 +1,329 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SpeckleQGISDialogBase</class>
<widget class="QDockWidget" name="SpeckleQGISDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>575</width>
<height>651</height>
</rect>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item row="0" column="1">
<layout class="QHBoxLayout" name="streamListButtons">
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="streamListLabel">
<property name="text">
<string>Stream</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="streamListButtons" stretch="20,1">
<item>
<widget class="QComboBox" name="streamList"/>
</item>
<item>
<widget class="QPushButton" name="streams_add_button">
<property name="text">
<string> </string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="streams_remove_button">
<property name="text">
<string> </string>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>10</width>
<height>10</height>
</rect>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="streamBranchLabel">
<property name="text">
<string>Branch</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="streamBranchDropdown"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="commitLabel">
<property name="text">
<string>Commit</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="commitDropdown"/>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
</layout>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="sendModeButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="receiveModeButton">
<property name="text">
<string>Receive</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="layerSendModeDropdown"/>
</item>
<item row="7" column="1">
<widget class="QListWidget" name="layersWidget">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="resizeMode">
<enum>QListView::Fixed</enum>
</property>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
</widget>
</item>
<item row="8" column="1">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="saveLayerSelection">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Save current layer selection</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="0">
<widget class="QLabel" name="messageLabel">
<property name="text">
<string>Message</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="messageInput">
<property name="placeholderText">
<string>Sent XXX objects from QGIS</string>
</property>
</widget>
</item>
<item row="10" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="runButton">
<property name="text">
<string> SEND</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
</spacer>
</item>
</layout>
</item>
<item row="11" column="0">
<widget class="QLabel" name="surveyPointLabel">
<property name="text">
<string>Lat, Lon</string>
</property>
</widget>
</item>
<item row="11" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="surveyPointLat">
<property name="placeholderText">
<string>0.0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="degreeSign">
<property name="text">
<string>°</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="surveyPointLon">
<property name="placeholderText">
<string>0.0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="degreeSign">
<property name="text">
<string>°</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="saveSurveyPoint">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Set as a project center</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="12" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="reloadButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
+42
View File
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StreamListDialog</class>
<widget class="QWidget" name="StreamListDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>70</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+154
View File
@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MappingSendDialog</class>
<widget class="QWidget" name="AddStreamDialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Add custom transformations</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<layout class="QFormLayout" name="form">
<item row="0" column="0">
<widget class="QLabel" name="transform_label">
<property name="text">
<string>Transformation</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="transformDropdown"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="layers_label">
<property name="text">
<string>Layer</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="layerDropdown"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="attr_label">
<property name="text">
<string>Attribute</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="attrDropdown"/>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item >
<widget class="QPushButton" name="addTransform">
<property name="text">
<string>+</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="1">
<widget class="QListWidget" name="transformationsList"/>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item >
<widget class="QPushButton" name="removeTransform">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QLabel" name="elevation_label">
<property name="text">
<string>Elevation layer</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="elevationLayerDropdown"/>
</item>
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,1,1">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
</spacer>
</item>
<item >
<widget class="QPushButton" name="more_info">
<property name="text">
<string>More info</string>
</property>
</widget>
</item >
<item >
<widget class="QPushButton" name="dialog_button_box">
<property name="text">
<string>Ok</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+162
View File
@@ -0,0 +1,162 @@
import inspect
import os
from typing import List, Union
from pyqt_ui.logger import logToUser
import pyqt_ui.dockwidget_main
from qgis.core import Qgis
from speckle.utils.panel_logging import logger
from qgis.PyQt import QtWidgets, uic, QtCore
from qgis.PyQt.QtCore import pyqtSignal
from specklepy.api.models import Stream
from specklepy.api.client import SpeckleClient
from specklepy.logging.exceptions import SpeckleException
from speckle.utils.utils import logger
from specklepy.api.credentials import get_local_accounts #, StreamWrapper
from specklepy.api.wrapper import StreamWrapper
from gql import gql
# 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.join(os.path.dirname(__file__), "ui", "add_stream_modal.ui") )
)
class AddStreamModalDialog(QtWidgets.QWidget, FORM_CLASS):
search_button: QtWidgets.QPushButton = None
search_text_field: QtWidgets.QLineEdit = None
search_results_list: QtWidgets.QListWidget = None
dialog_button_box: QtWidgets.QDialogButtonBox = None
accounts_dropdown: QtWidgets.QComboBox
stream_results: List[Stream] = []
speckle_client: Union[SpeckleClient, None] = None
#Events
handleStreamAdd = pyqtSignal(StreamWrapper)
def __init__(self, parent=None, speckle_client: SpeckleClient = None):
super(AddStreamModalDialog,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)
self.speckle_client = speckle_client
self.setupUi(self)
self.setWindowTitle("Add Speckle stream")
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
self.search_button.clicked.connect(self.onSearchClicked)
self.search_results_list.currentItemChanged.connect( self.searchResultChanged )
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.onOkClicked)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self.onCancelClicked)
self.accounts_dropdown.currentIndexChanged.connect(self.onAccountSelected)
self.populate_accounts_dropdown()
def searchResultChanged(self):
try:
index = self.search_results_list.currentIndex().row()
if index == -1: self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
else: self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onSearchClicked(self):
try:
query = self.search_text_field.text()
sw = None
results = []
if "http" in query and len(query.split("/")) >= 3: # URL
sw = StreamWrapper(query)
stream = sw.get_client().stream.get(sw.stream_id)
if isinstance(stream, Stream): results = [stream]
else: results = []
elif self.speckle_client is not None:
results = self.speckle_client.stream.search(query)
elif self.speckle_client is None:
logToUser(f"Account cannot be authenticated: {self.accounts_dropdown.currentText()}", level = 1, func = inspect.stack()[0][3])
self.stream_results = results
self.populateResultsList(sw)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def populateResultsList(self, sw):
try:
self.search_results_list.clear()
if isinstance(self.stream_results, SpeckleException):
logToUser("Some streams cannot be accessed", level = 1, func = inspect.stack()[0][3])
return
for stream in self.stream_results:
host = ""
if sw is not None:
host = sw.get_account().serverInfo.url
else:
host = self.speckle_client.account.serverInfo.url
if isinstance(stream, SpeckleException):
logToUser("Some streams cannot be accessed", level = 1, func = inspect.stack()[0][3])
else:
self.search_results_list.addItems([
f"{stream.name}, {stream.id} | {host}" #for stream in self.stream_results
])
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onOkClicked(self):
try:
if isinstance(self.stream_results, SpeckleException):
logToUser("Selected stream cannot be accessed: "+ str(self.stream_results.message), level = 1, func = inspect.stack()[0][3])
return
#elif index == -1 or len(self.stream_results) == 0:
# logger.logToUser("Select stream from \"Search Results\". No stream selected", Qgis.Warning)
# return
else:
try:
index = self.search_results_list.currentIndex().row()
stream = self.stream_results[index]
item = self.search_results_list.item(index)
url = item.text().split(" | ")[1] + "/streams/" + item.text().split(", ")[1].split(" | ")[0]
sw = StreamWrapper(url)
#acc = sw.get_account() #get_local_accounts()[self.accounts_dropdown.currentIndex()]
self.handleStreamAdd.emit(sw) #StreamWrapper(f"{acc.serverInfo.url}/streams/{stream.id}?u={acc.userInfo.id}"))
self.close()
except Exception as e:
logToUser("Some streams cannot be accessed: " + str(e), level = 1, func = inspect.stack()[0][3])
return
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onCancelClicked(self):
try:
self.close()
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onAccountSelected(self, index):
try:
account = self.speckle_accounts[index]
self.speckle_client = SpeckleClient(account.serverInfo.url, account.serverInfo.url.startswith("https"))
self.speckle_client.authenticate_with_token(token=account.token)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def populate_accounts_dropdown(self):
try:
# Populate the accounts comboBox
self.speckle_accounts = get_local_accounts()
self.accounts_dropdown.clear()
self.accounts_dropdown.addItems(
[
f"{acc.userInfo.name}, {acc.userInfo.email} | {acc.serverInfo.url}"
for acc in self.speckle_accounts
]
)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
+80
View File
@@ -0,0 +1,80 @@
import inspect
import os
from typing import List, Tuple, Union
from pyqt_ui.logger import logToUser
import pyqt_ui.dockwidget_main
from qgis.core import Qgis
from speckle.utils.panel_logging import logger
from qgis.PyQt import QtWidgets, uic, QtCore
from qgis.PyQt.QtCore import pyqtSignal
from specklepy.api.models import Stream
from specklepy.api.client import SpeckleClient
from specklepy.logging.exceptions import SpeckleException
from speckle.utils.utils import logger
from specklepy.api.credentials import Account, get_local_accounts #, StreamWrapper
from specklepy.api.wrapper import StreamWrapper
from gql import gql
# 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.join(os.path.dirname(__file__), "ui", "create_branch.ui") )
)
class CreateBranchModalDialog(QtWidgets.QWidget, FORM_CLASS):
name_field: QtWidgets.QLineEdit = None
description_field: QtWidgets.QLineEdit = None
dialog_button_box: QtWidgets.QDialogButtonBox = None
speckle_client: Union[SpeckleClient, None] = None
#Events
handleBranchCreate = pyqtSignal(str,str)
def __init__(self, parent=None, speckle_client: SpeckleClient = None):
super(CreateBranchModalDialog,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)
self.speckle_client = speckle_client
self.setupUi(self)
self.setWindowTitle("Create New Branch")
self.name_field.textChanged.connect(self.nameCheck)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.onOkClicked)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self.onCancelClicked)
def nameCheck(self):
try:
if len(self.name_field.text()) >= 3:
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
else:
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
return
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onOkClicked(self):
try:
name = self.name_field.text()
description = self.description_field.text()
self.handleBranchCreate.emit(name, description)
self.close()
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onCancelClicked(self):
try:
self.close()
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onAccountSelected(self, index):
try:
account = self.speckle_accounts[index]
self.speckle_client = SpeckleClient(account.serverInfo.url, account.serverInfo.url.startswith("https"))
self.speckle_client.authenticate_with_token(token=account.token)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
+104
View File
@@ -0,0 +1,104 @@
import inspect
import os
from typing import List, Tuple, Union
from pyqt_ui.logger import logToUser
import pyqt_ui.dockwidget_main
from qgis.core import Qgis
from speckle.utils.panel_logging import logger
from qgis.PyQt import QtWidgets, uic, QtCore
from qgis.PyQt.QtCore import pyqtSignal
from specklepy.api.models import Stream
from specklepy.api.client import SpeckleClient
from specklepy.logging.exceptions import SpeckleException
from speckle.utils.utils import logger
from specklepy.api.credentials import Account, get_local_accounts #, StreamWrapper
from specklepy.api.wrapper import StreamWrapper
from gql import gql
# 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.join(os.path.dirname(__file__), "ui", "create_stream.ui") )
)
class CreateStreamModalDialog(QtWidgets.QWidget, FORM_CLASS):
name_field: QtWidgets.QLineEdit = None
description_field: QtWidgets.QLineEdit = None
dialog_button_box: QtWidgets.QDialogButtonBox = None
accounts_dropdown: QtWidgets.QComboBox
public_toggle: QtWidgets.QCheckBox
speckle_client: Union[SpeckleClient, None] = None
#Events
handleStreamCreate = pyqtSignal(Account, str, str, bool)
def __init__(self, parent=None, speckle_client: SpeckleClient = None):
super(CreateStreamModalDialog,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)
self.speckle_client = speckle_client
self.setupUi(self)
self.setWindowTitle("Create New Stream")
self.name_field.textChanged.connect(self.nameCheck)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.onOkClicked)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self.onCancelClicked)
self.accounts_dropdown.currentIndexChanged.connect(self.onAccountSelected)
self.populate_accounts_dropdown()
def nameCheck(self):
try:
if len(self.name_field.text()) == 0 or len(self.name_field.text()) >= 3:
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
else:
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
return
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onOkClicked(self):
try:
acc = get_local_accounts()[self.accounts_dropdown.currentIndex()]
name = self.name_field.text()
description = self.description_field.text()
public = self.public_toggle.isChecked()
self.handleStreamCreate.emit(acc,name,description,public)
self.close()
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onCancelClicked(self):
try:
#self.handleCancelStreamCreate.emit()
self.close()
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def onAccountSelected(self, index):
try:
account = self.speckle_accounts[index]
self.speckle_client = SpeckleClient(account.serverInfo.url, account.serverInfo.url.startswith("https"))
self.speckle_client.authenticate_with_token(token=account.token)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def populate_accounts_dropdown(self):
try:
# Populate the accounts comboBox
self.speckle_accounts = get_local_accounts()
self.accounts_dropdown.clear()
self.accounts_dropdown.addItems(
[
f"{acc.userInfo.name}, {acc.userInfo.email} | {acc.serverInfo.url}"
for acc in self.speckle_accounts
]
)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
+18
View File
@@ -0,0 +1,18 @@
import os
from qgis.PyQt import QtWidgets, uic
from qgis.PyQt.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.join(os.path.dirname(__file__), "ui", "streamlist_dialog.ui") )
)
class StreamListDialog(QtWidgets.QWidget, FORM_CLASS):
streams_add_button: QtWidgets.QPushButton
streams_reload_button: QtWidgets.QPushButton
streams_remove_button: QtWidgets.QPushButton
def __init__(self, parent=None):
super(StreamListDialog, self).__init__(parent)
self.setupUi(self)
+380
View File
@@ -0,0 +1,380 @@
import inspect
import os
from typing import Any, List, Tuple, Union
from speckle.converter.layers import getAllLayers
from speckle.converter.layers.utils import getElevationLayer, getLayerGeomType
from pyqt_ui.logger import displayUserMsg, logToUser
import pyqt_ui.dockwidget_main
from qgis.core import Qgis, QgsProject, QgsVectorLayer, QgsRasterLayer, QgsIconUtils
from speckle.utils.panel_logging import logger
from qgis.PyQt import QtWidgets, uic, QtCore
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QCheckBox, QListWidgetItem
from qgis.PyQt.QtCore import pyqtSignal
from specklepy.api.models import Stream
from specklepy.api.client import SpeckleClient
from specklepy.logging.exceptions import SpeckleException
from speckle.utils.utils import logger
from specklepy.api.credentials import Account, get_local_accounts #, StreamWrapper
from specklepy.api.wrapper import StreamWrapper
from gql import gql
from specklepy.logging import metrics
from osgeo import gdal
import webbrowser
# 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.join(os.path.dirname(__file__), "ui", "transforms.ui") )
)
class MappingSendDialog(QtWidgets.QWidget, FORM_CLASS):
dialog_button_box: QtWidgets.QPushButton = None
more_info: QtWidgets.QPushButton = None
layerDropdown: QtWidgets.QComboBox
transformDropdown: QtWidgets.QComboBox
addTransform: QtWidgets.QPushButton
removeTransform: QtWidgets.QPushButton
transformationsList: QtWidgets.QListWidget
elevationLayerDropdown: QtWidgets.QComboBox
attrDropdown: QtWidgets.QComboBox
dataStorage: Any = None
#Events
#handleStreamCreate = pyqtSignal(Account, str, str, bool)
def __init__(self, parent=None):
super(MappingSendDialog,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)
self.setupUi(self)
self.setMinimumWidth(600)
#self.dialog_button_box.setMaximumWidth(30)
#self.more_info.setMaximumWidth(30)
#self.setWindowTitle("Add custom transformations")
self.addTransform.setStyleSheet("QPushButton {color: black; padding:3px;padding-left:5px;border: none; } QPushButton:hover { background-color: lightgrey}")
self.removeTransform.setStyleSheet("QPushButton {color: black; padding:3px;padding-left:5px;border: none; } QPushButton:hover { background-color: lightgrey}")
#self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.onOkClicked)
self.addTransform.clicked.connect(self.onAddTransform)
self.removeTransform.clicked.connect(self.onRemoveTransform)
self.transformDropdown.currentIndexChanged.connect(self.populateLayersByTransform)
self.transformDropdown.currentIndexChanged.connect(self.populateAttributesByLayer)
self.layerDropdown.currentIndexChanged.connect(self.populateAttributesByLayer)
self.dialog_button_box.clicked.connect(self.saveElevationLayer)
self.dialog_button_box.clicked.connect(self.onOkClicked)
self.more_info.clicked.connect(self.onMoreInfo)
return
self.speckle_client = speckle_client
self.name_field.textChanged.connect(self.nameCheck)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.onOkClicked)
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self.onCancelClicked)
self.populate_accounts_dropdown()
def runSetup(self):
#get_transformations(self.dataStorage)
self.attr_label.setEnabled(False)
self.attrDropdown.setEnabled(False)
self.populateTransforms()
#self.populateLayers()
self.populateLayersByTransform()
self.populateSavedTransforms()
self.populateSavedElevationLayer()
def populateSavedTransforms(self, dataStorage = None): #, savedTransforms: Union[List, None] = None, getLayer: Union[str, None] = None, getTransform: Union[str, None] = None):
if dataStorage is not None:
self.dataStorage = dataStorage # making sure lists are synced
self.transformationsList.clear()
vals = self.dataStorage.savedTransforms
all_l_names = [l.name() for l in self.dataStorage.all_layers]
for item in vals:
layer_name = item.split(" -> ")[0].split(" (\'")[0]
transform_name = item.split(" -> ")[1]
layer = None
for l in self.dataStorage.all_layers:
if layer_name == l.name():
layer = l
if layer is None:
displayUserMsg(f"Layer \'{layer_name}\' not found in the project.\nTransformation is removed.", level=2)
self.dataStorage.savedTransforms.remove(item)
else:
if transform_name not in self.dataStorage.transformsCatalog:
displayUserMsg(f"Saved transformation \'{transform_name}\' is not valid.\n. Transformation is removed.", level=1)
self.dataStorage.savedTransforms.remove(item)
elif all_l_names.count(layer.name()) > 1:
displayUserMsg(f"Layer name \'{layer.name()}\' is used for more than 1 layer in the project", level=1)
self.dataStorage.savedTransforms.remove(item)
else:
listItem = QListWidgetItem(item)
icon = QgsIconUtils().iconForLayer(layer)
listItem.setIcon(icon)
self.transformationsList.addItem(listItem)
#if self.dataStorage.savedTransforms is not None and isinstance(self.dataStorage.savedTransforms, List):
# for item in self.dataStorage.savedTransforms:
# self.transformationsList.addItem(QListWidgetItem(item))
def onAddTransform(self):
from speckle.utils.project_vars import set_transformations
root = self.dataStorage.project.layerTreeRoot()
self.dataStorage.all_layers = getAllLayers(root)
if len(self.layerDropdown.currentText())>1 and len(self.transformDropdown.currentText())>1:
listItem = str(self.layerDropdown.currentText()) + " -> " + str(self.transformDropdown.currentText())
layer_name = listItem.split(" -> ")[0].split(" (\'")[0]
transform_name = listItem.split(" -> ")[1].lower()
exists = 0
for record in self.dataStorage.savedTransforms:
current_layer_name = record.split(" -> ")[0].split(" (\'")[0]
current_transf_name = record.split(" -> ")[1].lower()
if layer_name == current_layer_name: # in layers
exists +=1
displayUserMsg("Selected layer already has a transformation applied", level=1)
break
if ("elevation" in transform_name and "mesh" in transform_name and "texture" not in transform_name) and transform_name == current_transf_name: # in transforms
exists +=1
displayUserMsg(f"Layer '{current_layer_name}' is already assigned as a 3d elevation", level=1)
break
if exists == 0:
layer = None
for l in self.dataStorage.all_layers:
if layer_name == l.name():
layer = l
if layer is not None:
if "attribute" in transform_name and self.attrDropdown.currentText() != '':
listItem = str(self.layerDropdown.currentText()) + " (\'" + str(self.attrDropdown.currentText()) + "\') -> " + str(self.transformDropdown.currentText())
self.dataStorage.savedTransforms.append(listItem)
self.populateSavedTransforms()
try:
metrics.track("Connector Action", self.dataStorage.active_account, {"name": "Add transformation on Send", "Transformation": listItem.split(" -> ")[1], "connector_version": str(self.dataStorage.plugin_version)})
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3] )
set_transformations(self.dataStorage)
def onRemoveTransform(self):
from speckle.utils.project_vars import set_transformations
if self.transformationsList.currentItem() is not None:
#if len(self.layerDropdown.currentText())>1 and len(self.transformDropdown.currentText())>1:
listItem = self.transformationsList.currentItem().text()
print(listItem)
if listItem in self.dataStorage.savedTransforms:
self.dataStorage.savedTransforms.remove(listItem)
self.populateSavedTransforms()
set_transformations(self.dataStorage)
def onOkClicked(self):
try:
self.close()
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def populateLayers(self):
try:
self.layerDropdown.clear()
root = self.dataStorage.project.layerTreeRoot()
self.dataStorage.all_layers = getAllLayers(root)
for i, layer in enumerate(self.dataStorage.all_layers):
listItem = layer.name()
self.layerDropdown.addItem(listItem)
icon = QgsIconUtils().iconForLayer(layer)
self.layerDropdown.setItemIcon(i, icon)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def populateLayersByTransform(self):
try:
self.layerDropdown.clear()
root = self.dataStorage.project.layerTreeRoot()
self.dataStorage.all_layers = getAllLayers(root)
transform = str(self.transformDropdown.currentText())
layers_dropdown = []
for i, layer in enumerate(self.dataStorage.all_layers):
listItem = None
if "extrude" in transform.lower():
if isinstance(layer, QgsVectorLayer):
geom_type = getLayerGeomType(layer)
if "polygon" in geom_type.lower():
listItem = layer.name()
elif "elevation" in transform.lower():
if isinstance(layer, QgsRasterLayer):
# avoiding tiling layers
ds = gdal.Open(layer.source(), gdal.GA_ReadOnly)
if ds is None:
continue
listItem = layer.name()
if listItem is not None:
layers_dropdown.append(listItem)
self.layerDropdown.addItem(listItem)
icon = QgsIconUtils().iconForLayer(layer)
self.layerDropdown.setItemIcon(len(layers_dropdown)-1, icon)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def populateAttributesByLayer(self):
try:
self.attrDropdown.clear()
root = self.dataStorage.project.layerTreeRoot()
self.dataStorage.all_layers = getAllLayers(root)
layer_name = str(self.layerDropdown.currentText())
transform_name = self.transformDropdown.currentText()
layerForAttributes = None
for i, layer in enumerate(self.dataStorage.all_layers):
if layer_name == layer.name():
if isinstance(layer, QgsVectorLayer):
geom_type = getLayerGeomType(layer)
if "polygon" in geom_type.lower():
layerForAttributes = layer
break
if layerForAttributes is not None and 'attribute' in transform_name:
self.attr_label.setEnabled(True)
self.attrDropdown.setEnabled(True)
if 'ignore' not in transform_name:
self.attrDropdown.addItem('Random height')
for field in layerForAttributes.fields():
field_type = field.type()
if field_type in [2,6,10]:
self.attrDropdown.addItem(str(field.name()))
else:
self.attr_label.setEnabled(False)
self.attrDropdown.setEnabled(False)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def populateTransforms(self):
try:
self.transformDropdown.clear()
for item in self.dataStorage.transformsCatalog:
self.transformDropdown.addItem(item)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def nameCheck(self):
return
try:
if len(self.name_field.text()) == 0 or len(self.name_field.text()) >= 3:
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
else:
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
return
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def populateSavedElevationLayer(self, dataStorage = None): #, savedTransforms: Union[List, None] = None, getLayer: Union[str, None] = None, getTransform: Union[str, None] = None):
try:
if dataStorage is not None:
self.dataStorage = dataStorage # making sure lists are synced
elevationLayer = getElevationLayer(self.dataStorage)
self.elevationLayerDropdown.clear()
root = self.dataStorage.project.layerTreeRoot()
self.dataStorage.all_layers = getAllLayers(root)
self.elevationLayerDropdown.addItem("")
setAsindex = 0
countRaster = 1
for i, layer in enumerate(self.dataStorage.all_layers):
if isinstance(layer, QgsRasterLayer):
# avoiding tiling layers
ds = gdal.Open(layer.source(), gdal.GA_ReadOnly)
if ds is None:
continue
listItem = layer.name()
self.elevationLayerDropdown.addItem(listItem)
icon = QgsIconUtils().iconForLayer(layer)
self.elevationLayerDropdown.setItemIcon(countRaster, icon)
if elevationLayer is not None:
if listItem == elevationLayer.name():
setAsindex = countRaster
countRaster += 1
self.elevationLayerDropdown.setCurrentIndex(setAsindex)
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3])
return
def saveElevationLayer(self):
from speckle.utils.project_vars import set_elevationLayer
root = self.dataStorage.project.layerTreeRoot()
layer = None
if self.dataStorage is None: return
layerName = str(self.elevationLayerDropdown.currentText())
if len(layerName) < 1:
layer = None
else:
self.dataStorage.all_layers = getAllLayers(root)
all_l_names = [l.name() for l in self.dataStorage.all_layers]
for l in self.dataStorage.all_layers:
if layerName == l.name():
layer = l
try:
if all_l_names.count(layer.name()) > 1:
displayUserMsg(f"Layer name \'{layer.name()}\' is used for more than 1 layer in the project", level=1)
layer = None
break
except:
displayUserMsg(f"Layer \'{layer.name()}\' is not found in the project", level=1)
layer = None
break
self.dataStorage.elevationLayer = layer
set_elevationLayer(self.dataStorage)
try:
metrics.track("Connector Action", self.dataStorage.active_account, {"name": "Add transformation on Send", "Transformation": "Set Layer as Elevation", "connector_version": str(self.dataStorage.plugin_version)})
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3] )
def onMoreInfo(self):
webbrowser.open("https://github.com/specklesystems/speckle-qgis/tree/main/speckle/automation/Automation.md")