start
@@ -0,0 +1 @@
|
||||
*.pyc
|
||||
@@ -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
|
||||
@@ -1 +1,3 @@
|
||||
# PyQt-UI
|
||||
# pyqt_ui
|
||||
|
||||
Python-based Qt UI for Speckle connectors
|
||||
@@ -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
|
||||
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 400 B |
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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")
|
||||
|
||||