Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin dailogue box not coming up #17

Open
zainahmadmian opened this issue Jan 10, 2025 · 0 comments
Open

Plugin dailogue box not coming up #17

zainahmadmian opened this issue Jan 10, 2025 · 0 comments

Comments

@zainahmadmian
Copy link

Hi,
I am trying to make a sub-plugin "Import Raster" from main plugin "LF Tools". I managed to make a icon on the toolbar but didnt manage to get the dailogue box upon clicking the plugin button in the toolbar. Could you please have a look and let me know where I am missing the code/logic.
My code is as following:

from PyQt5.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterString,
QgsProcessingParameterBoolean,
QgsProcessingParameterEnum,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterFile,
QgsProcessingParameterFileDestination,
QgsApplication,
QgsRasterLayer,
QgsCoordinateReferenceSystem)

from lftools.geocapt.imgs import Imgs
from lftools.translations.translate import translate
import os
import inspect
from PyQt5.QtWidgets import QAction,QDialog, QVBoxLayout, QLabel, QLineEdit, QPushButton, QGridLayout, QMessageBox,QComboBox, QCheckBox, QDialogButtonBox
from qgis.utils import iface
from pathlib import Path
from qgis.PyQt.QtGui import QIcon

cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0]

class ImportRaster:

LOC = QgsApplication.locale()[:2]

def __init__(self, iface):
    self.iface = iface

def initGui(self):
    icon = os.path.join(os.path.join(cmd_folder, 'post_importraster.jpg'))
    self.action = QAction(QIcon(icon), 'Import Raster', self.iface.mainWindow())
    self.iface.addToolBarIcon(self.action)
    self.action.triggered.connect(self.run)
  
def unload(self):
    self.iface.removeToolBarIcon(self.action)
    del self.action

def run(self):
    import processing
    processing.algorithmHelp("importraster")

def tr(self, *string):
    return translate(string, self.LOC)

def createInstance(self):
    return ImportRaster()

def name(self):
    return 'importraster'

def displayName(self):
    return self.tr('Import raster')

def group(self):
    return self.tr('PostGIS')

def groupId(self):
    return 'postgis'

def tags(self):
    return self.tr('postgis,postgresql,database,BD,DB,import,raster,overview,tiling').split(',')

def icon(self):
    return QIcon(os.path.join(os.path.dirname(os.path.dirname(__file__)), ':plugins\import_raster\post_importraster.jpg'))

txt_en = '''This tool allows you to load a raster layer into a PostGIS database.'''
figure = 'import_raster\post_importraster.jpg'

def shortHelpString(self):
    social_BW = Imgs().social_BW
    footer = '''<div align="center">
                  <img src="'''+ os.path.join(os.path.dirname(os.path.dirname(__file__)), self.figure) +'''">
                  </div>
                  <div align="right">
                  <p align="right">
                  <b>'''+self.tr('Author: Zain Ahmad')+'''</b>
                  </p>'''+ social_BW + '''</div>
                </div>'''
    return self.tr(self.txt_en, self.txt_pt) + footer
    

RASTER = 'RASTER'
DATABASE = 'DATABASE'
SCHEMA = 'SCHEMA'
TABLE = 'TABLE'
HOST = 'HOST'
PORT = 'PORT'
USER = 'USER'
VERSION = 'VERSION'
TYPE = 'TYPE'
NAMECOL = 'NAMECOL'
TILING = 'TILING'
OVERVIEW = 'OVERVIEW'
versions = ['9.5', '9.6', '10', '11', '12', '13', '14', '15', '16']

class ImportRasterDialog(QDialog):
def init(self, parent=None):
super().init(parent)
self.setWindowTitle("Import Raster Parameters")

    # Create layout
    layout = QVBoxLayout()

    # Input fields
    self.inputs = {}

    grid_layout = QGridLayout()
    labels = [
        "Raster Layer (path):",
        "Database:",
        "Schema:",
        "Table:",
        "Host:",
        "Port:",
        "User:",
        "PostgreSQL Version:",
        "Options:",
        "Create column with raster name:",
        "Tiling:",
        "Overviews:"
    ]
    self.inputs["raster"] = QLineEdit()
    self.inputs["database"] = QLineEdit()
    self.inputs["schema"] = QLineEdit()
    self.inputs["table"] = QLineEdit()
    self.inputs["host"] = QLineEdit()
    self.inputs["port"] = QLineEdit()
    self.inputs["user"] = QLineEdit()

    # Dropdown for PostgreSQL version
    self.inputs["version"] = QComboBox()
    self.inputs["version"].addItems(['9.5', '9.6', '10', '11', '12', '13', '14', '15', '16'])

    # Dropdown for options
    self.inputs["options"] = QComboBox()
    self.inputs["options"].addItems(['Drops and creates a table', 'Appends data to an existing table',
                                     'Creates a new table', 'Turns on prepare mode'])

    # Checkbox for creating raster name column
    self.inputs["namecol"] = QCheckBox()

    self.inputs["tiling"] = QLineEdit()
    self.inputs["overview"] = QLineEdit()

    # Add inputs to grid layout
    for i, label_text in enumerate(labels):
        label = QLabel(label_text)
        input_field = list(self.inputs.values())[i]
        grid_layout.addWidget(label, i, 0)
        grid_layout.addWidget(input_field, i, 1)

    layout.addLayout(grid_layout)

    # OK and Cancel buttons
    button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
    button_box.accepted.connect(self.accept)
    button_box.rejected.connect(self.reject)
    layout.addWidget(button_box)

    self.setLayout(layout)

def getInputs(self):
    """Retrieve inputs from the dialog box."""
    return {key: field.text() if isinstance(field, QLineEdit) else (
        field.currentText() if isinstance(field, QComboBox) else field.isChecked()
    ) for key, field in self.inputs.items()}

def initAlgorithm(self, config=None):
    # INPUT
    self.addParameter(
        QgsProcessingParameterRasterLayer(
            self.RASTER,
            self.tr('Raster layer'),
            [QgsProcessing.TypeRaster]
        )
    )

    self.addParameter(
        QgsProcessingParameterString(
            self.DATABASE,
            self.tr('Database')
        )
    )

    self.addParameter(
        QgsProcessingParameterString(
            self.SCHEMA,
            self.tr('Schema'),
            defaultValue = 'public'
        )
    )

    self.addParameter(
        QgsProcessingParameterString(
            self.TABLE,
            self.tr('Table')
        )
    )

    self.addParameter(
        QgsProcessingParameterString(
            self.HOST,
            self.tr('Host'),
            defaultValue = 'localhost'
        )
    )

    self.addParameter(
        QgsProcessingParameterString(
            self.PORT,
            self.tr('Port'),
             defaultValue = '5432'
        )
    )

    self.addParameter(
        QgsProcessingParameterString(
            self.USER,
            self.tr('User'),
            defaultValue = 'postgres'
        )
    )

    self.addParameter(
        QgsProcessingParameterEnum(
            self.VERSION,
            self.tr('PostgreSQL version'),
			options = self.versions,
            defaultValue = 8
        )
    )

    tipos = ['d: Drops and creates a table',
             'a: Appends data to an existing table',
             'c: Creates a new table',
             'p: Turns on prepare mode']

    self.addParameter(
        QgsProcessingParameterEnum(
            self.TYPE,
            self.tr('Options'),
			options = tipos,
            defaultValue= 2
        )
    )

    self.addParameter(
        QgsProcessingParameterBoolean(
        self.NAMECOL,
        self.tr('Create column with raster name'),
        defaultValue=False
        )
    )

    self.addParameter(
        QgsProcessingParameterString(
            self.TILING,
            self.tr('Tiling')
        )
    )

    self.addParameter(
        QgsProcessingParameterString(
            self.OVERVIEW,
            self.tr('Overviews'),
            defaultValue = '2,4,8'
        )
    )

def run(self):
    # OPEN DIALOG FOR USER INPUT
    dialog = ImportRasterDialog()
    if dialog.exec_() == QDialog.Accepted:
        user_inputs = dialog.getInputs()

        # Validate mandatory inputs
        required_fields = ["raster", "database", "table", "host", "port", "user"]
        missing_fields = [field for field in required_fields if not user_inputs[field]]
        if missing_fields:
            self.iface.messageBar().pushCritical(
                "Input Error",
                f"Missing required fields: {', '.join(missing_fields)}"
            )
        return

        # Process validated inputs
        raster = user_inputs["raster"]
        database = user_inputs["database"]
        schema = user_inputs["schema"]
        table = user_inputs["table"]
        host = user_inputs["host"]
        port = user_inputs["port"]
        user = user_inputs["user"]
        version = user_inputs["version"]
        tipo = user_inputs["options"]
        namecol = user_inputs["namecol"]
        tiling = user_inputs["tiling"]
        overview = user_inputs["overview"]

        # Construct command (you can refine this as needed)
        comando = f'raster2pgsql -s 4326 -t {tiling} -I -C -M "{raster}" {schema}.{table} | psql -U {user} -d {database} -h {host} -p {port}'

        feedback = self.iface.messageBar()
        feedback.pushInfo(f"Executing: {comando}")

        result = os.system(comando)

        if result == 0:
            feedback.pushSuccess("Operation completed successfully!")
        else:
            feedback.pushCritical("Operation failed. Please check the input parameters.")

def processAlgorithm(self, parameters, context, feedback):

    raster = self.parameterAsRasterLayer(
        parameters,
        self.RASTER,
        context
    )
    if raster is None:
        raise QgsProcessingException(self.invalidSourceError(parameters, self.RASTER))


    database = self.parameterAsString(
        parameters,
        self.DATABASE,
        context
    )
    if not database or database == '' or ' ' in database:
        raise QgsProcessingException(self.invalidSourceError(parameters, self.DATABASE))


    schema = self.parameterAsString(
        parameters,
        self.SCHEMA,
        context
    )

    table = self.parameterAsString(
        parameters,
        self.TABLE,
        context
    )
    if not table or table == '' or ' ' in table:
        raise QgsProcessingException(self.invalidSourceError(parameters, self.TABLE))

    host = self.parameterAsString(
        parameters,
        self.HOST,
        context
    )

    port = self.parameterAsString(
        parameters,
        self.PORT,
        context
    )

    version = self.parameterAsEnum(
        parameters,
        self.VERSION,
        context
    )
    version = self.versions[version]

    user = self.parameterAsString(
        parameters,
        self.USER,
        context
    )

    tipo = self.parameterAsEnum(
        parameters,
        self.TYPE,
        context
    )
    tipo = ['-d ', '-a ', '-c ', '-p '][tipo]

    namecol = self.parameterAsBool(
        parameters,
        self.NAMECOL,
        context
    )
    namecol = '-F ' if namecol else ''

    tiling = self.parameterAsString(
        parameters,
        self.TILING,
        context
    )
    if len(tiling)>2 and 'x' in tiling:
        tiling = '-t {} '.format(tiling)
    else:
        tiling = ''

    ovr = self.parameterAsString(
        parameters,
        self.OVERVIEW,
        context
    )
    if ovr or ovr != '' or ' ' in ovr:
        ovr = '-l {} '.format(ovr)
    else:
        ovr = ''

    projection = raster.crs().authid().split(":")[1]
    projection = ' -s ' + projection + ' '
    raster_path = raster.dataProvider().dataSourceUri()
    comando = 'raster2pgsql' + projection + tiling + tipo + namecol + ovr + '-I -C -M "'+ raster_path + '" ' + schema +'.'+ table + ' | psql -U '+user+' -d '+database+' -h '+host+' -p '+port
    feedback.pushInfo('\n' + self.tr('Command: ') + comando)

    win64 = 'C:/Program Files/PostgreSQL/'+version+'/bin'
    win64d = 'D:/Program Files/PostgreSQL/'+version+'/bin'
    win32 = 'C:/Program Files/PostgreSQL/'+version+'/bin'
    win32d = 'D:/Program Files/PostgreSQL/'+version+'/bin'
    mac = '/Library/PostgreSQL/'+version+'/bin/'
    if os.path.isdir(win64):
        os.chdir(win64)
    elif os.path.isdir(win64d):
        os.chdir(win64d)
    elif os.path.isdir(win32):
        os.chdir(win32)
    elif os.path.isdir(win32d):
        os.chdir(win32d)
    elif os.path.isdir(mac):
        os.chdir(mac)
    else:
        raise QgsProcessingException(self.tr('Make sure your PostgreSQL version is correct!'))

    feedback.pushInfo('\n' + self.tr('Importing raster into the database...'))
    result = os.system(comando)

    if result==0:
        feedback.pushInfo(self.tr('Operation completed successfully!'))
        feedback.pushInfo(self.tr('Zain Ahmad - Ocean Winds'))
    else:
        feedback.pushInfo(self.tr('There was a problem while executing the command. Please check the input parameters.'))

    return {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant