diff --git a/qt_ui/DataStorage.py b/qt_ui/DataStorage.py index 5615f0d..70ac8e2 100644 --- a/qt_ui/DataStorage.py +++ b/qt_ui/DataStorage.py @@ -5,7 +5,7 @@ import webbrowser try: from specklepy_qt_ui.qt_ui.utils.logger import logToUser -except ModuleNotFoundError: +except ModuleNotFoundError: from speckle.specklepy_qt_ui.qt_ui.utils.logger import logToUser from specklepy.core.api.credentials import get_local_accounts @@ -22,6 +22,7 @@ class DataStorage: currentCRS = None currentUnits = "m" currentOriginalUnits = "" + workspace = "" custom_lat: Optional[float] = None custom_lon: Optional[float] = None diff --git a/qt_ui/mainWindow.py b/qt_ui/mainWindow.py index afafcb1..72c6f8b 100644 --- a/qt_ui/mainWindow.py +++ b/qt_ui/mainWindow.py @@ -40,7 +40,7 @@ import arcpy import inspect # from speckle.speckle_arcgis_new import Speckle -from speckle.speckle.converter.layers import getLayers, getAllProjLayers +from speckle.speckle.converter.layers import getLayersWithStructure, getAllProjLayers from speckle.speckle.utils.panel_logging import logToUser from speckle.specklepy_qt_ui.qt_ui.LogWidget import LogWidget from speckle.specklepy_qt_ui.qt_ui.utils.utils import constructCommitURL @@ -57,6 +57,8 @@ from speckle.specklepy_qt_ui.qt_ui.utils.global_resources import ( ICON_SEARCH, ICON_DELETE, ICON_DELETE_BLUE, + ICON_PIN_ACTIVE, + ICON_PIN_DISABLED, ICON_SEND, ICON_RECEIVE, ICON_SEND_BLACK, @@ -84,6 +86,8 @@ ui_file_path = os.path.join( class SpeckleGISDialog(QMainWindow): + on_top: bool = False + pin_label: QtWidgets.QPushButton closingPlugin = pyqtSignal() streamList: QtWidgets.QComboBox sendModeButton: QtWidgets.QPushButton @@ -217,7 +221,7 @@ class SpeckleGISDialog(QMainWindow): self.runButton.setIcon(QIcon(ICON_SEND)) # insert checkbox - l = self.verticalLayout + # l = self.verticalLayout except Exception as e: logToUser(str(e), level=2, func=inspect.stack()[0][3], plugin=self) @@ -300,16 +304,39 @@ class SpeckleGISDialog(QMainWindow): boxLayout = QHBoxLayout(widget) boxLayout.addWidget(text_label) # , alignment=Qt.AlignCenter) boxLayout.addWidget(version_label) - boxLayout.setContentsMargins(0, 0, 0, 0) + boxLayout.setContentsMargins(0, 0, 30, 0) self.setWindowTitle("SpeckleArcGIS") self.gridLayoutTitleBar.addWidget(widget) # fro QMainWindow # self.setTitleBarWidget(widget) # for dockwidget self.labelWidget = text_label self.labelWidget.setCursor(QCursor(QtCore.Qt.PointingHandCursor)) self.labelWidget.clicked.connect(self.onClickLogo) + + pin_label = QtWidgets.QPushButton("") + pin_label.setIcon(QIcon(ICON_PIN_DISABLED)) + pin_label.setMaximumWidth(25) + # pin_label.setFlat(True) + pin_label.setStyleSheet("QPushButton {border: none;}") + boxLayout.addWidget(pin_label) + pin_label.setCursor(QCursor(QtCore.Qt.PointingHandCursor)) + self.pin_label = pin_label + self.pin_label.clicked.connect(self.pinWindow) + except Exception as e: logToUser(e) + def pinWindow(self): + if self.on_top == True: + self.setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, False) + self.pin_label.setIcon(QIcon(ICON_PIN_DISABLED)) + self.on_top = False + self.show() + else: + self.setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, True) + self.pin_label.setIcon(QIcon(ICON_PIN_ACTIVE)) + self.on_top = True + self.show() + def addDataStorage(self, plugin): self.dataStorage = plugin.dataStorage try: @@ -617,7 +644,7 @@ class SpeckleGISDialog(QMainWindow): self.runButton.setEnabled(False) elif ( self.layerSendModeDropdown.currentIndex() == 1 - and len(plugin.dataStorage.current_layers) == 0 + and len(plugin.dataStorage.saved_layers) == 0 ): # saved layers; but the list is empty self.runButton.setEnabled(False) else: @@ -673,7 +700,7 @@ class SpeckleGISDialog(QMainWindow): all_layers = getAllProjLayers(plugin) if all_layers is None: return - + all_layers_ids = [l.dataSource for l in all_layers] for layer_tuple in plugin.dataStorage.saved_layers: if layer_tuple[1].dataSource in all_layers_ids: @@ -685,16 +712,18 @@ class SpeckleGISDialog(QMainWindow): print("populate layers from selection") plugin.dataStorage.current_layers = [] - layers = getLayers(plugin, bySelection=True) # List[QgsLayerTreeNode] - print(layers) + layers, structure = getLayersWithStructure( + plugin, bySelection=True + ) # List[QgsLayerTreeNode] + # print(layers) if layers is not None: for i, layer in enumerate(layers): plugin.dataStorage.current_layers.append((layer.name, layer)) listItem = self.fillLayerList(layer) self.layersWidget.addItem(listItem) - print("populate layers from selection 2") + # print("populate layers from selection 2") set_project_layer_selection(plugin) - print("populate layers from selection 3") + # print("populate layers from selection 3") self.layersWidget.setIconSize(QSize(20, 20)) self.runBtnStatusChanged(plugin) @@ -704,7 +733,7 @@ class SpeckleGISDialog(QMainWindow): logToUser(str(e), level=2, func=inspect.stack()[0][3], plugin=self) def fillLayerList(self, layer): - print("Fill layer list") + # print("Fill layer list") try: listItem = QListWidgetItem(layer.name) diff --git a/qt_ui/utils/assets/pin-outline.png b/qt_ui/utils/assets/pin-outline.png new file mode 100644 index 0000000..682d64a Binary files /dev/null and b/qt_ui/utils/assets/pin-outline.png differ diff --git a/qt_ui/utils/assets/pin.png b/qt_ui/utils/assets/pin.png new file mode 100644 index 0000000..94395f0 Binary files /dev/null and b/qt_ui/utils/assets/pin.png differ diff --git a/qt_ui/utils/global_resources.py b/qt_ui/utils/global_resources.py index 52d60a9..54511f4 100644 --- a/qt_ui/utils/global_resources.py +++ b/qt_ui/utils/global_resources.py @@ -81,3 +81,10 @@ ICON_POINT = os.path.join( ICON_GENERIC = os.path.join( os.path.dirname(os.path.abspath(__file__)), "assets", "legend_generic.png" ) +ICON_PIN_ACTIVE = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "assets", "pin.png" +) +ICON_PIN_DISABLED = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "assets", "pin-outline.png" +) + diff --git a/qt_ui/utils/utils.py b/qt_ui/utils/utils.py index 8cc73b6..41be9b1 100644 --- a/qt_ui/utils/utils.py +++ b/qt_ui/utils/utils.py @@ -2,6 +2,8 @@ from textwrap import wrap from typing import Union import requests +SYMBOL = "_x_x_" + def splitTextIntoLines(text: str = "", number: int = 40) -> str: msg = "" diff --git a/qt_ui/widget_report.py b/qt_ui/widget_report.py index 619bb0e..a5d0a59 100644 --- a/qt_ui/widget_report.py +++ b/qt_ui/widget_report.py @@ -5,9 +5,11 @@ from typing import List, Tuple, Union try: from specklepy_qt_ui.qt_ui.DataStorage import DataStorage from specklepy_qt_ui.qt_ui.utils.global_resources import COLOR -except ModuleNotFoundError: + from specklepy_qt_ui.qt_ui.utils.utils import SYMBOL +except ModuleNotFoundError: from speckle.specklepy_qt_ui.qt_ui.DataStorage import DataStorage from speckle.specklepy_qt_ui.qt_ui.utils.global_resources import COLOR + from speckle.specklepy_qt_ui.qt_ui.utils.utils import SYMBOL # from specklepy_qt_ui.qt_ui.utils.logger import logToUser @@ -22,6 +24,7 @@ from specklepy.core.api.client import SpeckleClient FORM_CLASS, _ = uic.loadUiType( os.path.join(os.path.join(os.path.dirname(__file__), "ui", "report.ui")) ) +CRS_KEYWORD = "CRS" class ReportDialog(QtWidgets.QWidget, FORM_CLASS): @@ -50,7 +53,7 @@ class ReportDialog(QtWidgets.QWidget, FORM_CLASS): try: if self.dataStorage is None: return - reportList = self.dataStorage.latestActionReport + reportList: List[dict] = self.dataStorage.latestActionReport if reportList is None: return @@ -66,11 +69,13 @@ class ReportDialog(QtWidgets.QWidget, FORM_CLASS): for item in reportList: line = "✅ " try: # if sending - line += f'{item["feature_id"]}: {item["obj_type"]}' + some_id = item["feature_id"].replace(SYMBOL, "\\") + line += f'{some_id}: {item["obj_type"]}' operation = f"Sent at {self.dataStorage.latestActionTime}" except: # if receiving sending = False - line += f'{item["speckle_id"]}: {item["obj_type"]}' + some_id = item[list(item.keys())[0]].replace(SYMBOL, "\\") + line += f'{some_id}: {item["obj_type"]}' # f'{item["speckle_id"]}: {item["obj_type"]}' operation = f"Received at {self.dataStorage.latestActionTime}" # edit based on the type @@ -121,22 +126,30 @@ class ReportDialog(QtWidgets.QWidget, FORM_CLASS): text += "\n" # add info about the offsets - text += "Project CRS: " + self.dataStorage.project.crs().authid() + "\n" + try: + crs = self.dataStorage.project.crs() + text += "Project CRS: " + crs.authid() + "\n" + except AttributeError: + crs = self.dataStorage.project.activeMap.spatialReference + CRS_KEYWORD = "Spatial Reference" + text += f"Project {CRS_KEYWORD}: " + crs.name + "\n" units = self.dataStorage.latestActionUnits text += ( - "Project CRS units: " + f"Project {CRS_KEYWORD} units: " + units + f"{' (not supported, treated as Meters)' if 'degrees' in units else ''}" + "\n" ) + try: + text += f"Project {CRS_KEYWORD} WKT: \n" + crs.toWkt() + "\n\n" + except: + text += f"Project {CRS_KEYWORD} WKT: \n" + crs.exportToString() + "\n\n" + text += ( - "Project CRS WKT: \n" + self.dataStorage.project.crs().toWkt() + "\n\n" - ) - text += ( - f"CRS offsets: x={self.dataStorage.crs_offset_x}, y={self.dataStorage.crs_offset_y}" + f"{CRS_KEYWORD} offsets: x={self.dataStorage.crs_offset_x}, y={self.dataStorage.crs_offset_y}" + "\n" ) - text += f"CRS rotation: {self.dataStorage.crs_rotation}°" + "\n\n" + text += f"{CRS_KEYWORD} rotation: {self.dataStorage.crs_rotation}°" + "\n\n" text += last_report