@@ -72,6 +72,13 @@ class LayerData(TypedDict):
7272 LayerData = Dict
7373
7474
75+ class PackagingCanceledException (Exception ):
76+ """Exception to be raised when offline converting is canceled"""
77+
78+ def __init__ (self , * args ):
79+ super ().__init__ (QObject ().tr ("Packaging canceled by the user" ), * args )
80+
81+
7582class ExportType (Enum ):
7683 Cable = "cable"
7784 Cloud = "cloud"
@@ -86,6 +93,8 @@ class OfflineConverter(QObject):
8693 # feedback used for basemap generation processing algorithm
8794 _feedback = QgsProcessingFeedback ()
8895
96+ _is_canceled : bool = False
97+
8998 def __init__ (
9099 self ,
91100 project : QgsProject ,
@@ -206,7 +215,13 @@ def _convert(self, project: QgsProject) -> None:
206215 copied_files = list ()
207216
208217 if self .create_basemap and self .project_configuration .create_base_map :
209- self ._export_basemap ()
218+ is_basemap_export_success = self ._export_basemap ()
219+
220+ if not is_basemap_export_success and not self ._is_canceled :
221+ self .warning .emit (
222+ self .tr ("Failed to create basemap" ),
223+ self .tr ("The basemap creation was unsuccessful." ),
224+ )
210225
211226 # We store the pks of the original vector layers
212227 for layer_idx , layer in enumerate (project_layers ):
@@ -270,6 +285,8 @@ def _convert(self, project: QgsProject) -> None:
270285 self .trUtf8 ("Copying layers…" ),
271286 )
272287
288+ self ._check_canceled ()
289+
273290 if layer_action == SyncAction .OFFLINE :
274291 offline_layers .append (layer )
275292 self .__offline_layer_names .append (layer .name ())
@@ -292,6 +309,8 @@ def _convert(self, project: QgsProject) -> None:
292309 # save the original project path
293310 self .project_configuration .original_project_path = str (self .original_filename )
294311
312+ self ._check_canceled ()
313+
295314 # save the offline project twice so that the offline plugin can "know" that it's a relative path
296315 QgsProject .instance ().write (str (export_project_filename ))
297316
@@ -306,6 +325,8 @@ def _convert(self, project: QgsProject) -> None:
306325 if not should_copy :
307326 continue
308327
328+ self ._check_canceled ()
329+
309330 copy_attachments (
310331 self .original_filename .parent ,
311332 export_project_filename .parent ,
@@ -315,6 +336,8 @@ def _convert(self, project: QgsProject) -> None:
315336 # copy project plugin if present
316337 plugin_file = Path ("{}.qml" .format (str (self .original_filename )[:- 4 ]))
317338 if plugin_file .exists ():
339+ self ._check_canceled ()
340+
318341 copy_multifile (
319342 plugin_file , export_project_filename .parent .joinpath (plugin_file .name )
320343 )
@@ -328,6 +351,8 @@ def _convert(self, project: QgsProject) -> None:
328351 QgsProject .instance (),
329352 ).transformBoundingBox (self .area_of_interest .boundingBox ())
330353
354+ self ._check_canceled ()
355+
331356 is_success = self .offliner .convert_to_offline (
332357 str (self ._export_filename .with_name ("data.gpkg" )),
333358 offline_layers ,
@@ -342,10 +367,14 @@ def _convert(self, project: QgsProject) -> None:
342367 )
343368 )
344369
370+ self ._check_canceled ()
371+
345372 # Disable project options that could create problems on a portable
346373 # project with offline layers
347374 self .post_process_offline_layers ()
348375
376+ self ._check_canceled ()
377+
349378 # Now we have a project state which can be saved as offline project
350379 on_original_project_write = self ._on_original_project_write_wrapper (
351380 xml_elements_to_preserve
@@ -711,11 +740,18 @@ def _on_offline_editing_task_progress(self, progress):
711740
712741 def cancel (self ) -> None :
713742 """
714- Cancels the offline export of a QField project.
743+ Cancels the offline packaging of a QField project.
715744 Typically used when the QField export dialog is closed.
716745 """
746+ self ._is_canceled = True
717747 self ._feedback .cancel ()
718748
749+ def _check_canceled (self ) -> None :
750+ """Checks if packaging has been and should be canceled."""
751+ QCoreApplication .processEvents ()
752+ if self ._is_canceled :
753+ raise PackagingCanceledException ()
754+
719755 def convertorProcessingProgress (self ):
720756 """
721757 Will create a new progress object for processing to get feedback from the basemap
0 commit comments