Source code for sec_interp.gui.main_dialog_export

from __future__ import annotations

"""Export management module for SecInterp main dialog.

This module handles exporting preview data to various file formats
(PNG, PDF, SVG) and orchestrating data exports (SHP, CSV) via ExportService.
"""

from pathlib import Path
from typing import TYPE_CHECKING

from qgis.core import Qgis, QgsSettings
from qgis.PyQt.QtCore import QSize
from qgis.PyQt.QtGui import QColor
from qgis.PyQt.QtWidgets import QFileDialog

from sec_interp.core.exceptions import ExportError, SecInterpError
from sec_interp.core.performance_metrics import MetricsCollector, PerformanceTimer
from sec_interp.core.services.export_service import ExportService
from sec_interp.exporters import get_exporter
from sec_interp.logger_config import get_logger

from .main_dialog_config import DialogConfig

if TYPE_CHECKING:
    pass

logger = get_logger(__name__)


[docs] class ExportManager: """Manages all export operations for the dialog. This class handles exporting preview data to various file formats (PNG, PDF, SVG) and orchestrating data exports (SHP, CSV) via ExportService. """
[docs] def __init__(self, dialog: sec_interp.gui.main_dialog.SecInterpDialog): """Initialize export manager with reference to parent dialog. Args: dialog: The :class:`sec_interp.gui.main_dialog.SecInterpDialog` instance """ self.dialog = dialog self.metrics = MetricsCollector() self.export_service = ExportService(self.dialog.plugin_instance.controller)
[docs] def export_preview(self) -> bool: """Export the current preview to a file. Returns: True if export successful, False otherwise """ self.metrics.clear() try: with PerformanceTimer("Total Preview Export Time", self.metrics): if not self.dialog.current_canvas: self.dialog.message_manager.push_message( self.dialog.tr("Export Error"), self.dialog.tr("No preview available to export. Generate a preview first."), level=Qgis.Warning, ) return False canvas = self.dialog.current_canvas layers = canvas.layers() if not layers: self.dialog.message_manager.push_message( self.dialog.tr("Export Error"), self.dialog.tr("No layers to export."), level=Qgis.Warning, ) return False # Format selection settings = QgsSettings() last_dir = settings.value("SecInterp/lastExportDir", "", type=str) default_path = str(Path(last_dir) / "preview.png") if last_dir else "preview.png" file_filter = ( "PNG Image (*.png);;" "JPEG Image (*.jpg *.jpeg);;" "PDF Document (*.pdf);;" "SVG Vector (*.svg)" ) output_path, _selected_filter = QFileDialog.getSaveFileName( self.dialog, "Export Preview", default_path, file_filter ) if not output_path: return False output_path = Path(output_path) settings.setValue("SecInterp/lastExportDir", str(output_path.parent)) # Determine dimensions and DPI ext = output_path.suffix.lower() width = self.dialog.preview_widget.canvas.width() height = self.dialog.preview_widget.canvas.height() dpi = 96 if ext in [".png", ".jpg", ".jpeg"]: width *= 3 height *= 3 dpi = 300 # Prepare settings opts = self.dialog.get_preview_options() export_params = { "width": width, "height": height, "dpi": dpi, "background_color": QColor(255, 255, 255), "show_legend": opts.get("show_legend", True), "legend_renderer": getattr( self.dialog.plugin_instance, "preview_renderer", None ), "title": "Section Interpretation Preview", "description": "Generated by SecInterp QGIS Plugin", "extent": canvas.extent(), } map_settings = self.export_service.get_map_settings( layers, export_params["extent"], self.dialog.preview_widget.canvas.size(), export_params["background_color"], ) # Special size override for rasters if ext in [".png", ".jpg", ".jpeg"]: map_settings.setOutputSize(QSize(width, height)) # Execute export exporter = get_exporter(ext, export_params) success = exporter.export(output_path, map_settings) if success: self.dialog.message_manager.push_message( self.dialog.tr("Success"), self.dialog.tr("Preview exported to {}").format(output_path.name), level=Qgis.Success, ) else: raise ExportError(f"Failed to export preview to {output_path.name}") if DialogConfig.LOG_DETAILED_METRICS: logger.info(f"Preview Performance: {self.metrics.get_summary()}") return success except SecInterpError as e: self.dialog.handle_error(e, "Export Error") return False except Exception as e: self.dialog.handle_error(e, "Unexpected Export Error") return False
[docs] def export_data(self) -> bool: """Orchestrate full data export (SHP/CSV) to the selected folder. Returns: True if successful, False otherwise """ try: # 1. Validate inputs via dialog params = self.dialog.plugin_instance._get_and_validate_inputs() if not params: return False # Auto-save current valid settings self.dialog.settings_manager.save_settings() # Get values for output path (still needed from dialog/values) values = self.dialog.get_selected_values() output_folder = Path(values["output_path"]) # 2. Generate data via controller self.dialog.preview_widget.results_text.setPlainText("✓ Generating data for export...") profile_data, geol_data, struct_data, drillhole_data, _ = ( self.dialog.plugin_instance.controller.generate_profile_data(params) ) if not profile_data: self.dialog.message_manager.push_message( self.dialog.tr("Error"), self.dialog.tr("No profile data generated."), level=Qgis.Critical, ) return False num_interps = len(self.dialog.interpretations) logger.info(f"Exporting data: found {num_interps} interpretation(s) in dialog.") # Extract export settings export_options = { "exp_topo": values.get("exp_topo", True), "exp_geol": values.get("exp_geol", True), "exp_struct": values.get("exp_struct", True), "exp_drill": values.get("exp_drill", True), "exp_interp": values.get("exp_interp", True), "drill_3d_traces": values.get("drill_3d_traces", True), "drill_3d_intervals": values.get("drill_3d_intervals", True), "drill_3d_original": values.get("drill_3d_original", True), "drill_3d_projected": values.get("drill_3d_projected", False), } result_msg = self.export_service.export_data( output_folder, params, profile_data, geol_data, struct_data, drillhole_data, interp_data=self.dialog.interpretations, export_options=export_options, ) self.dialog.preview_widget.results_text.setPlainText("\n".join(result_msg)) except SecInterpError as e: self.dialog.handle_error(e, "Data Export Error") return False except Exception as e: self.dialog.handle_error(e, "Unexpected Data Export Error") return False else: return True