From f15c23fb566226f3716e18531cc9a32841f22cf6 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Thu, 1 May 2025 15:05:00 +0800 Subject: [PATCH 1/4] admin.py: add support for win32 --- admin.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/admin.py b/admin.py index 2a6842f..25c862f 100644 --- a/admin.py +++ b/admin.py @@ -88,13 +88,18 @@ def install( built_directory = build(context, clean=True) \ if build_src else LOCAL_ROOT_DIR / "build" / SRC_NAME - root_directory = Path.home() / \ - f".local/share/QGIS/QGIS3/profiles/" \ - f"{context.obj['qgis_profile']}" + if os.name != "posix": + root_directory = Path.home() / \ + f"AppData/Roaming/QGIS/QGIS3/profiles/" \ + f"{context.obj['qgis_profile']}" + else: + root_directory = Path.home() / \ + f".local/share/QGIS/QGIS3/profiles/" \ + f"{context.obj['qgis_profile']}" base_target_directory = root_directory / "python/plugins" / SRC_NAME _log(f"Copying built plugin to {base_target_directory}...", context=context) - shutil.copytree(built_directory, base_target_directory) + shutil.copytree(built_directory, base_target_directory, dirs_exist_ok=True) _log( f"Installed {str(built_directory)!r}" f" into {str(base_target_directory)!r}", @@ -273,7 +278,8 @@ def compile_resources( target_path = output_directory / "resources.py" target_path.parent.mkdir(parents=True, exist_ok=True) _log(f"compile_resources target_path: {target_path}", context=context) - subprocess.run(shlex.split(f"pyrcc5 -o {target_path} {resources_path}")) + is_posix = os.name == "posix" + subprocess.run(shlex.split(f"pyrcc5 -o {target_path} {resources_path}", posix=is_posix)) @app.command() From 59d8deedcc0127f62410a39b928b7f1214d8abbc Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Fri, 2 May 2025 00:59:26 +0800 Subject: [PATCH 2/4] Move the loading of thumbnails to background tasks Allow the search results to display as soon as the results are returned and move the loading of the thumbnails to background tasks. If thumbnails are still loading when you page back and forth, or clear the results, they will be cancelled. --- src/qgis_stac/gui/qgis_stac_widget.py | 8 ++++++ src/qgis_stac/gui/result_item_widget.py | 36 ++++++++++++++++--------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/qgis_stac/gui/qgis_stac_widget.py b/src/qgis_stac/gui/qgis_stac_widget.py index 74018c9..1bb6236 100644 --- a/src/qgis_stac/gui/qgis_stac_widget.py +++ b/src/qgis_stac/gui/qgis_stac_widget.py @@ -537,6 +537,8 @@ def search_items(self): sort_order = SortOrder.DESCENDING \ if self.reverse_order_box.isChecked() else SortOrder.ASCENDING + self.cancel_loading_thumbnails() + self.api_client.get_items( ItemSearch( collections=collections, @@ -902,10 +904,16 @@ def all_footprints_btn_clicked(self): def clear_search_results(self): """ Clear current search results from the UI""" + self.cancel_loading_thumbnails() self.scroll_area.setWidget(QtWidgets.QWidget()) self.result_items_la.clear() self.result_items = [] + def cancel_loading_thumbnails(self): + """ Cancel any thumbnails which are still loading""" + for riw in self.scroll_area.findChildren(ResultItemWidget): + riw.cancel_thumbnail() + def filter_changed(self, filter_text): """ Sets the filter on the collections proxy model and trigger diff --git a/src/qgis_stac/gui/result_item_widget.py b/src/qgis_stac/gui/result_item_widget.py index 807d419..514f335 100644 --- a/src/qgis_stac/gui/result_item_widget.py +++ b/src/qgis_stac/gui/result_item_widget.py @@ -83,6 +83,8 @@ def __init__( self.item = item self.title_la.setText(item.id) self.thumbnail_url = None + self.thumbnail_task = None + self.thumbnail_task_id = None self.date_time_format = "%Y-%m-%dT%H:%M:%S" self.simple_date_format = "%m/%d/%Y" self.main_widget = main_widget @@ -317,6 +319,12 @@ def add_thumbnail(self): self.thumbnail_response ) + def cancel_thumbnail(self): + """ Cancel loading thumbnail if it's still in progress""" + task = QgsApplication.taskManager().task(self.thumbnail_task_id) + if self.thumbnail_task_id and task: + task.cancel() + def thumbnail_response(self, content): """ Callback to handle the thumbnail network response. Sets the thumbnail image data into the widget thumbnail label. @@ -347,17 +355,20 @@ def network_task( :param auth_config: Authentication configuration string :type auth_config: str """ - task = QgsNetworkContentFetcherTask( + self.thumbnail_task = QgsNetworkContentFetcherTask( request, - authcfg=auth_config + authcfg=auth_config, + flags=QgsTask.CanCancel|QgsTask.CancelWithoutPrompt|QgsTask.Silent ) response_handler = partial( self.response, - task, + self.thumbnail_task, handler ) - task.fetched.connect(response_handler) - task.run() + + self.thumbnail_task.fetched.connect(response_handler) + self.thumbnail_task_id = QgsApplication.taskManager().addTask(self.thumbnail_task) + def response( self, @@ -369,13 +380,14 @@ def response( :param task: QGIS task that fetches network content :type task: QgsNetworkContentFetcherTask """ - reply = task.reply() - error = reply.error() - if error == QtNetwork.QNetworkReply.NoError: - contents: QtCore.QByteArray = reply.readAll() - handler(contents) - else: - log(tr("Problem fetching response from network")) + if not task.isCanceled(): + reply = task.reply() + error = reply.error() + if error == QtNetwork.QNetworkReply.NoError: + contents: QtCore.QByteArray = reply.readAll() + handler(contents) + else: + log(tr("Problem fetching response from network")) def add_footprint_helper(item, main_widget): From 6057d0b9ae44c1a990db6ebc381c6cbda808d3a7 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Fri, 2 May 2025 10:31:29 +0800 Subject: [PATCH 3/4] qgis_stac_main.ui: Make search button always visible This fixes #214 by moving the search button below the scroll area of the Search tab. --- src/qgis_stac/ui/qgis_stac_main.ui | 1244 ++++++++++++++-------------- 1 file changed, 630 insertions(+), 614 deletions(-) diff --git a/src/qgis_stac/ui/qgis_stac_main.ui b/src/qgis_stac/ui/qgis_stac_main.ui index b541bd4..0b6b390 100644 --- a/src/qgis_stac/ui/qgis_stac_main.ui +++ b/src/qgis_stac/ui/qgis_stac_main.ui @@ -52,7 +52,7 @@ - false + true @@ -62,549 +62,465 @@ - 0 + 11 - 0 + 11 - 0 + 11 - 0 + 11 - - - + + + 9 - - QFrame::NoFrame + + 0 - - QFrame::Plain - - - true - - - - - 0 - 0 - 755 - 741 - - - - - - - - - - - 0 - 0 - - - - Connections - - - - - - - + + + + + + + QFrame::StyledPanel + + + QFrame::Plain + + + true + + + + + 0 + 0 + 723 + 669 + + + + + + + + + + + 0 + 0 + + + + Connections + + - - - Create a new service connection - - - &New - - + - - - false - - - Edit selected service connection - - - Edit - - + + + + + Create a new service connection + + + &New + + + + + + + false + + + Edit selected service connection + + + Edit + + + + + + + false + + + Remove connection to selected service + + + Remove + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 171 + 30 + + + + + + + + + + + + Collections + + + false + + - - - false - - - Remove connection to selected service - - - Remove - - + + + + + Filter and search the fetched collections, using the title property. + + + + + + + Filter and search the fetched collections, using the title property. + + + Filter collections + + + + - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 171 - 30 - - - - - - - - - - - - - Collections - - - false - - - - - - - - Filter and search the fetched collections, using the title property. - - - - - - - Filter and search the fetched collections, using the title property. - + - Filter collections + + + + true - - - - - - - - - true - - - - - - - - - - true - - - - - - - - - 0 - 0 - - - - Click on an item to select the collection. - - - QAbstractItemView::NoEditTriggers - - - QAbstractItemView::MultiSelection - - - 5 - - - true - - - true + + + true - - - - - - - Get all collections provided by the current STAC API connection - - - Fetch collections - - + + + + + + 0 + 0 + + + + Click on an item to select the collection. + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::MultiSelection + + + 5 + + + true + + + true + + + true + + + + - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + Get all collections provided by the current STAC API connection + + + Fetch collections + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - - - - - - - - - Filter by date - - - true - - - false - - - true - - - - - - Start - - - - - - - End - - - - - - - - - - - 0 - 0 - 0 - 2021 - 1 - 1 - - - - - - - - - 0 - 0 - 0 - 2021 - 12 - 1 - - - - - 2021 - 12 - 1 - - - - - - - - - - - true - - - - 0 - 0 - - - - Qt::LeftToRight - - - Extent (current: none) - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - true - - - false - - - true - - - - - - - <html><head/><body><p>Insert filter text to be used, the type of filter should align with the </p><p>current selected filter language.</p></body></html> - - - Advanced filter - - - true - - - false - - - true - - - - - - - - Filter and search the fetched collections, using the title property. - + + + + + + + + + Filter by date + + + true + + + false + + + true + + + + - Filter language + Start - - - - Qt::Horizontal - - - - 40 - 20 - + + + + End - + - - - - - 250 - 0 - - + + - Select filter language to be used. + - - 0 + + + 0 + 0 + 0 + 2021 + 1 + 1 + - - - - - - Filter - - - - - - - - - - - - - - - - - - - - <html><head/><body><p>Use queryable properties to filter the catalog when searching.</p></body></html> - - - Data driven queryables - - - true - - - false - - - true - - - - - - These properties are fetched from the '/queryables' catalog endpoint. - - - font-size:14px; font-weight: 400; - - - Queryable properties that are available in the current catalog can be used as filters when searching. - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - QLayout::SetDefaultConstraint - - - - - Property + + + + + 0 + 0 + 0 + 2021 + 12 + 1 + - - true + + + 2021 + 12 + 1 + - - + + + + + + + true + + + + 0 + 0 + + + + Qt::LeftToRight + + + Extent (current: none) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + true + + + false + + + true + + + + + + + <html><head/><body><p>Insert filter text to be used, the type of filter should align with the </p><p>current selected filter language.</p></body></html> + + + Advanced filter + + + true + + + false + + + true + + + + + + + + Filter and search the fetched collections, using the title property. + + + Filter language + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 250 + 0 + + + + Select filter language to be used. + + + 0 + + + + + + + - Input - - - true + Filter - - - + + + + + + - - - - - QFrame::NoFrame - - - true - - - - - 0 - 0 - 471 - 94 - - - - - - - + + + + + + <html><head/><body><p>Use queryable properties to filter the catalog when searching.</p></body></html> + + + Data driven queryables + + + true + + + false + + + true + + - - - - 0 - 0 - + + + These properties are fetched from the '/queryables' catalog endpoint. + + + font-size:14px; font-weight: 400; - Fetch properties + Queryable properties that are available in the current catalog can be used as filters when searching. - - - - - - - 0 - 0 - + + true - + Qt::Horizontal @@ -617,37 +533,195 @@ - - - Qt::Horizontal + + + QLayout::SetDefaultConstraint - - - 40 - 20 - - - + + + + Property + + + true + + + + + + + Input + + + true + + + + + + + + + + + - - - <html><head/><body><p>Clear the list of the current queryable properties, should be used when new properties are needed to replace the current properties.</p></body></html> + + + QFrame::NoFrame - - Clear + + true + + + + 0 + 0 + 458 + 103 + + + + + + + + + + 0 + 0 + + + + Fetch properties + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p>Clear the list of the current queryable properties, should be used when new properties are needed to replace the current properties.</p></body></html> + + + Clear + + + + + - - - - - - + + - + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + Sort by + + + sort_cmb + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Reverse order + + + + + + + Qt::Horizontal @@ -660,60 +734,29 @@ - - - - 0 - 0 - - - - - - - Sort by - - - sort_cmb - - - - - - - - 0 - 0 - - - - - 0 - 0 - + + + Qt::Vertical - - - - - + - 0 - 0 + 20 + 40 - - Qt::LeftToRight - - - Reverse order - - + - - - + + + + + + + 0 + + + Qt::Horizontal @@ -725,77 +768,47 @@ - - + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + Search + + + true + + + + + - Qt::Vertical + Qt::Horizontal - 20 - 40 + 40 + 20 - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - - - Search - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - + + @@ -804,6 +817,9 @@ Results + + 11 + @@ -873,8 +889,8 @@ 0 0 - 735 - 595 + 98 + 28 @@ -1121,7 +1137,7 @@ 0 0 777 - 22 + 26 From fd97399943576923cfb4d1b49f15478fdf5bde13 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Fri, 2 May 2025 11:23:53 +0800 Subject: [PATCH 4/4] queryables: default datetime to NULL instead of current datetime If you enable Data Driven Queryables the current timestamp is used for the datetime property and the user needs to manually clear it if they don't want to use it. If they don't clear the datetime their search won't return any results. --- src/qgis_stac/gui/queryable_property.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qgis_stac/gui/queryable_property.py b/src/qgis_stac/gui/queryable_property.py index b44db45..b5a7af3 100644 --- a/src/qgis_stac/gui/queryable_property.py +++ b/src/qgis_stac/gui/queryable_property.py @@ -89,6 +89,7 @@ def initialize_ui(self): QueryablePropertyType.DATETIME.value: datetime_edit = QgsDateTimeEdit() + datetime_edit.clear() datetime_edit.setSizePolicy(size_policy) input_layout.addWidget(datetime_edit)