Esempio n. 1
0
    def saveCtrl(self):
        n = 0
        if self.lineEdit_3.text()=='':
            n += 1
        if self.lineEdit_4.text()=='':
            n += 1
        if self.lineEdit_5.text()=='':
            n += 1
        if self.comboBox_2.currentText()=='':
            n += 1
        if self.comboBox_3.currentText()=='':
            n += 1
        if self.comboBox_4.currentText()=='':
            n += 1
        if self.tableWidget.rowCount()==0:
            n += 1

        if n==0:
            self.btnsave.setEnabled(True)
            self.label_12.setText('')
        else:
            self.btnsave.setEnabled(False)
            pal = QPalette()
            pal.setColor(self.label_12.backgroundRole(), Qt.red)
            pal.setColor(self.label_12.foregroundRole(), Qt.red)
            self.label_12.setPalette(pal)
            self.label_12.setText('All bold field must be given!')
    def db_size(self,  db_connections):
        usedSpace = 0
        self.numDbs = len(list(db_connections._dbs.keys()))
        for db in list(db_connections._dbs.keys()):
            try:
                conn = db_connections.db(db).psycopg_connection()
            except:
                continue
            cursor = conn.cursor()
            sql = "SELECT pg_database_size('" + str(db) + "')"
            cursor.execute(sql)
            usedSpace += int(cursor.fetchone()[0])-(11*1024*1024)
            cursor.close()
            conn.close

        # Used space in MB
        usedSpace /= 1024 * 1024

        login_info = self.api.check_login(version_info=self._version_info())
        
        try:            
            self.maxSize = login_info['max_storage']
            self.maxDBs = login_info['max_dbs']
        except:
            self.maxSize = 50
            self.maxDBs = 5

        lblPalette = QPalette(self.ui.lblDbSize.palette())
        usage = usedSpace / float(self.maxSize)
        self.storage_exceeded = False
    
        if usage < 0.8:
            bg_color = QColor(255, 0, 0, 0)
            text_color = QColor(Qt.black)
        elif usage >= 0.8 and usage < 1:
            bg_color = QColor(255, 0, 0, 100)
            text_color = QColor(Qt.white)
        elif usage >= 1:
            bg_color = QColor(255, 0, 0, 255)
            text_color = QColor(Qt.white)
            self.storage_exceeded = True

        lblPalette.setColor(QPalette.Window, QColor(bg_color))
        lblPalette.setColor(QPalette.Foreground,QColor(text_color))
        
        self.ui.lblDbSize.setAutoFillBackground(True)
        self.ui.lblDbSize.setPalette(lblPalette)
        self.ui.lblDbSize.setText(
            self.tr("Used DB Storage: ") + "%d / %d MB" % (usedSpace, self.maxSize))

        self.ui.lblDbSizeUpload.setAutoFillBackground(True)
        self.ui.lblDbSizeUpload.setPalette(lblPalette)
        self.ui.lblDbSizeUpload.setText(
            self.tr("Used DB Storage: ") + "%d / %d MB" % (usedSpace, self.maxSize))
        self.ui.btnUploadData.setDisabled(self.storage_exceeded)
        self.ui.btnPublishMap.setDisabled(self.storage_exceeded)
Esempio n. 3
0
    def nameCtrl(self):
        ss = 'zone_a_%s' % self.lineEdit.text()
        if ss in self.tablst:
            self.btnok.setEnabled(False)
            pal = QPalette()
            pal.setColor(self.label_17.backgroundRole(), Qt.red)
            pal.setColor(self.label_17.foregroundRole(), Qt.red)
            self.label_17.setPalette(pal)
            self.label_17.setText('Database contain layer with tis name!')
        else:
            self.btnok.setEnabled(True)

        self.saveCtrl()
Esempio n. 4
0
 def accept(self):
     context = dataobjects.createContext()
     try:
         parameters = self.getParameterValues()
         self.setOutputValues()
         ok, msg = self.algorithm().checkParameterValues(parameters, context)
         if not ok:
             QMessageBox.warning(
                 self, self.tr('Unable to execute algorithm'), msg)
             return
         description = algAsDict(self.algorithm())
         description["name"] = self.settingsPanel.txtName.text().strip()
         description["group"] = self.settingsPanel.txtGroup.text().strip()
         if not (description["name"] and description["group"]):
             self.tabWidget().setCurrentIndex(self.tabWidget().count() - 1)
             return
         validChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:'
         filename = ''.join(c for c in description["name"] if c in validChars).lower() + ".json"
         filepath = os.path.join(preconfiguredAlgorithmsFolder(), filename)
         with open(filepath, "w") as f:
             json.dump(description, f)
         QgsApplication.processingRegistry().providerById('preconfigured').refreshAlgorithms()
     except AlgorithmDialogBase.InvalidParameterValue as e:
         try:
             self.buttonBox().accepted.connect(lambda: e.widget.setPalette(QPalette()))
             palette = e.widget.palette()
             palette.setColor(QPalette.Base, QColor(255, 255, 0))
             e.widget.setPalette(palette)
             self.messageBar().pushMessage("", self.tr('Missing parameter value: {0}').format(
                 e.parameter.description()),
                 level=Qgis.Warning, duration=5)
             return
         except:
             QMessageBox.critical(self,
                                  self.tr('Unable to execute algorithm'),
                                  self.tr('Wrong or missing parameter values'))
     self.close()
Esempio n. 5
0
 def accept(self):
     try:
         self.setParamValues()
         msg = self.alg._checkParameterValuesBeforeExecuting()
         if msg:
             QMessageBox.warning(
                 self, self.tr('Unable to execute algorithm'), msg)
             return
         description = algAsDict(self.alg)
         description["name"] = self.settingsPanel.txtName.text().strip()
         description["group"] = self.settingsPanel.txtGroup.text().strip()
         if not (description["name"] and description["group"]):
             self.tabWidget.setCurrentIndex(self.tabWidget.count() - 1)
             return
         validChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:'
         filename = ''.join(c for c in description["name"] if c in validChars).lower() + ".json"
         filepath = os.path.join(preconfiguredAlgorithmsFolder(), filename)
         with open(filepath, "w") as f:
             json.dump(description, f)
         algList.reloadProvider('preconfigured')
     except AlgorithmDialogBase.InvalidParameterValue as e:
         try:
             self.buttonBox.accepted.connect(lambda:
                                             e.widget.setPalette(QPalette()))
             palette = e.widget.palette()
             palette.setColor(QPalette.Base, QColor(255, 255, 0))
             e.widget.setPalette(palette)
             self.parent.bar.pushMessage("", self.tr('Missing parameter value: %s')
                                         % e.parameter.description,
                                         level=QgsMessageBar.WARNING, duration=5)
             return
         except:
             QMessageBox.critical(self,
                                  self.tr('Unable to execute algorithm'),
                                  self.tr('Wrong or missing parameter values'))
     self.close()
Esempio n. 6
0
    def accept(self):
        feedback = self.createFeedback()
        context = dataobjects.createContext(feedback)

        checkCRS = ProcessingConfig.getSetting(ProcessingConfig.WARN_UNMATCHING_CRS)
        try:
            parameters = self.getParameterValues()

            if checkCRS and not self.algorithm().validateInputCrs(parameters, context):
                reply = QMessageBox.question(self, self.tr("Unmatching CRS's"),
                                             self.tr('Layers do not all use the same CRS. This can '
                                                     'cause unexpected results.\nDo you want to '
                                                     'continue?'),
                                             QMessageBox.Yes | QMessageBox.No,
                                             QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            checkExtentCRS = ProcessingConfig.getSetting(ProcessingConfig.WARN_UNMATCHING_EXTENT_CRS)
            # TODO
            if False and checkExtentCRS and self.checkExtentCRS():
                reply = QMessageBox.question(self, self.tr("Extent CRS"),
                                             self.tr('Extent parameters must use the same CRS as the input layers.\n'
                                                     'Your input layers do not have the same extent as the project, '
                                                     'so the extent might be in a wrong CRS if you have selected it from the canvas.\n'
                                                     'Do you want to continue?'),
                                             QMessageBox.Yes | QMessageBox.No,
                                             QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            ok, msg = self.algorithm().checkParameterValues(parameters, context)
            if msg:
                QMessageBox.warning(
                    self, self.tr('Unable to execute algorithm'), msg)
                return
            self.runButton().setEnabled(False)
            self.cancelButton().setEnabled(False)
            buttons = self.mainWidget().iterateButtons
            self.iterateParam = None

            for i in range(len(list(buttons.values()))):
                button = list(buttons.values())[i]
                if button.isChecked():
                    self.iterateParam = list(buttons.keys())[i]
                    break

            self.clearProgress()
            self.setProgressText(self.tr('Processing algorithm...'))

            self.setInfo(
                self.tr('<b>Algorithm \'{0}\' starting...</b>').format(self.algorithm().displayName()), escapeHtml=False)

            feedback.pushInfo(self.tr('Input parameters:'))
            display_params = []
            for k, v in parameters.items():
                display_params.append("'" + k + "' : " + self.algorithm().parameterDefinition(k).valueAsPythonString(v, context))
            feedback.pushCommandInfo('{ ' + ', '.join(display_params) + ' }')
            feedback.pushInfo('')
            start_time = time.time()

            if self.iterateParam:
                # Make sure the Log tab is visible before executing the algorithm
                try:
                    self.showLog()
                    self.repaint()
                except:
                    pass

                self.cancelButton().setEnabled(self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel)
                if executeIterating(self.algorithm(), parameters, self.iterateParam, context, feedback):
                    feedback.pushInfo(
                        self.tr('Execution completed in {0:0.2f} seconds'.format(time.time() - start_time)))
                    self.cancelButton().setEnabled(False)
                    self.finish(True, parameters, context, feedback)
                else:
                    self.cancelButton().setEnabled(False)
                    self.resetGui()
            else:
                command = self.algorithm().asPythonCommand(parameters, context)
                if command:
                    ProcessingLog.addToLog(command)
                self.cancelButton().setEnabled(self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel)

                def on_complete(ok, results):
                    if ok:
                        feedback.pushInfo(self.tr('Execution completed in {0:0.2f} seconds'.format(time.time() - start_time)))
                        feedback.pushInfo(self.tr('Results:'))
                        feedback.pushCommandInfo(pformat(results))
                    else:
                        feedback.reportError(
                            self.tr('Execution failed after {0:0.2f} seconds'.format(time.time() - start_time)))
                    feedback.pushInfo('')

                    if self.feedback_dialog is not None:
                        self.feedback_dialog.close()
                        self.feedback_dialog.deleteLater()
                        self.feedback_dialog = None

                    self.cancelButton().setEnabled(False)

                    self.finish(ok, results, context, feedback)

                if self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanRunInBackground:
                    # Make sure the Log tab is visible before executing the algorithm
                    self.showLog()

                    task = QgsProcessingAlgRunnerTask(self.algorithm(), parameters, context, feedback)
                    task.executed.connect(on_complete)
                    self.setCurrentTask(task)
                else:
                    self.feedback_dialog = self.createProgressDialog()
                    self.feedback_dialog.show()
                    ok, results = execute(self.algorithm(), parameters, context, feedback)
                    on_complete(ok, results)

        except AlgorithmDialogBase.InvalidParameterValue as e:
            try:
                self.buttonBox().accepted.connect(lambda e=e:
                                                  e.widget.setPalette(QPalette()))
                palette = e.widget.palette()
                palette.setColor(QPalette.Base, QColor(255, 255, 0))
                e.widget.setPalette(palette)
            except:
                pass
            self.messageBar().clearWidgets()
            self.messageBar().pushMessage("", self.tr("Wrong or missing parameter value: {0}").format(e.parameter.description()),
                                          level=QgsMessageBar.WARNING, duration=5)
Esempio n. 7
0
    def accept(self):
        super(AlgorithmDialog, self)._saveGeometry()

        feedback = self.createFeedback()
        context = dataobjects.createContext(feedback)

        checkCRS = ProcessingConfig.getSetting(
            ProcessingConfig.WARN_UNMATCHING_CRS)
        try:
            parameters = self.getParamValues()

            if checkCRS and not self.alg.validateInputCrs(parameters, context):
                reply = QMessageBox.question(
                    self, self.tr("Unmatching CRS's"),
                    self.tr('Layers do not all use the same CRS. This can '
                            'cause unexpected results.\nDo you want to '
                            'continue?'), QMessageBox.Yes | QMessageBox.No,
                    QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            checkExtentCRS = ProcessingConfig.getSetting(
                ProcessingConfig.WARN_UNMATCHING_EXTENT_CRS)
            # TODO
            if False and checkExtentCRS and self.checkExtentCRS():
                reply = QMessageBox.question(
                    self, self.tr("Extent CRS"),
                    self.
                    tr('Extent parameters must use the same CRS as the input layers.\n'
                       'Your input layers do not have the same extent as the project, '
                       'so the extent might be in a wrong CRS if you have selected it from the canvas.\n'
                       'Do you want to continue?'),
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            ok, msg = self.alg.checkParameterValues(parameters, context)
            if msg:
                QMessageBox.warning(self,
                                    self.tr('Unable to execute algorithm'),
                                    msg)
                return
            self.btnRun.setEnabled(False)
            self.btnClose.setEnabled(False)
            buttons = self.mainWidget.iterateButtons
            self.iterateParam = None

            for i in range(len(list(buttons.values()))):
                button = list(buttons.values())[i]
                if button.isChecked():
                    self.iterateParam = list(buttons.keys())[i]
                    break

            self.progressBar.setMaximum(0)
            self.lblProgress.setText(self.tr('Processing algorithm...'))
            # Make sure the Log tab is visible before executing the algorithm
            try:
                self.tabWidget.setCurrentIndex(1)
                self.repaint()
            except:
                pass

            self.setInfo(
                self.tr('<b>Algorithm \'{0}\' starting...</b>').format(
                    self.alg.displayName()),
                escape_html=False)

            feedback.pushInfo(self.tr('Input parameters:'))
            feedback.pushCommandInfo(pformat(parameters))
            feedback.pushInfo('')
            start_time = time.time()

            if self.iterateParam:
                self.buttonCancel.setEnabled(
                    self.alg.flags() & QgsProcessingAlgorithm.FlagCanCancel)
                if executeIterating(self.alg, parameters, self.iterateParam,
                                    context, feedback):
                    feedback.pushInfo(
                        self.tr(
                            'Execution completed in {0:0.2f} seconds'.format(
                                time.time() - start_time)))
                    self.buttonCancel.setEnabled(False)
                    self.finish(True, parameters, context, feedback)
                else:
                    self.buttonCancel.setEnabled(False)
                    self.resetGUI()
            else:
                command = self.alg.asPythonCommand(parameters, context)
                if command:
                    ProcessingLog.addToLog(command)
                self.buttonCancel.setEnabled(
                    self.alg.flags() & QgsProcessingAlgorithm.FlagCanCancel)

                def on_complete(ok, results):
                    if ok:
                        feedback.pushInfo(
                            self.tr('Execution completed in {0:0.2f} seconds'.
                                    format(time.time() - start_time)))
                        feedback.pushInfo(self.tr('Results:'))
                        feedback.pushCommandInfo(pformat(results))
                    else:
                        feedback.reportError(
                            self.tr('Execution failed after {0:0.2f} seconds'.
                                    format(time.time() - start_time)))
                    feedback.pushInfo('')

                    self.buttonCancel.setEnabled(False)
                    self.finish(ok, results, context, feedback)

                task = QgsProcessingAlgRunnerTask(self.alg, parameters,
                                                  context, feedback)
                task.executed.connect(on_complete)
                QgsApplication.taskManager().addTask(task)

        except AlgorithmDialogBase.InvalidParameterValue as e:
            try:
                self.buttonBox.accepted.connect(
                    lambda e=e: e.widget.setPalette(QPalette()))
                palette = e.widget.palette()
                palette.setColor(QPalette.Base, QColor(255, 255, 0))
                e.widget.setPalette(palette)
            except:
                pass
            self.bar.clearWidgets()
            self.bar.pushMessage(
                "",
                self.tr("Wrong or missing parameter value: {0}").format(
                    e.parameter.description()),
                level=QgsMessageBar.WARNING,
                duration=5)
Esempio n. 8
0
    def accept(self):
        super(AlgorithmDialog, self)._saveGeometry()

        context = dataobjects.createContext()

        checkCRS = ProcessingConfig.getSetting(
            ProcessingConfig.WARN_UNMATCHING_CRS)
        try:
            parameters = self.getParamValues()

            QgsMessageLog.logMessage(str(parameters), 'Processing',
                                     QgsMessageLog.CRITICAL)

            # TODO
            if False and checkCRS and not self.alg.checkInputCRS():
                reply = QMessageBox.question(
                    self, self.tr("Unmatching CRS's"),
                    self.tr('Layers do not all use the same CRS. This can '
                            'cause unexpected results.\nDo you want to '
                            'continue?'), QMessageBox.Yes | QMessageBox.No,
                    QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            checkExtentCRS = ProcessingConfig.getSetting(
                ProcessingConfig.WARN_UNMATCHING_EXTENT_CRS)
            #TODO
            if False and checkExtentCRS and self.checkExtentCRS():
                reply = QMessageBox.question(
                    self, self.tr("Extent CRS"),
                    self.
                    tr('Extent parameters must use the same CRS as the input layers.\n'
                       'Your input layers do not have the same extent as the project, '
                       'so the extent might be in a wrong CRS if you have selected it from the canvas.\n'
                       'Do you want to continue?'),
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            ok, msg = self.alg.checkParameterValues(parameters, context)
            if msg:
                QMessageBox.warning(self,
                                    self.tr('Unable to execute algorithm'),
                                    msg)
                return
            self.btnRun.setEnabled(False)
            self.btnClose.setEnabled(False)
            buttons = self.mainWidget.iterateButtons
            self.iterateParam = None

            for i in range(len(list(buttons.values()))):
                button = list(buttons.values())[i]
                if button.isChecked():
                    self.iterateParam = list(buttons.keys())[i]
                    break

            self.progressBar.setMaximum(0)
            self.lblProgress.setText(self.tr('Processing algorithm...'))
            # Make sure the Log tab is visible before executing the algorithm
            try:
                self.tabWidget.setCurrentIndex(1)
                self.repaint()
            except:
                pass

            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

            self.setInfo(
                self.tr('<b>Algorithm {0} starting...</b>').format(
                    self.alg.displayName()))

            if self.iterateParam:
                if executeIterating(self.alg, parameters, self.iterateParam,
                                    context, self.feedback):
                    self.finish(parameters, context)
                else:
                    QApplication.restoreOverrideCursor()
                    self.resetGUI()
            else:
                # TODO
                #command = self.alg.getAsCommand()
                #if command:
                #    ProcessingLog.addToLog(command)
                self.buttonCancel.setEnabled(
                    self.alg.flags() & QgsProcessingAlgorithm.FlagCanCancel)
                result = executeAlgorithm(self.alg, parameters, context,
                                          self.feedback)
                self.buttonCancel.setEnabled(False)
                self.finish(result, context)
                #TODO
                #else:
                #    QApplication.restoreOverrideCursor()
                #    self.resetGUI()
        except AlgorithmDialogBase.InvalidParameterValue as e:
            try:
                self.buttonBox.accepted.connect(
                    lambda e=e: e.widget.setPalette(QPalette()))
                palette = e.widget.palette()
                palette.setColor(QPalette.Base, QColor(255, 255, 0))
                e.widget.setPalette(palette)
            except:
                pass
            self.bar.clearWidgets()
            self.bar.pushMessage(
                "",
                self.tr("Wrong or missing parameter value: {0}").format(
                    e.parameter.description()),
                level=QgsMessageBar.WARNING,
                duration=5)
class QgisCloudPluginDialog(QDockWidget):
    COLUMN_LAYERS = 0
    COLUMN_DATA_SOURCE = 1
    COLUMN_TABLE_NAME = 2
    COLUMN_GEOMETRY_TYPE = 3
    COLUMN_SRID = 4

    GEOMETRY_TYPES = {
        QgsWkbTypes.Unknown: "Unknown",
        QgsWkbTypes.NoGeometry: "No geometry",
        QgsWkbTypes.Point: "Point",
        QgsWkbTypes.MultiPoint: "MultiPoint",               
        QgsWkbTypes.PointZ: "PointZ",
        QgsWkbTypes.MultiPointZ: "MultiPointZ",
        QgsWkbTypes.PointM: "PointM",
        QgsWkbTypes.MultiPointM: "MultiPointM",
        QgsWkbTypes.PointZM: "PointZM",
        QgsWkbTypes.MultiPointZM: "MultiPointZM",
        QgsWkbTypes.Point25D: "Point25D",
        QgsWkbTypes.MultiPoint25D: "MultiPoint25D",
        QgsWkbTypes.LineString: "LineString",
        QgsWkbTypes.MultiLineString: "LineString",
        QgsWkbTypes.LineStringZ: "LineStringZ",
        QgsWkbTypes.MultiLineStringZ: "LineStringZ",
        QgsWkbTypes.LineStringM: "LineStringM",
        QgsWkbTypes.MultiLineStringM: "LineStringM",
        QgsWkbTypes.LineStringZM: "LineStringZM",
        QgsWkbTypes.MultiLineStringZM: "LineStringZM",
        QgsWkbTypes.LineString25D: "LineString25D",
        QgsWkbTypes.MultiLineString25D: "MultiLineString25D",
        QgsWkbTypes.Polygon: "Polygon",            
        QgsWkbTypes.MultiPolygon: "MultiPolygon", 
        QgsWkbTypes.PolygonZ: "PolygonZ",            
        QgsWkbTypes.MultiPolygonZ: "MultiPolygonZ", 
        QgsWkbTypes.PolygonM: "PolygonM",            
        QgsWkbTypes.MultiPolygonM: "MultiPolygonM", 
        QgsWkbTypes.PolygonZM: "PolygonZM",            
        QgsWkbTypes.MultiPolygonZM: "MultiPolygonZM", 
        QgsWkbTypes.Polygon25D: "Polygon25D",            
        QgsWkbTypes.MultiPolygon25D: "MultiPolygon25D", 
        QgsWkbTypes.CircularString: "CircularString",
        QgsWkbTypes.CompoundCurve: "CompoundCurve",
        QgsWkbTypes.CurvePolygon: "CurvePolygon", 
        QgsWkbTypes.MultiCurve: "MultiCurve",
        QgsWkbTypes.MultiSurface: "MultiSurface",
        QgsWkbTypes.CircularStringZ: "CircularStringZ",
        QgsWkbTypes.CompoundCurveZ: "CompoundCurveZ",
        QgsWkbTypes.CurvePolygonZ: "CurvePolygonZ", 
        QgsWkbTypes.MultiCurveZ: "MultiCurveZ",
        QgsWkbTypes.MultiSurfaceZ: "MultiSurfaceZ",
        QgsWkbTypes.CircularStringM: "CircularStringM",
        QgsWkbTypes.CompoundCurveM: "CompoundCurveM",
        QgsWkbTypes.CurvePolygonM: "CurvePolygonM", 
        QgsWkbTypes.MultiCurveM: "MultiCurveM",
        QgsWkbTypes.MultiSurfaceM: "MultiSurfaceM",
        QgsWkbTypes.CircularStringZM: "CircularStringZM",
        QgsWkbTypes.CompoundCurveZM: "CompoundCurveZM",
        QgsWkbTypes.CurvePolygonZM: "CurvePolygonZM", 
        QgsWkbTypes.MultiCurveZM: "MultiCurveZM",
        QgsWkbTypes.MultiSurfaceZM: "MultiSurfaceZM",
    }
        
    PROJECT_INSTANCE = QgsProject.instance()     
    
    
    def __init__(self, iface, version):
        QDockWidget.__init__(self, None)
        self.iface = iface
        self.clouddb = True
        self.version = version
        # Set up the user interface from Designer.
        self.ui = Ui_QgisCloudPlugin()
        self.ui.setupUi(self)
        self.storage_exceeded = True
        
        myAbout = DlgAbout()
        self.ui.aboutText.setText(
            myAbout.aboutString() +
            myAbout.contribString() +
            myAbout.licenseString() +
            "<p>Versions:<ul>" +
            "<li>QGIS: %s</li>" % str(Qgis.QGIS_VERSION).encode("utf-8") +
            "<li>Python: %s</li>" % sys.version.replace("\n", " ") +
            "<li>OS: %s</li>" % platform.platform() +
            "</ul></p>")
            
        data_protection_link = """<a href="http://qgiscloud.com/pages/privacy">%s</a>""" % (self.tr("Privacy Policy"))
            
        self.ui.lblVersionPlugin.setText("%s &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%s" % (self.version,  data_protection_link))
        self.ui.lblVersionPlugin.setOpenExternalLinks(True)            
#        self.ui.lblVersionPlugin.setText(self.version)

        self.ui.tblLocalLayers.setColumnCount(5)
        header = ["Layers", "Data source",
                  "Table name", "Geometry type", "SRID"]
        self.ui.tblLocalLayers.setHorizontalHeaderLabels(header)
        self.ui.tblLocalLayers.resizeColumnsToContents()
        self.ui.tblLocalLayers.setEditTriggers(QAbstractItemView.NoEditTriggers)

        self.ui.btnUploadData.setEnabled(False)
        self.ui.btnPublishMap.setEnabled(False)
        self.ui.btnMapDelete.setEnabled(False)
        self.ui.progressWidget.hide()
        self.ui.btnLogout.hide()
        self.ui.lblLoginStatus.hide()
        self.ui.widgetServices.hide()
        self.ui.widgetDatabases.setEnabled(False)
        self.ui.widgetMaps.setEnabled(False)
        self.ui.labelOpenLayersPlugin.hide()

        try:
            from .openlayers_menu import OpenlayersMenu
            self.ui.btnBackgroundLayer.setMenu(OpenlayersMenu(self.iface))
        except:
                self.ui.btnBackgroundLayer.hide()
                self.ui.labelOpenLayersPlugin.show()

        # map<data source, table name>
        self.data_sources_table_names = {}
        # flag to disable update of local data sources during upload
        self.do_update_local_data_sources = True

        self.ui.btnLogin.clicked.connect(self.check_login)
        self.ui.btnDbCreate.clicked.connect(self.create_database)
        self.ui.btnDbDelete.clicked.connect(self.delete_database)
        self.ui.btnDbRefresh.clicked.connect(self.refresh_databases)
        self.ui.btnMapDelete.clicked.connect(self.delete_map)
        self.ui.btnMapLoad.clicked.connect(self.map_load)
        self.ui.tabMaps.itemDoubleClicked.connect(self.map_load)
        self.ui.tabDatabases.itemSelectionChanged.connect(self.select_database)
        self.ui.tabMaps.itemSelectionChanged.connect(self.select_map)
        self.ui.btnPublishMap.clicked.connect(self.publish_map)
        self.ui.btnRefreshLocalLayers.clicked.connect(self.refresh_local_data_sources)
        self.iface.newProjectCreated.connect(self.reset_load_data)
        self.iface.projectRead.connect(self.reset_load_data)

        self.PROJECT_INSTANCE.layerWillBeRemoved.connect(self.remove_layer)
        self.PROJECT_INSTANCE.layerWasAdded.connect(self.add_layer)
        
        self.ui.cbUploadDatabase.currentIndexChanged.connect(lambda idx: self.activate_upload_button())
        self.ui.btnUploadData.clicked.connect(self.upload_data)

        self.ui.editServer.textChanged.connect(self.serverURL)
        self.ui.resetUrlBtn.clicked.connect(self.resetApiUrl)

        self.read_settings()
        self.api = API()
        self.db_connections = DbConnections()
        self.local_data_sources = LocalDataSources()
        self.data_upload = DataUpload(
            self.iface, self.statusBar(), self.ui.lblProgress, self.api,
            self.db_connections)

        if self.URL == "":
            self.ui.editServer.setText(self.api.api_url())
        else:
            self.ui.editServer.setText(self.URL)

        self.palette_red = QPalette(self.ui.lblVersionPlugin.palette())
        self.palette_red.setColor(QPalette.WindowText, Qt.red)

    def unload(self):
        self.do_update_local_data_sources = False
        if self.iface:
            self.iface.newProjectCreated.disconnect(self.reset_load_data)
            self.iface.projectRead.disconnect(self.reset_load_data)
        
        if self.PROJECT_INSTANCE:
            self.PROJECT_INSTANCE.layerWillBeRemoved.disconnect(self.remove_layer)
            self.PROJECT_INSTANCE.layerWasAdded.disconnect(self.add_layer)
        

    def statusBar(self):
        return self.iface.mainWindow().statusBar()

    def map(self):
        project = QgsProject.instance()
        name = os.path.splitext(os.path.basename(str(project.fileName())))[0]
            
        # Allowed chars for QGISCloud map name: /\A[A-Za-z0-9\_\-]*\Z/
        name = str(name).encode('ascii', 'replace')  # Replace non-ascii chars
        
        # Replace withespace
        name = name.replace(b" ",  b"_")
        return name

    def resetApiUrl(self):
        self.ui.editServer.setText(self.api.api_url())

    def serverURL(self, URL):
        self.URL = URL
        self.store_settings()

    def store_settings(self):
        s = QSettings()
        s.setValue("qgiscloud/user", self.user)
        s.setValue("qgiscloud/URL", self.URL)

    def read_settings(self):
        s = QSettings()
        self.user = s.value("qgiscloud/user", "")
        self.URL = s.value("qgiscloud/URL", "")

    def _update_clouddb_mode(self, clouddb):
        self.clouddb = clouddb
        self.ui.widgetDatabases.setVisible(self.clouddb)
        tab_index = 1
        tab_name = QApplication.translate("QgisCloudPlugin", "Upload Data")
        visible = (self.ui.tabWidget.indexOf(self.ui.uploadTab) == tab_index)
        if visible and not self.clouddb:
            self.ui.tabWidget.removeTab(tab_index)
        elif not visible and self.clouddb:
            self.ui.tabWidget.insertTab(tab_index, self.ui.uploadTab, tab_name)

    def _version_info(self):
        return {
            'versions': {
                'plugin': self.version.encode('utf-8').decode('utf-8'),
                'QGIS': Qgis.QGIS_VERSION.encode('utf-8').decode('utf-8'),
                'OS': platform.platform().encode('utf-8').decode('utf-8'),
                'Python': sys.version.encode('utf-8').decode('utf-8')
            }
        }

    def check_login(self):
        version_ok = True
        if not self.api.check_auth():
#            res = QMessageBox.information(
#                self,
#                self.tr("QGIS 3 message"),
#                self.tr("""You have started the QGIS Cloud Plugin with QGIS 3. This configuration is not stable and is not intended for productive use. A lot can still change in QGIS before the first QGIS 3 LTR. Therefore, it is possible that the plugin does not work as you expect or terminates with errors. If you need a stable version of QGIS Cloud, please continue working with QGIS 2."""),
#                QMessageBox.StandardButtons(
#                QMessageBox.Close))        	
            login_dialog = QDialog(self)
            login_dialog.ui = Ui_LoginDialog()
            login_dialog.ui.setupUi(login_dialog)
            login_dialog.ui.editUser.setText(self.user)
            login_ok = False
            while not login_ok and version_ok:
                self.api.set_url(self.api_url())
                if not login_dialog.exec_():
                    self.api.set_auth(
                        user=login_dialog.ui.editUser.text(), password=None)
                    return login_ok
                self.api.set_auth(
                    user=login_dialog.ui.editUser.text(),
                    password=login_dialog.ui.editPassword.text())
                try:
                    login_info = self.api.check_login(
                        version_info=self._version_info())

# QGIS private Cloud has no tos_accepted
                    try:
                        if not login_info['tos_accepted']:
                            result = QMessageBox.information(
                                None,
                                self.tr("Accept new Privacy Policy"),
                                self.tr("""Due to the GDPR qgiscloud.com has a new <a href='http://qgiscloud.com/en/pages/privacy'> Privacy Policy </a>. 
                                To continue using qgiscloud.com, you must accept the new policy. """),
                                QMessageBox.StandardButtons(
                                    QMessageBox.No |
                                    QMessageBox.Yes))
                            
                            if result == QMessageBox.No:
                                login_ok = False
                                return
                            else:
                                result = self.api.accept_tos()
                    except:
                        pass
                            
                    self.user = login_dialog.ui.editUser.text()
                    self._update_clouddb_mode(login_info['clouddb'])
                    version_ok = StrictVersion(self.version) >= StrictVersion(login_info['current_plugin'])
                    if not version_ok:
                        self.ui.lblVersionPlugin.setPalette(self.palette_red)
                        QMessageBox.information(None, self.tr('New Version'),  self.tr('New plugin release {version} is available! Please upgrade the QGIS Cloud plugin.').format(version=login_info['current_plugin']))
                    self.store_settings()
                    self.ui.btnLogin.hide()
                    self.ui.lblSignup.hide()
                    self.ui.btnLogout.show()
                    self.ui.widgetDatabases.setEnabled(True)
                    self.ui.widgetMaps.setEnabled(True)

                    self.ui.lblLoginStatus.setText(
                        self.tr("Logged in as {0} ({1})").format(self.user, login_info['plan']))
                    self.ui.lblLoginStatus.show()
                    self._push_message(
                        self.tr("QGIS Cloud"),
                        self.tr("Logged in as {0}").format(self.user),
                        level=0, duration=2)
                    self.refresh_databases()
                    self.refresh_maps()
                    if not version_ok:
                        self._push_message(self.tr("QGIS Cloud"), self.tr(
                            "Unsupported versions detected. Please check your versions first!"), level=1)
                        version_ok = False
                        self.ui.tabWidget.setCurrentWidget(self.ui.aboutTab)
                    login_ok = True
                    self.update_local_layers()
            
                except ForbiddenError:
                    QMessageBox.critical(
                        self, self.tr("Account Disabled"),
                        self.tr("Account {username} is disabled! Please contact [email protected]").format(username=login_dialog.ui.editUser.text()))
                    login_ok = False                    
                except UnauthorizedError:
                    QMessageBox.critical(
                        self, self.tr("Login for user {username} failed").format(username=login_dialog.ui.editUser.text()),
                        self.tr("Wrong user name or password"))
                    login_ok = False
                except (TokenRequiredError, ConnectionException) as e:
                    QMessageBox.critical(
                        self, self.tr("Login failed"),
                        self.tr("Login failed: %s") % str(e))
                    login_ok = False
        return version_ok

    def create_database(self):
        if self.numDbs < self.maxDBs:
            db = self.api.create_database()
            self.show_api_error(db)
            self.refresh_databases()
        else:
            QMessageBox.warning(None, self.tr('Warning!'),  self.tr('Number of %s permitted databases exceeded! Please upgrade your account!') % self.maxDBs)

    def delete_database(self):
        name = self.ui.tabDatabases.currentItem().text()
        
        answer = False
        
        for layer in list(self.PROJECT_INSTANCE.mapLayers().values()):            
            if QgsDataSourceUri(layer.publicSource()).database() == name:
                
                if not answer:
                    answer = QMessageBox.question(
                        self,
                        self.tr("Warning"),
                        self.tr('You have layers from database "{name}" loaded in your project! Do you want to remove them before you delete database "{name}"?').format(name=name),
                        QMessageBox.StandardButtons(
                            QMessageBox.Cancel |
                            QMessageBox.Yes))

                if answer == QMessageBox.Yes:
                     self.PROJECT_INSTANCE.removeMapLayer(layer.id())
                     
        if answer == QMessageBox.Cancel:
            QMessageBox.warning(None,  self.tr('Warning'),  self.tr('Deletion of database "{name}" interrupted!').format(name=name))
            return
            
        msgBox = QMessageBox()
        msgBox.setWindowTitle(self.tr("Delete QGIS Cloud database."))
        msgBox.setText(
            self.tr("Do you want to delete the database \"%s\"?") % name)
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        msgBox.setIcon(QMessageBox.Question)
        ret = msgBox.exec_()
        
        if ret == QMessageBox.Ok:
            self.setCursor(Qt.WaitCursor)
            result = self.api.delete_database(name)
            self.show_api_error(result)
            self.ui.btnDbDelete.setEnabled(False)
            time.sleep(2)
            self.refresh_databases()
            self.unsetCursor()

    def select_database(self):
        self.ui.btnDbDelete.setEnabled(len(self.ui.tabDatabases.selectedItems()) > 0)
            
    def select_map(self):
        self.ui.btnMapDelete.setEnabled(len(self.ui.tabMaps.selectedItems()) > 0)
        self.ui.btnMapLoad.setEnabled(len(self.ui.tabMaps.selectedItems()) > 0)
        self.update_urls(map=self.ui.tabMaps.currentItem().text())

    @pyqtSlot()
    def on_btnLogout_clicked(self):
        self.api.reset_auth()
        self.ui.btnLogout.hide()
        self.ui.lblLoginStatus.hide()
        self.ui.btnLogin.show()
        self.ui.widgetServices.hide()
        self.ui.tabDatabases.clear()
        self.ui.tabMaps.clear()
        self.ui.lblDbSize.setText("")
        self.ui.lblDbSizeUpload.setText("")
        self.ui.cbUploadDatabase.clear()
        self.ui.widgetDatabases.setEnabled(False)
        self.activate_upload_button()

    def refresh_databases(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        if self.clouddb:
            db_list = self.api.read_databases()
            if self.show_api_error(db_list):
                QApplication.restoreOverrideCursor()
                return
            self.db_connections = DbConnections()
            for db in db_list:
                self.db_connections.add_from_json(db)

            self.ui.tabDatabases.clear()
            self.ui.btnDbDelete.setEnabled(False)
            self.ui.cbUploadDatabase.clear()
            self.ui.cbUploadDatabase.setEditable(True)
            self.ui.cbUploadDatabase.lineEdit().setReadOnly(True)
            if self.db_connections.count() == 0:
                self.ui.cbUploadDatabase.setEditText(self.tr("No databases"))
            else:
                for name, db in list(self.db_connections.iteritems()):
                    it = QListWidgetItem(name)
                    it.setToolTip(db.description())
                    self.ui.tabDatabases.addItem(it)
                    self.ui.cbUploadDatabase.addItem(name)
                if self.ui.cbUploadDatabase.count() > 1:
                    # Display the "Select database" text if more than one db is available
                    self.ui.cbUploadDatabase.setCurrentIndex(-1)
                    self.ui.cbUploadDatabase.setEditText(self.tr("Select database"))
            self.db_connections.refresh(self.user)

        self.db_size(self.db_connections)
        QApplication.restoreOverrideCursor()
        
    def map_load(self,  item=None,  row=None):     
        self.ui.widgetServices.close()
        self.setCursor(Qt.WaitCursor)
        map_id = self.ui.tabMaps.currentItem().data(Qt.UserRole)
        map_name = self.ui.tabMaps.currentItem().text()
        result = self.api.load_map_project(map_name,  map_id)
        qgs_file_name = '%s/%s.qgs' % (tempfile.gettempdir(), map_name)
        qgs_file = open(qgs_file_name,  'w')
        qgs_file.write(result)
        qgs_file.close()
        project = QgsProject.instance()
        if project.isDirty():
            ok = QMessageBox.information(
                self,
                self.tr("Save Project"),
                self.tr("""Your actual project has changes. Do you want to save the project?"""),
                QMessageBox.StandardButtons(
                    QMessageBox.Abort |
                    QMessageBox.Discard |
                    QMessageBox.Save))
            if ok:
                project.write()           
                
        project.read(qgs_file_name)
        project.setDirty(False)
        self.iface.mainWindow().setWindowTitle("QGIS %s - %s" % (Qgis.QGIS_VERSION,  map_name))
        self.unsetCursor()
            
    def delete_map(self):
        name = self.ui.tabMaps.currentItem().text()
        map_id = self.ui.tabMaps.currentItem().data(Qt.UserRole)
        
        msgBox = QMessageBox()
        msgBox.setWindowTitle(self.tr("Delete QGIS Cloud map."))
        msgBox.setText(
            self.tr("Do you want to delete the map \"%s\"?") % name)
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        msgBox.setIcon(QMessageBox.Question)
        ret = msgBox.exec_()
        
        if ret == QMessageBox.Ok:
            self.ui.widgetServices.close()
            self.setCursor(Qt.WaitCursor)
            success = self.api.delete_map(map_id)
            
            if success:
                self.ui.btnMapDelete.setEnabled(False)
                self.refresh_maps()
            else:
                self.show_api_error(success)
                
            self.unsetCursor()
            self.ui.widgetServices.close()
        else:
            QMessageBox.warning(None,  self.tr('Warning'),  self.tr('Deletion of map "{name}" interrupted!').format(name=name))
            
            
    def refresh_maps(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        if self.clouddb:
            map_list = self.api.read_maps()
            if self.show_api_error(map_list):
                QApplication.restoreOverrideCursor()
                return

            self.ui.tabMaps.clear()
            self.ui.btnMapDelete.setEnabled(False)
            self.ui.btnMapLoad.setEnabled(False)
            
            for map in map_list:
                it = QListWidgetItem(map['map']['name'])
                self.ui.tabMaps.addItem(it)
                it.setData(Qt.UserRole,  map['map']['id'])

        QApplication.restoreOverrideCursor()        

    def api_url(self):
        return str(self.ui.editServer.text())
        
    def update_urls(self,  map=None):
        
        if map == None:
            map = self.map()
        
        try:
            map = map.decode('utf-8')
        except:
            pass
            
        self.update_url(self.ui.lblWebmap, self.api_url(),
                        'https://', u'{0}/{1}/'.format(self.user, map))
                        
        if self.clouddb:
            self.update_url(
                self.ui.lblWMS, self.api_url(),
                'https://wms.', u'{0}/{1}/'.format(self.user, map))
        else:
            self.update_url(self.ui.lblWMS, self.api_url(
            ), 'https://', u'{0}/{1}/wms'.format(self.user, map))
        self.update_url(self.ui.lblMaps, self.api_url(), 'https://', 'maps')
        self.ui.widgetServices.show()

    def update_url(self, label, api_url, prefix, path):
        try:
            base_url = string.replace(api_url, 'https://api.', prefix)
        except:
            base_url = api_url.replace('https://api.', prefix)
            
        url = u'{0}/{1}'.format(base_url, path)
        text = re.sub(r'http[^"]+', url, str(label.text()))
        label.setText(text)

    def read_maps(self):
        if self.check_login():
            self.api.read_maps()

    def check_project_saved(self):
        project = QgsProject.instance()
        fname = project.fileName()
        if project.isDirty() or fname == '':
            msgBox = QMessageBox()
            msgBox.setWindowTitle(self.tr("Project Modified"))
            msgBox.setText(self.tr("The project has been modified."))
            msgBox.setInformativeText(
                self.tr("The project needs to be saved before it can be published. Proceed?"))
            msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Cancel)
            msgBox.setDefaultButton(QMessageBox.Save)
            if msgBox.exec_() == QMessageBox.Save:
                self.iface.actionSaveProject().trigger()
                return not project.isDirty()
            else:
                return False
        return True

    def publish_map(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        canvas = self.iface.mapCanvas()
        srs=QgsMapSettings().destinationCrs()
        
        if "USER" in srs.authid():
            QMessageBox.warning(None, self.tr('Warning!'),  self.tr("The project has a user defined CRS. The use of user defined CRS is not supported. Please correct the project CRS before publishing!"))
            QApplication.restoreOverrideCursor()
            return 
            
        layer_dict = QgsProject.instance().mapLayers()
        layers = list(layer_dict.values())                    
        layerList = ''
        
        for layer in layers:
            if "USER" in layer.crs().authid():
                 layerList += "'"+layer.name()+"' "
        
        if len(layerList) > 0:
            QMessageBox.warning(None, self.tr('Warning!'),  self.tr("The layer(s) {layerlist}have user defined CRS. The use of user defined CRS is not supported. Please correct the CRS before publishing!").format(layerlist=layerList))
            QApplication.restoreOverrideCursor()
            return
                 
        saved = self.check_project_saved()
        if not saved:
            self.statusBar().showMessage(self.tr("Cancelled"))
        elif self.check_login() and self.check_layers():
            self.statusBar().showMessage(self.tr("Publishing map"))
            try:
                fullExtent = self.iface.mapCanvas().fullExtent()
                config = {
                    'fullExtent': {
                        'xmin': fullExtent.xMinimum(),
                        'ymin': fullExtent.yMinimum(),
                        'xmax': fullExtent.xMaximum(),
                        'ymax': fullExtent.yMaximum()
                        #},
                        # 'svgPaths': QgsApplication.svgPaths() #For resolving absolute symbol paths in print composer
                    }
                }
                
                fname = str(QgsProject.instance().fileName())
                    
                map = self.api.create_map(self.map(), fname, config)['map']
                self.show_api_error(map)
                if map['config']['missingSvgSymbols']:
                    self.publish_symbols(map['config']['missingSvgSymbols'])
                self.update_urls()
                self._push_message(self.tr("QGIS Cloud"), self.tr(
                    "Map successfully published"), level=0, duration=2)
                self.statusBar().showMessage(
                    self.tr("Map successfully published"))
            except Exception as e:
                self.statusBar().showMessage("")
                ErrorReportDialog(self.tr("Error uploading project"), self.tr("An error occured."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()
        self.refresh_maps()
        QApplication.restoreOverrideCursor()

    def publish_symbols(self, missingSvgSymbols):
        self.statusBar().showMessage(self.tr("Uploading SVG symbols"))
        search_paths = QgsApplication.svgPaths()
        if hasattr(QgsProject.instance(), 'homePath'):
            search_paths += [QgsProject.instance().homePath()]
        # Search and upload symbol files
        for sym in missingSvgSymbols:
            # Absolute custom path
            if os.path.isfile(sym):
                self.api.create_graphic(sym, sym)
            else:
                for path in search_paths:
                    fullpath = os.path.join(str(path), sym)
                    if os.path.isfile(fullpath):
                        self.api.create_graphic(sym, fullpath)
        self.statusBar().showMessage("")

    def reset_load_data(self):
        self.ui.widgetServices.hide()
        self.update_local_data_sources([],  [])
        self.ui.btnUploadData.setEnabled(False)
        self.ui.tabMaps.clearSelection()

    def remove_layer(self, layer_id):
        if self.do_update_local_data_sources:
            # skip layer if layer will be removed
            self.update_local_layers(layer_id)
            self.activate_upload_button()

    def add_layer(self):
        if self.do_update_local_data_sources:
            self.update_local_layers()
            self.activate_upload_button()

    def update_local_layers(self, skip_layer_id=None):
        local_layers, unsupported_layers,  local_raster_layers = self.local_data_sources.local_layers(skip_layer_id)
        try:
            self.update_local_data_sources(local_layers,  local_raster_layers)
        except Exception as e:
            ErrorReportDialog(self.tr("Error checking local data sources"), self.tr("An error occured."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()

        return local_layers, unsupported_layers,  local_raster_layers

    def check_layers(self):
        local_layers, unsupported_layers,  local_raster_layers = self.update_local_layers()
        
        
        if ((local_layers or local_raster_layers) and self.clouddb) or unsupported_layers:
            message = ""

            if local_layers or local_raster_layers:
                title = self.tr("Local layers found")
                message += self.tr(
                    "Some layers are using local data. Please upload local layers to your cloud database in the 'Upload Data' tab before publishing.\n\n")

            if unsupported_layers:
                title = self.tr("Unsupported layers found")
                message += self.tr(
                    "Raster, plugin or geometryless layers are not supported:\n\n")
                layer_types = ["No geometry", "Raster", "Plugin"]
                for layer in sorted(unsupported_layers, key=lambda layer: layer.name()):
                    message += self.tr("  -  %s (%s)\n") % (
                        layer.name(), layer_types[layer.type()])
                message += self.tr(
                    "\nPlease remove or replace above layers before publishing your map.\n")
                message += self.tr(
                    "For raster data you can use public WMS layers or the OpenLayers Plugin.")

            QMessageBox.warning(self, title, message)

            self.refresh_databases()
            self.ui.tabWidget.setCurrentWidget(self.ui.uploadTab)
            return False

        return True

    def update_local_data_sources(self, local_layers,  local_raster_layers):
        # update table names lookup
        local_layers += local_raster_layers
        self.update_data_sources_table_names()
        
        self.local_data_sources.update_local_data_sources(local_layers)

        # update GUI
        self.ui.tblLocalLayers.setRowCount(0)
        
        for data_source, layers in list(self.local_data_sources.iteritems()):
            layer_names = []
            for layer in layers:
                layer_names.append(str(layer.name()))
            layers_item = QTableWidgetItem(", ".join(layer_names))
            layers_item.setToolTip("\n".join(layer_names))
            data_source_item = QTableWidgetItem(data_source)
            data_source_item.setToolTip(data_source)
            # find a better table name if there are multiple layers with same
            # data source?
            table_name = layers[0].name()
            if data_source in self.data_sources_table_names:
                # use current table name if available to keep changes by user
                table_name = self.data_sources_table_names[data_source]
            
            table_name_item = QTableWidgetItem(self.launder_pg_name(table_name))
        
            if layers[0].providerType() == 'gdal':
                geometry_type_item = QTableWidgetItem('Raster')
            else:
                wkbType = layers[0].wkbType()
                
                if wkbType not in self.GEOMETRY_TYPES:
                    QMessageBox.warning(self.iface.mainWindow(), self.tr("Unsupported geometry type"), self.tr(
                        "Unsupported geometry type '{type}' in layer '{layer}'").format(type=self.__wkbTypeString(wkbType), layer=layers[0].name()))
                    continue
                geometry_type_item = QTableWidgetItem(self.GEOMETRY_TYPES[wkbType])
                if layers[0].providerType() == "ogr":
                    geometry_type_item.setToolTip(
                        self.tr("Note: OGR features will be converted to MULTI-type"))
                        
            srid_item = QTableWidgetItem(layers[0].crs().authid())
    
            row = self.ui.tblLocalLayers.rowCount()
            self.ui.tblLocalLayers.insertRow(row)
            self.ui.tblLocalLayers.setItem(
                row, self.COLUMN_LAYERS, layers_item)
            self.ui.tblLocalLayers.setItem(
                row, self.COLUMN_DATA_SOURCE, data_source_item)
            self.ui.tblLocalLayers.setItem(
                row, self.COLUMN_TABLE_NAME, table_name_item)
            self.ui.tblLocalLayers.setItem(
                row, self.COLUMN_GEOMETRY_TYPE, geometry_type_item)
            self.ui.tblLocalLayers.setItem(row, self.COLUMN_SRID, srid_item)

        if self.local_data_sources.count() > 0:
            self.ui.tblLocalLayers.resizeColumnsToContents()
            self.ui.tblLocalLayers.setColumnWidth(self.COLUMN_LAYERS, 100)
            self.ui.tblLocalLayers.setColumnWidth(self.COLUMN_DATA_SOURCE, 100)
            self.ui.tblLocalLayers.sortItems(self.COLUMN_DATA_SOURCE)
            self.ui.tblLocalLayers.setSortingEnabled(False)
        else:
            self.ui.btnUploadData.setEnabled(False)

        self.statusBar().showMessage(self.tr("Updated local data sources"))

    def __wkbTypeString(self, wkbType):
        if wkbType == Qgis.WkbUnknown:
            return "WkbUnknown"
        elif wkbType == Qgis.WkbPoint:
            return "WkbPoint"
        elif wkbType == Qgis.WkbLineString:
            return "WkbLineString"
        elif wkbType == Qgis.WkbMultiLineString:
            return "WkbMultiLineString"
        elif wkbType == Qgis.WkbPolygon:
            return "WkbPolygon"
        elif wkbType == Qgis.WkbMultiPoint:
            return "WkbMultiPoint"
        elif wkbType == Qgis.WkbMultiPolygon:
            return "WkbMultiPolygon"
        elif wkbType == Qgis.WkbNoGeometry:
            return "WkbNoGeometry"
        elif wkbType == Qgis.WkbPoint25D:
            return "WkbPoint25D"
        elif wkbType == Qgis.WkbLineString25D:
            return "WkbLineString25D"
        elif wkbType == Qgis.WkbPolygon25D:
            return "WkbPolygon25D"
        elif wkbType == Qgis.WkbMultiPoint25D:
            return "WkbMultiPoint25D"
        elif wkbType == Qgis.WkbMultiLineString25D:
            return "WkbMultiLineString25D"
        elif wkbType == Qgis.WkbMultiPolygon25D:
            return "WkbMultiPolygon25D"
        elif wkbType == QgsWkbTypes.LineStringZM:
            return "WkbLineStringZM"
        elif wkbType == QgsWkbTypes.MultiLineStringZM:
            return "WkbMultiLineStringZM"
        
        return self.tr("Unknown type")

#    @staticmethod
    def launder_pg_name(self,  name):
        # OGRPGDataSource::LaunderName
        # return re.sub(r"[#'-]", '_', unicode(name).lower())
        input_string = str(name).lower().encode('ascii', 'replace')
        input_string = input_string.replace(b" ",b"_")    
        input_string = input_string.replace(b".",b"_")    

        # check if table_name starts with number
        
        if re.search("^\d", input_string.decode('utf-8')):
           input_string = '_'+input_string.decode('utf-8') 
        
        try:
            return input_string.decode('utf-8')
        except:
            return input_string

    def refresh_local_data_sources(self):
        self.do_update_local_data_sources = True
        self.update_local_layers()
        self.activate_upload_button()
#
    def update_data_sources_table_names(self):
        if self.local_data_sources.count() == 0:
            self.data_sources_table_names.clear()
        else:
            # remove table names without data sources
            keys_to_remove = []
            for key in list(self.data_sources_table_names.keys()):
                if self.local_data_sources.layers(key) is None:
                    keys_to_remove.append(key)

            for key in keys_to_remove:
                del self.data_sources_table_names[key]

            # update table names
            for row in range(0, self.ui.tblLocalLayers.rowCount()):
                data_source = self.ui.tblLocalLayers.item(row, self.COLUMN_DATA_SOURCE).text()
                table_name = self.ui.tblLocalLayers.item(row, self.COLUMN_TABLE_NAME).text()
                self.data_sources_table_names[data_source] = table_name

    def activate_upload_button(self):
        if not self.storage_exceeded:
            self.ui.btnUploadData.setEnabled(self.local_data_sources.count() > 0)
            self.ui.btnPublishMap.setDisabled(self.storage_exceeded)
        else:
            self.ui.btnUploadData.setDisabled(self.storage_exceeded)
            self.ui.btnPublishMap.setDisabled(self.storage_exceeded)

    def upload_data(self):
        if self.check_login():
            if self.local_data_sources.count() == 0:
                return

            if self.db_connections.count() == 0:
                QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab."))
                return

            if not self.ui.cbUploadDatabase.currentIndex() >= 0:
                QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data."))
                return

            db_name = self.ui.cbUploadDatabase.currentText()

            if not self.db_connections.isPortOpen(db_name):
                uri = self.db_connections.cloud_layer_uri(db_name, "", "")
                host = str(uri.host())
                port = uri.port()
                QMessageBox.critical(self, self.tr("Network Error"),
                                     self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port)))
                return

            # disable update of local data sources during upload, as there are
            # temporary layers added and removed
            self.do_update_local_data_sources = False
            self.statusBar().showMessage(self.tr("Uploading data..."))
            self.setCursor(Qt.WaitCursor)
            self.ui.btnUploadData.hide()
            self.ui.spinner.start()
            self.ui.progressWidget.show()

            # Map<data_source, {table: table, layers: layers}>
            data_sources_items = {}
            for row in range(0, self.ui.tblLocalLayers.rowCount()):
                data_source = unicode(
                    self.ui.tblLocalLayers.item(
                        row, self.COLUMN_DATA_SOURCE).text())
                layers = self.local_data_sources.layers(data_source)
                if layers is not None:
                    table_name = unicode(
                        self.ui.tblLocalLayers.item(
                            row, self.COLUMN_TABLE_NAME).text())
                    data_sources_items[data_source] = {
                        u'table': unicode(table_name), u'layers': layers}

            login_info = self.api.check_login(version_info=self._version_info())
            try:            
                self.maxSize = login_info['max_storage']
                self.maxDBs = login_info['max_dbs']
            except:
                self.maxSize = 50
                self.maxDBs = 5

            try:
                self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize))
                upload_ok = True
            except Exception as e:
                ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()
                upload_ok = False

            self.ui.spinner.stop()
            self.ui.progressWidget.hide()
            self.ui.btnUploadData.show()
            self.unsetCursor()
            self.statusBar().showMessage("")
            # Refresh local layers
            self.do_update_local_data_sources = True
            self.update_local_layers()
            # Refresh used space after upload
            self.db_size(self.db_connections)

            if upload_ok:
                # Show save project dialog
                save_dialog = QDialog(self)
                save_dialog.setWindowTitle(self.tr("Save Project"))
                save_dialog.setLayout(QVBoxLayout())
                header = QWidget()
                header.setLayout(QVBoxLayout())
                label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database."))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                label = QLabel(self.tr("Choose were to save the modified project:"))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                save_dialog.layout().setContentsMargins(0, 0, 0, 0)
                save_dialog.layout().addWidget(header)
                initialPath = QgsProject.instance().fileName()
                if not initialPath:
                    initialPath = QSettings().value("/UI/lastProjectDir", ".")
                fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files"))
                fd.setParent(save_dialog, Qt.Widget)
                fd.setOption(QFileDialog.DontUseNativeDialog)
                fd.setAcceptMode(QFileDialog.AcceptSave)
                save_dialog.layout().addWidget(fd)
                header.layout().setContentsMargins(fd.layout().contentsMargins())
                fd.accepted.connect(save_dialog.accept)
                fd.rejected.connect(save_dialog.reject)
                if save_dialog.exec_() == QDialog.Accepted:
                    files = list(fd.selectedFiles())
                    if files:
                        QgsProject.instance().setFileName(files[0])
                        self.iface.actionSaveProject().trigger()

                # Switch to map tab
                self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)

    def _push_message(self, title, text, level=0, duration=0):
        # QGIS >= 2.0
        if hasattr(self.iface, 'messageBar') and hasattr(self.iface.messageBar(), 'pushMessage'):
            self.iface.messageBar().pushMessage(title, text, level, duration)
        else:
            QMessageBox.information(self, title, text)

    def show_api_error(self, result):
        if 'error' in result:
            QMessageBox.critical(
                self, self.tr("QGIS Cloud Error"), "%s" % result['error'])
            self.statusBar().showMessage(self.tr("Error"))
            return True
        else:
            return False

#    def tr_uni(self, str):
#        return str(self.tr(str))

    def db_size(self,  db_connections):
        usedSpace = 0
        self.numDbs = len(list(db_connections._dbs.keys()))
        for db in list(db_connections._dbs.keys()):
            try:
                conn = db_connections.db(db).psycopg_connection()
            except:
                continue
            cursor = conn.cursor()
            sql = "SELECT pg_database_size('" + str(db) + "')"
            cursor.execute(sql)
            usedSpace += int(cursor.fetchone()[0])-(11*1024*1024)
            cursor.close()
            conn.close

        # Used space in MB
        usedSpace /= 1024 * 1024

        login_info = self.api.check_login(version_info=self._version_info())
        
        try:            
            self.maxSize = login_info['max_storage']
            self.maxDBs = login_info['max_dbs']
        except:
            self.maxSize = 50
            self.maxDBs = 5

        lblPalette = QPalette(self.ui.lblDbSize.palette())
        usage = usedSpace / float(self.maxSize)
        self.storage_exceeded = False
    
        if usage < 0.8:
            bg_color = QColor(255, 0, 0, 0)
            text_color = QColor(Qt.black)
        elif usage >= 0.8 and usage < 1:
            bg_color = QColor(255, 0, 0, 100)
            text_color = QColor(Qt.white)
        elif usage >= 1:
            bg_color = QColor(255, 0, 0, 255)
            text_color = QColor(Qt.white)
            self.storage_exceeded = True

        lblPalette.setColor(QPalette.Window, QColor(bg_color))
        lblPalette.setColor(QPalette.Foreground,QColor(text_color))
        
        self.ui.lblDbSize.setAutoFillBackground(True)
        self.ui.lblDbSize.setPalette(lblPalette)
        self.ui.lblDbSize.setText(
            self.tr("Used DB Storage: ") + "%d / %d MB" % (usedSpace, self.maxSize))

        self.ui.lblDbSizeUpload.setAutoFillBackground(True)
        self.ui.lblDbSizeUpload.setPalette(lblPalette)
        self.ui.lblDbSizeUpload.setText(
            self.tr("Used DB Storage: ") + "%d / %d MB" % (usedSpace, self.maxSize))
        self.ui.btnUploadData.setDisabled(self.storage_exceeded)
        self.ui.btnPublishMap.setDisabled(self.storage_exceeded)
    def __init__(self, iface, version):
        QDockWidget.__init__(self, None)
        self.iface = iface
        self.clouddb = True
        self.version = version
        # Set up the user interface from Designer.
        self.ui = Ui_QgisCloudPlugin()
        self.ui.setupUi(self)
        self.storage_exceeded = True
        
        myAbout = DlgAbout()
        self.ui.aboutText.setText(
            myAbout.aboutString() +
            myAbout.contribString() +
            myAbout.licenseString() +
            "<p>Versions:<ul>" +
            "<li>QGIS: %s</li>" % str(Qgis.QGIS_VERSION).encode("utf-8") +
            "<li>Python: %s</li>" % sys.version.replace("\n", " ") +
            "<li>OS: %s</li>" % platform.platform() +
            "</ul></p>")
            
        data_protection_link = """<a href="http://qgiscloud.com/pages/privacy">%s</a>""" % (self.tr("Privacy Policy"))
            
        self.ui.lblVersionPlugin.setText("%s &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%s" % (self.version,  data_protection_link))
        self.ui.lblVersionPlugin.setOpenExternalLinks(True)            
#        self.ui.lblVersionPlugin.setText(self.version)

        self.ui.tblLocalLayers.setColumnCount(5)
        header = ["Layers", "Data source",
                  "Table name", "Geometry type", "SRID"]
        self.ui.tblLocalLayers.setHorizontalHeaderLabels(header)
        self.ui.tblLocalLayers.resizeColumnsToContents()
        self.ui.tblLocalLayers.setEditTriggers(QAbstractItemView.NoEditTriggers)

        self.ui.btnUploadData.setEnabled(False)
        self.ui.btnPublishMap.setEnabled(False)
        self.ui.btnMapDelete.setEnabled(False)
        self.ui.progressWidget.hide()
        self.ui.btnLogout.hide()
        self.ui.lblLoginStatus.hide()
        self.ui.widgetServices.hide()
        self.ui.widgetDatabases.setEnabled(False)
        self.ui.widgetMaps.setEnabled(False)
        self.ui.labelOpenLayersPlugin.hide()

        try:
            from .openlayers_menu import OpenlayersMenu
            self.ui.btnBackgroundLayer.setMenu(OpenlayersMenu(self.iface))
        except:
                self.ui.btnBackgroundLayer.hide()
                self.ui.labelOpenLayersPlugin.show()

        # map<data source, table name>
        self.data_sources_table_names = {}
        # flag to disable update of local data sources during upload
        self.do_update_local_data_sources = True

        self.ui.btnLogin.clicked.connect(self.check_login)
        self.ui.btnDbCreate.clicked.connect(self.create_database)
        self.ui.btnDbDelete.clicked.connect(self.delete_database)
        self.ui.btnDbRefresh.clicked.connect(self.refresh_databases)
        self.ui.btnMapDelete.clicked.connect(self.delete_map)
        self.ui.btnMapLoad.clicked.connect(self.map_load)
        self.ui.tabMaps.itemDoubleClicked.connect(self.map_load)
        self.ui.tabDatabases.itemSelectionChanged.connect(self.select_database)
        self.ui.tabMaps.itemSelectionChanged.connect(self.select_map)
        self.ui.btnPublishMap.clicked.connect(self.publish_map)
        self.ui.btnRefreshLocalLayers.clicked.connect(self.refresh_local_data_sources)
        self.iface.newProjectCreated.connect(self.reset_load_data)
        self.iface.projectRead.connect(self.reset_load_data)

        self.PROJECT_INSTANCE.layerWillBeRemoved.connect(self.remove_layer)
        self.PROJECT_INSTANCE.layerWasAdded.connect(self.add_layer)
        
        self.ui.cbUploadDatabase.currentIndexChanged.connect(lambda idx: self.activate_upload_button())
        self.ui.btnUploadData.clicked.connect(self.upload_data)

        self.ui.editServer.textChanged.connect(self.serverURL)
        self.ui.resetUrlBtn.clicked.connect(self.resetApiUrl)

        self.read_settings()
        self.api = API()
        self.db_connections = DbConnections()
        self.local_data_sources = LocalDataSources()
        self.data_upload = DataUpload(
            self.iface, self.statusBar(), self.ui.lblProgress, self.api,
            self.db_connections)

        if self.URL == "":
            self.ui.editServer.setText(self.api.api_url())
        else:
            self.ui.editServer.setText(self.URL)

        self.palette_red = QPalette(self.ui.lblVersionPlugin.palette())
        self.palette_red.setColor(QPalette.WindowText, Qt.red)
    def updateTitle(self):

        texto = self.email.model().data(self.email.model().index(0, 0))
        if texto is None:
            texto = self.name.text().strip()

        texto += u" \u21D2 " + self.organization.text() + "-" + self.city.text(
        ) + "-" + self.country.text()
        texto = re.sub(r"^\-*", "", texto.strip())
        texto = re.sub(r"\-*$", "", texto.strip())
        texto = re.sub(r'\-\-+', '-', texto.strip())
        if texto.strip() == u'\u21D2':
            palette = QPalette()
            palette.setColor(QPalette.Text, Qt.red)
            self.mGroupBox.setPalette(palette)
            self.mGroupBox.setTitle(u"Contacto Incompleto \u26a0")
            self.setToolTip(u"Contacto Incompleto.")
        elif self.email.model().rowCount() == 0 or self.organization.text(
        ) == "":
            palette = QPalette()
            palette.setColor(QPalette.Text, Qt.red)
            self.mGroupBox.setPalette(palette)
            self.mGroupBox.setTitle(texto)
            self.setToolTip(u"Contacto Incompleto.")
        else:
            palette = QPalette()
            palette.setColor(QPalette.Text, Qt.black)
            self.mGroupBox.setPalette(palette)
            self.mGroupBox.setTitle(texto)
            self.setToolTip(u"")
        self.check_mandatory_completude()
Esempio n. 12
0
    def __init__(self, parent=None):
        ''' Constructor '''
        super().__init__(parent)
        self.surface = VideoWidgetSurface(self)
        self.setAttribute(Qt.WA_OpaquePaintEvent)

        self.Tracking_Video_RubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.Censure_RubberBand = QRubberBand(QRubberBand.Rectangle, self)

        color_blue = QColor(Qt.blue)
        color_black = QColor(Qt.black)
        color_amber = QColor(252, 215, 108)

        pal_blue = QPalette()
        pal_blue.setBrush(QPalette.Highlight, QBrush(color_blue))
        self.Tracking_Video_RubberBand.setPalette(pal_blue)

        pal_black = QPalette()
        pal_black.setBrush(QPalette.Highlight, QBrush(color_black))
        self.Censure_RubberBand.setPalette(pal_black)

        self._interaction = InteractionState()
        self._filterSatate = FilterState()

        self._isinit = False
        self._MGRS = False
        self.gt = None

        self.drawCesure = []
        self.poly_coordinates, self.drawPtPos, self.drawLines, self.drawMeasureDistance, self.drawMeasureArea, self.drawPolygon = [], [], [], [], [], []
        # Draw Polygon Canvas Rubberband
        self.poly_Canvas_RubberBand = QgsRubberBand(
            iface.mapCanvas(), True)  # Polygon type
        # set rubber band style
        self.poly_Canvas_RubberBand.setColor(color_amber)
        self.poly_Canvas_RubberBand.setWidth(3)

        # Tracking Canvas Rubberband
        self.Track_Canvas_RubberBand = QgsRubberBand(
            iface.mapCanvas(), QgsWkbTypes.LineGeometry)
        # set rubber band style
        self.Track_Canvas_RubberBand.setColor(color_blue)
        self.Track_Canvas_RubberBand.setWidth(5)

        # Cursor Canvas Rubberband
        self.Cursor_Canvas_RubberBand = QgsRubberBand(
            iface.mapCanvas(), QgsWkbTypes.PointGeometry)
        self.Cursor_Canvas_RubberBand.setWidth(4)
        self.Cursor_Canvas_RubberBand.setColor(QColor(255, 100, 100, 250))
        self.Cursor_Canvas_RubberBand.setIcon(QgsRubberBand.ICON_FULL_DIAMOND)

        self.parent = parent.parent()

        palette = self.palette()
        palette.setColor(QPalette.Background, Qt.transparent)
        self.setPalette(palette)

        self.origin, self.dragPos = QPoint(), QPoint()
        self.tapTimer = QBasicTimer()
        self.brush = QBrush(color_black)
        self.blue_Pen = QPen(color_blue, 3)
class QgisCloudPluginDialog(QDockWidget):
    COLUMN_LAYERS = 0
    COLUMN_SCHEMA_NAME = 1
    COLUMN_TABLE_NAME = 2
    COLUMN_GEOMETRY_TYPE = 3
    COLUMN_SRID = 4
    COLUMN_DATA_SOURCE = 5


    GEOMETRY_TYPES = {
        QgsWkbTypes.Unknown: "Unknown",
        QgsWkbTypes.NoGeometry: "No geometry",
        QgsWkbTypes.Point: "Point",
        QgsWkbTypes.MultiPoint: "MultiPoint",               
        QgsWkbTypes.PointZ: "PointZ",
        QgsWkbTypes.MultiPointZ: "MultiPointZ",
        QgsWkbTypes.PointM: "PointM",
        QgsWkbTypes.MultiPointM: "MultiPointM",
        QgsWkbTypes.PointZM: "PointZM",
        QgsWkbTypes.MultiPointZM: "MultiPointZM",
        QgsWkbTypes.Point25D: "Point25D",
        QgsWkbTypes.MultiPoint25D: "MultiPoint25D",
        QgsWkbTypes.LineString: "LineString",
        QgsWkbTypes.MultiLineString: "LineString",
        QgsWkbTypes.LineStringZ: "LineStringZ",
        QgsWkbTypes.MultiLineStringZ: "LineStringZ",
        QgsWkbTypes.LineStringM: "LineStringM",
        QgsWkbTypes.MultiLineStringM: "LineStringM",
        QgsWkbTypes.LineStringZM: "LineStringZM",
        QgsWkbTypes.MultiLineStringZM: "LineStringZM",
        QgsWkbTypes.LineString25D: "LineString25D",
        QgsWkbTypes.MultiLineString25D: "MultiLineString25D",
        QgsWkbTypes.Polygon: "Polygon",            
        QgsWkbTypes.MultiPolygon: "MultiPolygon", 
        QgsWkbTypes.PolygonZ: "PolygonZ",            
        QgsWkbTypes.MultiPolygonZ: "MultiPolygonZ", 
        QgsWkbTypes.PolygonM: "PolygonM",            
        QgsWkbTypes.MultiPolygonM: "MultiPolygonM", 
        QgsWkbTypes.PolygonZM: "PolygonZM",            
        QgsWkbTypes.MultiPolygonZM: "MultiPolygonZM", 
        QgsWkbTypes.Polygon25D: "Polygon25D",            
        QgsWkbTypes.MultiPolygon25D: "MultiPolygon25D", 
        QgsWkbTypes.CircularString: "CircularString",
        QgsWkbTypes.CompoundCurve: "CompoundCurve",
        QgsWkbTypes.CurvePolygon: "CurvePolygon", 
        QgsWkbTypes.MultiCurve: "MultiCurve",
        QgsWkbTypes.MultiSurface: "MultiSurface",
        QgsWkbTypes.CircularStringZ: "CircularStringZ",
        QgsWkbTypes.CompoundCurveZ: "CompoundCurveZ",
        QgsWkbTypes.CurvePolygonZ: "CurvePolygonZ", 
        QgsWkbTypes.MultiCurveZ: "MultiCurveZ",
        QgsWkbTypes.MultiSurfaceZ: "MultiSurfaceZ",
        QgsWkbTypes.CircularStringM: "CircularStringM",
        QgsWkbTypes.CompoundCurveM: "CompoundCurveM",
        QgsWkbTypes.CurvePolygonM: "CurvePolygonM", 
        QgsWkbTypes.MultiCurveM: "MultiCurveM",
        QgsWkbTypes.MultiSurfaceM: "MultiSurfaceM",
        QgsWkbTypes.CircularStringZM: "CircularStringZM",
        QgsWkbTypes.CompoundCurveZM: "CompoundCurveZM",
        QgsWkbTypes.CurvePolygonZM: "CurvePolygonZM", 
        QgsWkbTypes.MultiCurveZM: "MultiCurveZM",
        QgsWkbTypes.MultiSurfaceZM: "MultiSurfaceZM",
    }
        
    PROJECT_INSTANCE = QgsProject.instance()     
    
    
    def __init__(self, iface, version):
        QDockWidget.__init__(self, None)
        self.iface = iface
        self.clouddb = True
        self.version = version
        # Set up the user interface from Designer.
        self.ui = Ui_QgisCloudPlugin()
        self.ui.setupUi(self)
        self.storage_exceeded = True
        
        myAbout = DlgAbout()
        self.ui.aboutText.setText(
            myAbout.aboutString() +
            myAbout.contribString() +
            myAbout.licenseString() +
            "<p>Versions:<ul>" +
            "<li>QGIS: %s</li>" % str(Qgis.QGIS_VERSION).encode("utf-8") +
            "<li>Python: %s</li>" % sys.version.replace("\n", " ") +
            "<li>OS: %s</li>" % platform.platform() +
            "</ul></p>")
            
        data_protection_link = """<a href="http://qgiscloud.com/pages/privacy">%s</a>""" % (self.tr("Privacy Policy"))
            
        self.ui.lblVersionPlugin.setText("%s &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%s" % (self.version,  data_protection_link))
        self.ui.lblVersionPlugin.setOpenExternalLinks(True)            

        self.ui.tblLocalLayers.setColumnCount(6)
        header = ["Layers","Table Schema","Table name", "Geometry type", "SRID","Data Source"]
        self.ui.tblLocalLayers.setHorizontalHeaderLabels(header)
        self.ui.tblLocalLayers.resizeColumnsToContents()
#        self.ui.tblLocalLayers.setEditTriggers(QAbstractItemView.NoEditTriggers)
        
        self.ui.btnUploadData.setEnabled(False)
        self.ui.btnPublishMap.setEnabled(False)
        self.ui.btnMapDelete.setEnabled(False)
        self.ui.progressWidget.hide()
        self.ui.btnLogout.hide()
        self.ui.lblLoginStatus.hide()
        self.ui.widgetServices.hide()
        self.ui.widgetDatabases.setEnabled(False)
        self.ui.widgetMaps.setEnabled(False)
        self.ui.labelOpenLayersPlugin.hide()

        try:
            from .openlayers_menu import OpenlayersMenu
            self.ui.btnBackgroundLayer.setMenu(OpenlayersMenu(self.iface))
        except:
                self.ui.btnBackgroundLayer.hide()
                self.ui.labelOpenLayersPlugin.show()

        # map<data source, table name>
        self.data_sources_table_names = {}
        # flag to disable update of local data sources during upload
        self.do_update_local_data_sources = True

        self.ui.btnLogin.clicked.connect(self.check_login)
        self.ui.btnDbCreate.clicked.connect(self.create_database)
        self.ui.btnDbDelete.clicked.connect(self.delete_database)
        self.ui.btnDbRefresh.clicked.connect(self.refresh_databases)
        self.ui.btnMapDelete.clicked.connect(self.delete_map)
        self.ui.btnMapLoad.clicked.connect(self.map_load)
        self.ui.tabMaps.itemDoubleClicked.connect(self.map_load)
        self.ui.tabDatabases.itemSelectionChanged.connect(self.select_database)
        self.ui.tabMaps.itemSelectionChanged.connect(self.select_map)
        self.ui.btnPublishMap.clicked.connect(self.publish_map)
        self.ui.btnRefreshLocalLayers.clicked.connect(self.refresh_local_data_sources)
        self.ui.cbUploadDatabase.currentTextChanged.connect(self.update_data_sources_table_names)
        self.iface.newProjectCreated.connect(self.reset_load_data)
        self.iface.projectRead.connect(self.reset_load_data)

        self.PROJECT_INSTANCE.layerWillBeRemoved.connect(self.remove_layer)
        self.PROJECT_INSTANCE.layerWasAdded.connect(self.add_layer)
        
        self.ui.cbUploadDatabase.currentIndexChanged.connect(lambda idx: self.activate_upload_button())
        self.ui.btnUploadData.clicked.connect(self.upload_data)

        self.ui.editServer.textChanged.connect(self.serverURL)
        self.ui.resetUrlBtn.clicked.connect(self.resetApiUrl)

        self.read_settings()
        self.api = API()
        self.db_connections = DbConnections()
        self.local_data_sources = LocalDataSources()
        self.data_upload = DataUpload(
            self.iface, self.statusBar(), self.ui.lblProgress, self.api,
            self.db_connections)

        if self.URL == "":
            self.ui.editServer.setText(self.api.api_url())
        else:
            self.ui.editServer.setText(self.URL)

        self.palette_red = QPalette(self.ui.lblVersionPlugin.palette())
        self.palette_red.setColor(QPalette.WindowText, Qt.red)

    def unload(self):
        self.do_update_local_data_sources = False
        if self.iface:
            self.iface.newProjectCreated.disconnect(self.reset_load_data)
            self.iface.projectRead.disconnect(self.reset_load_data)
        
        if self.PROJECT_INSTANCE:
            self.PROJECT_INSTANCE.layerWillBeRemoved.disconnect(self.remove_layer)
            self.PROJECT_INSTANCE.layerWasAdded.disconnect(self.add_layer)
        

    def statusBar(self):
        return self.iface.mainWindow().statusBar()

    def map(self):
        project = QgsProject.instance()
        name = os.path.splitext(os.path.basename(str(project.fileName())))[0]
            
        # Allowed chars for QGISCloud map name: /\A[A-Za-z0-9\_\-]*\Z/
#        name = str(name).encode('ascii', 'replace')  # Replace non-ascii chars
        name = str(re.sub(r'[^\x00-\x7F]+','_', name))
        # Replace withespace
        name = name.replace(" ",  "_")
        return name

    def resetApiUrl(self):
        self.ui.editServer.setText(self.api.api_url())

    def serverURL(self, URL):
        self.URL = URL
        self.store_settings()

    def store_settings(self):
        s = QSettings()
        s.setValue("qgiscloud/user", self.user)
        s.setValue("qgiscloud/URL", self.URL)

    def read_settings(self):
        s = QSettings()
        self.user = s.value("qgiscloud/user", "")
        self.URL = s.value("qgiscloud/URL", "")

    def _update_clouddb_mode(self, clouddb):
        self.clouddb = clouddb
        self.ui.widgetDatabases.setVisible(self.clouddb)
        tab_index = 1
        tab_name = QApplication.translate("QgisCloudPlugin", "Upload Data")
        visible = (self.ui.tabWidget.indexOf(self.ui.uploadTab) == tab_index)
        if visible and not self.clouddb:
            self.ui.tabWidget.removeTab(tab_index)
        elif not visible and self.clouddb:
            self.ui.tabWidget.insertTab(tab_index, self.ui.uploadTab, tab_name)

    def _version_info(self):
        return {
            'versions': {
                'plugin': self.version.encode('utf-8').decode('utf-8'),
                'QGIS': Qgis.QGIS_VERSION.encode('utf-8').decode('utf-8'),
                'OS': platform.platform().encode('utf-8').decode('utf-8'),
                'Python': sys.version.encode('utf-8').decode('utf-8')
            }
        }
        
    def _qgis3_info(self):
        cloud_info_off = QSettings().value("Plugin-QgisCloud/qgis3_info_off", defaultValue=False, type=bool)
        lastInfo = QSettings().value("Plugin-QgisCloud/qgis3_info_ts", defaultValue=0.0, type=float)
        
        day = 3600*24
        now = time.time()
        days = (now-lastInfo)/day
        
        if days >= 20 or not cloud_info_off:
            self.qgis3_info_dlg = Qgis3Warning()
            self.qgis3_info_dlg.show()
            QSettings().setValue("Plugin-QgisCloud/qgis3_info_ts", now)

    def check_login(self):
        version_ok = True
        if not self.api.check_auth():
            self._qgis3_info()

            login_dialog = QDialog(self)
            login_dialog.ui = Ui_LoginDialog()
            login_dialog.ui.setupUi(login_dialog)
            login_dialog.ui.editUser.setText(self.user)
            login_ok = False
            while not login_ok and version_ok:
                self.api.set_url(self.api_url())
                if not login_dialog.exec_():
                    self.api.set_auth(
                        user=login_dialog.ui.editUser.text(), password=None)
                    return login_ok
                self.api.set_auth(
                    user=login_dialog.ui.editUser.text(),
                    password=login_dialog.ui.editPassword.text())
                try:
                    login_info = self.api.check_login(
                        version_info=self._version_info())

# QGIS private Cloud has no tos_accepted
                    try:
                        if not login_info['tos_accepted']:
                            result = QMessageBox.information(
                                None,
                                self.tr("Accept new Privacy Policy"),
                                self.tr("""Due to the GDPR qgiscloud.com has a new <a href='http://qgiscloud.com/en/pages/privacy'> Privacy Policy </a>. 
                                To continue using qgiscloud.com, you must accept the new policy. """),
                                QMessageBox.StandardButtons(
                                    QMessageBox.No |
                                    QMessageBox.Yes))
                            
                            if result == QMessageBox.No:
                                login_ok = False
                                return
                            else:
                                result = self.api.accept_tos()
                    except:
                        pass
                            
                    self.user = login_dialog.ui.editUser.text()
                    self._update_clouddb_mode(login_info['clouddb'])
                    version_ok = StrictVersion(self.version) >= StrictVersion(login_info['current_plugin'])
                    if not version_ok:
                        self.ui.lblVersionPlugin.setPalette(self.palette_red)
                        QMessageBox.information(None, self.tr('New Version'),  self.tr('New plugin release {version} is available! Please upgrade the QGIS Cloud plugin.').format(version=login_info['current_plugin']))
                    self.store_settings()
                    self.ui.btnLogin.hide()
                    self.ui.lblSignup.hide()
                    self.ui.btnLogout.show()
                    self.ui.widgetDatabases.setEnabled(True)
                    self.ui.widgetMaps.setEnabled(True)

                    self.ui.lblLoginStatus.setText(
                        self.tr("Logged in as {0} ({1})").format(self.user, login_info['plan']))
                    self.ui.lblLoginStatus.show()
                    self._push_message(
                        self.tr("QGIS Cloud"),
                        self.tr("Logged in as {0}").format(self.user),
                        level=0, duration=2)
                    self.refresh_databases()
                    self.refresh_maps()
                    if not version_ok:
                        self._push_message(self.tr("QGIS Cloud"), self.tr(
                            "Unsupported versions detected. Please check your versions first!"), level=1)
                        version_ok = False
                        self.ui.tabWidget.setCurrentWidget(self.ui.aboutTab)
                    login_ok = True
                    self.update_local_layers()
            
                except ForbiddenError:
                    QMessageBox.critical(
                        self, self.tr("Account Disabled"),
                        self.tr("Account {username} is disabled! Please contact [email protected]").format(username=login_dialog.ui.editUser.text()))
                    login_ok = False                    
                except UnauthorizedError:
                    QMessageBox.critical(
                        self, self.tr("Login for user {username} failed").format(username=login_dialog.ui.editUser.text()),
                        self.tr("Wrong user name or password"))
                    login_ok = False
                except (TokenRequiredError, ConnectionException) as e:
                    QMessageBox.critical(
                        self, self.tr("Login failed"),
                        self.tr("Login failed: %s") % str(e))
                    login_ok = False
        return version_ok

    def create_database(self):
        if self.numDbs < self.maxDBs:
            db = self.api.create_database()
            self.show_api_error(db)
            self.refresh_databases()
        else:
            QMessageBox.warning(None, self.tr('Warning!'),  self.tr('Number of %s permitted databases exceeded! Please upgrade your account!') % self.maxDBs)

    def delete_database(self):
        name = self.ui.tabDatabases.currentItem().text()
        
        answer = False
        
        for layer in list(self.PROJECT_INSTANCE.mapLayers().values()):            
            if QgsDataSourceUri(layer.publicSource()).database() == name:
                
                if not answer:
                    answer = QMessageBox.question(
                        self,
                        self.tr("Warning"),
                        self.tr('You have layers from database "{name}" loaded in your project! Do you want to remove them before you delete database "{name}"?').format(name=name),
                        QMessageBox.StandardButtons(
                            QMessageBox.Cancel |
                            QMessageBox.Yes))

                if answer == QMessageBox.Yes:
                     self.PROJECT_INSTANCE.removeMapLayer(layer.id())
                     
        if answer == QMessageBox.Cancel:
            QMessageBox.warning(None,  self.tr('Warning'),  self.tr('Deletion of database "{name}" interrupted!').format(name=name))
            return
            
        msgBox = QMessageBox()
        msgBox.setWindowTitle(self.tr("Delete QGIS Cloud database."))
        msgBox.setText(
            self.tr("Do you want to delete the database \"%s\"?") % name)
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        msgBox.setIcon(QMessageBox.Question)
        ret = msgBox.exec_()
        
        if ret == QMessageBox.Ok:
            self.setCursor(Qt.WaitCursor)
            result = self.api.delete_database(name)
            self.show_api_error(result)
            self.ui.btnDbDelete.setEnabled(False)
            time.sleep(2)
            self.refresh_databases()
            self.unsetCursor()

    def select_database(self):
        self.ui.btnDbDelete.setEnabled(len(self.ui.tabDatabases.selectedItems()) > 0)
            
    def select_map(self):
        self.ui.btnMapDelete.setEnabled(len(self.ui.tabMaps.selectedItems()) > 0)
        self.ui.btnMapLoad.setEnabled(len(self.ui.tabMaps.selectedItems()) > 0)
        self.update_urls(map=self.ui.tabMaps.currentItem().text())

    @pyqtSlot()
    def on_btnLogout_clicked(self):
        self.api.reset_auth()
        self.ui.btnLogout.hide()
        self.ui.lblLoginStatus.hide()
        self.ui.btnLogin.show()
        self.ui.widgetServices.hide()
        self.ui.tabDatabases.clear()
        self.ui.tabMaps.clear()
        self.ui.lblDbSize.setText("")
        self.ui.lblDbSizeUpload.setText("")
        self.ui.cbUploadDatabase.clear()
        self.ui.widgetDatabases.setEnabled(False)
        self.activate_upload_button()

    def refresh_databases(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        if self.clouddb:
            db_list = self.api.read_databases()
            if self.show_api_error(db_list):
                QApplication.restoreOverrideCursor()
                return
            self.db_connections = DbConnections()
            for db in db_list:
                self.db_connections.add_from_json(db)

            self.ui.tabDatabases.clear()
            self.ui.btnDbDelete.setEnabled(False)
            self.ui.cbUploadDatabase.clear()
            self.ui.cbUploadDatabase.setEditable(True)
            self.ui.cbUploadDatabase.lineEdit().setReadOnly(True)
            if self.db_connections.count() == 0:
                self.ui.cbUploadDatabase.setEditText(self.tr("No databases"))
            else:
                for name, db in list(self.db_connections.iteritems()):
                    it = QListWidgetItem(name)
                    it.setToolTip(db.description())
                    self.ui.tabDatabases.addItem(it)
                    self.ui.cbUploadDatabase.addItem(name)
                if self.ui.cbUploadDatabase.count() > 1:
                    # Display the "Select database" text if more than one db is available
                    self.ui.cbUploadDatabase.setCurrentIndex(-1)
                    self.ui.cbUploadDatabase.setEditText(self.tr("Select database"))
            self.db_connections.refresh(self.user)

        self.db_size(self.db_connections)
        QApplication.restoreOverrideCursor()
        
    def map_load(self,  item=None,  row=None):     
        self.ui.widgetServices.close()
        self.setCursor(Qt.WaitCursor)
        map_id = self.ui.tabMaps.currentItem().data(Qt.UserRole)
        map_name = self.ui.tabMaps.currentItem().text()
        result = self.api.load_map_project(map_name,  map_id)
        qgs_file_name = '%s/%s.qgs' % (tempfile.gettempdir(), map_name)
        qgs_file = open(qgs_file_name,  'w')
        qgs_file.write(result)
        qgs_file.close()
        project = QgsProject.instance()
        if project.isDirty():
            ok = QMessageBox.information(
                self,
                self.tr("Save Project"),
                self.tr("""Your actual project has changes. Do you want to save the project?"""),
                QMessageBox.StandardButtons(
                    QMessageBox.Abort |
                    QMessageBox.Discard |
                    QMessageBox.Save))
            if ok:
                project.write()           
                
        project.read(qgs_file_name)
        project.setDirty(False)
        self.iface.mainWindow().setWindowTitle("QGIS %s - %s" % (Qgis.QGIS_VERSION,  map_name))
        self.unsetCursor()
            
    def delete_map(self):
        name = self.ui.tabMaps.currentItem().text()
        map_id = self.ui.tabMaps.currentItem().data(Qt.UserRole)
        
        msgBox = QMessageBox()
        msgBox.setWindowTitle(self.tr("Delete QGIS Cloud map."))
        msgBox.setText(
            self.tr("Do you want to delete the map \"%s\"?") % name)
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        msgBox.setIcon(QMessageBox.Question)
        ret = msgBox.exec_()
        
        if ret == QMessageBox.Ok:
            self.ui.widgetServices.close()
            self.setCursor(Qt.WaitCursor)
            success = self.api.delete_map(map_id)
            
            if success:
                self.ui.btnMapDelete.setEnabled(False)
                self.refresh_maps()
            else:
                self.show_api_error(success)
                
            self.unsetCursor()
            self.ui.widgetServices.close()
        else:
            QMessageBox.warning(None,  self.tr('Warning'),  self.tr('Deletion of map "{name}" interrupted!').format(name=name))
            
            
    def refresh_maps(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        if self.clouddb:
            map_list = self.api.read_maps()
            if self.show_api_error(map_list):
                QApplication.restoreOverrideCursor()
                return

            self.ui.tabMaps.clear()
            self.ui.btnMapDelete.setEnabled(False)
            self.ui.btnMapLoad.setEnabled(False)
            
            for map in map_list:
                it = QListWidgetItem(map['map']['name'])
                self.ui.tabMaps.addItem(it)
                it.setData(Qt.UserRole,  map['map']['id'])

        QApplication.restoreOverrideCursor()        

    def api_url(self):
        return str(self.ui.editServer.text())
        
    def update_urls(self,  map=None):
        
        if map == None:
            map = self.map()
        
        try:
            map = map.decode('utf-8')
        except:
            pass
            
        self.update_url(self.ui.lblWebmap, self.api_url(),
                        'https://', u'{0}/{1}/'.format(self.user, map))
                        
        if self.clouddb:
            self.update_url(
                self.ui.lblWMS, self.api_url(),
                'https://wms.', u'{0}/{1}/'.format(self.user, map))
        else:
            self.update_url(self.ui.lblWMS, self.api_url(
            ), 'https://', u'{0}/{1}/wms'.format(self.user, map))
        self.update_url(self.ui.lblMaps, self.api_url(), 'https://', 'maps')
        self.ui.widgetServices.show()

    def update_url(self, label, api_url, prefix, path):
        try:
            base_url = string.replace(api_url, 'https://api.', prefix)
        except:
            base_url = api_url.replace('https://api.', prefix)
            
        url = u'{0}/{1}'.format(base_url, path)
        text = re.sub(r'http[^"]+', url, str(label.text()))
        label.setText(text)

    def read_maps(self):
        if self.check_login():
            self.api.read_maps()

    def check_project_saved(self):
        project = QgsProject.instance()
        fname = project.fileName()
        if project.isDirty() or fname == '':
            msgBox = QMessageBox()
            msgBox.setWindowTitle(self.tr("Project Modified"))
            msgBox.setText(self.tr("The project has been modified."))
            msgBox.setInformativeText(
                self.tr("The project needs to be saved before it can be published. Proceed?"))
            msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Cancel)
            msgBox.setDefaultButton(QMessageBox.Save)
            if msgBox.exec_() == QMessageBox.Save:
                self.iface.actionSaveProject().trigger()
                return not project.isDirty()
            else:
                return False
        return True

    def publish_map(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        srs=QgsMapSettings().destinationCrs()
        
        if "USER" in srs.authid():
            QMessageBox.warning(None, self.tr('Warning!'),  self.tr("The project has a user defined CRS. The use of user defined CRS is not supported. Please correct the project CRS before publishing!"))
            QApplication.restoreOverrideCursor()
            return 
            
        layer_dict = QgsProject.instance().mapLayers()
        layers = list(layer_dict.values())                    
        layerList = ''
        
        for layer in layers:
            if "USER" in layer.crs().authid():
                 layerList += "'"+layer.name()+"' "
        
        if len(layerList) > 0:
            QMessageBox.warning(None, self.tr('Warning!'),  self.tr("The layer(s) {layerlist}have user defined CRS. The use of user defined CRS is not supported. Please correct the CRS before publishing!").format(layerlist=layerList))
            QApplication.restoreOverrideCursor()
            return
                 
        saved = self.check_project_saved()
        if not saved:
            self.statusBar().showMessage(self.tr("Cancelled"))
        elif self.check_login() and self.check_layers():
            self.statusBar().showMessage(self.tr("Publishing map"))
            try:
                fullExtent = self.iface.mapCanvas().fullExtent()
                config = {
                    'fullExtent': {
                        'xmin': fullExtent.xMinimum(),
                        'ymin': fullExtent.yMinimum(),
                        'xmax': fullExtent.xMaximum(),
                        'ymax': fullExtent.yMaximum()
                        #},
                        # 'svgPaths': QgsApplication.svgPaths() #For resolving absolute symbol paths in print composer
                    }
                }
                
                fname = str(QgsProject.instance().fileName())
                map = self.api.create_map( self.map(), fname, config)['map']
                self.show_api_error(map)
                if map['config']['missingSvgSymbols']:
                    self.publish_symbols(map['config']['missingSvgSymbols'])
                self.update_urls()
                self._push_message(self.tr("QGIS Cloud"), self.tr(
                    "Map successfully published"), level=0, duration=2)
                self.statusBar().showMessage(
                    self.tr("Map successfully published"))
            except Exception as e:
                self.statusBar().showMessage("")
                ErrorReportDialog(self.tr("Error uploading project"), self.tr("An error occured."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()
        self.refresh_maps()
        QApplication.restoreOverrideCursor()

    def publish_symbols(self, missingSvgSymbols):
        self.statusBar().showMessage(self.tr("Uploading SVG symbols"))
        search_paths = QgsApplication.svgPaths()
        if hasattr(QgsProject.instance(), 'homePath'):
            search_paths += [QgsProject.instance().homePath()]
        # Search and upload symbol files
        for sym in missingSvgSymbols:
            # Absolute custom path
            if os.path.isfile(sym):
                self.api.create_graphic(sym, sym)
            else:
                for path in search_paths:
                    fullpath = os.path.join(str(path), sym)
                    if os.path.isfile(fullpath):
                        self.api.create_graphic(sym, fullpath)
        self.statusBar().showMessage("")

    def reset_load_data(self):
        self.ui.widgetServices.hide()
        self.update_local_data_sources([],  [])
        self.ui.btnUploadData.setEnabled(False)
        self.ui.tabMaps.clearSelection()

    def remove_layer(self, layer_id):
        if self.do_update_local_data_sources:
            # skip layer if layer will be removed
            self.update_local_layers(layer_id)
            self.activate_upload_button()

    def add_layer(self):
        if self.do_update_local_data_sources:
            self.update_local_layers()
            self.activate_upload_button()

    def update_local_layers(self, skip_layer_id=None):
        local_layers, unsupported_layers,  local_raster_layers = self.local_data_sources.local_layers(skip_layer_id)
        try:
            self.update_local_data_sources(local_layers,  local_raster_layers)
        except Exception as e:
            ErrorReportDialog(self.tr("Error checking local data sources"), self.tr("An error occured."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()

        return local_layers, unsupported_layers,  local_raster_layers

    def check_layers(self):
        local_layers, unsupported_layers,  local_raster_layers = self.update_local_layers()
        
        
        if ((local_layers or local_raster_layers) and self.clouddb) or unsupported_layers:
            message = ""

            if local_layers or local_raster_layers:
                title = self.tr("Local layers found")
                message += self.tr(
                    "Some layers are using local data. Please upload local layers to your cloud database in the 'Upload Data' tab before publishing.\n\n")

            if unsupported_layers:
                title = self.tr("Unsupported layers found")
                message += self.tr(
                    "Raster, plugin or geometryless layers are not supported:\n\n")
                layer_types = ["No geometry", "Raster", "Plugin"]
                for layer in sorted(unsupported_layers, key=lambda layer: layer.name()):
                    message += self.tr("  -  %s (%s)\n") % (
                        layer.name(), layer_types[layer.type()])
                message += self.tr(
                    "\nPlease remove or replace above layers before publishing your map.\n")
                message += self.tr(
                    "For raster data you can use public WMS layers or the OpenLayers Plugin.")

            QMessageBox.warning(self, title, message)

            self.refresh_databases()
            self.ui.tabWidget.setCurrentWidget(self.ui.uploadTab)
            return False

        return True

    def update_local_data_sources(self, local_layers,  local_raster_layers):
        # update table names lookup
        local_layers += local_raster_layers
        self.update_data_sources_table_names()
        
        self.local_data_sources.update_local_data_sources(local_layers)

        # update GUI
        self.ui.tblLocalLayers.setRowCount(0)
        
        schema_list = []
        if self.ui.cbUploadDatabase.count() == 1:
            schema_list = self.fetch_schemas(self.ui.cbUploadDatabase.currentText())
        elif self.ui.cbUploadDatabase.currentIndex() > 0:
            schema_list = self.fetch_schemas(self.ui.cbUploadDatabase.currentText())

        for data_source, layers in list(self.local_data_sources.iteritems()):
            layer_names = []
            for layer in layers:
                layer_names.append(str(layer.name()))
            layers_item = QTableWidgetItem(", ".join(layer_names))
            layers_item.setToolTip("\n".join(layer_names))
            data_source_item = QTableWidgetItem(data_source)
            data_source_item.setToolTip(data_source)            

            # find a better table name if there are multiple layers with same
            # data source?
            table_name = layers[0].name()
            if data_source in self.data_sources_table_names:
                # use current table name if available to keep changes by user
                table_name = self.data_sources_table_names[data_source]
            
            table_name_item = QTableWidgetItem(self.launder_pg_name(table_name))
        
            if layers[0].providerType() == 'gdal':
                geometry_type_item = QTableWidgetItem('Raster')
            else:
                wkbType = layers[0].wkbType()
                
                if wkbType not in self.GEOMETRY_TYPES:
                    QMessageBox.warning(self.iface.mainWindow(), self.tr("Unsupported geometry type"), self.tr(
                        "Unsupported geometry type '{type}' in layer '{layer}'").format(type=self.__wkbTypeString(wkbType), layer=layers[0].name()))
                    continue
                geometry_type_item = QTableWidgetItem(self.GEOMETRY_TYPES[wkbType])
                if layers[0].providerType() == "ogr":
                    geometry_type_item.setToolTip(
                        self.tr("Note: OGR features will be converted to MULTI-type"))
                        
            srid_item = QTableWidgetItem(layers[0].crs().authid())

            row = self.ui.tblLocalLayers.rowCount()
            self.ui.tblLocalLayers.insertRow(row)
            layers_item.setFlags( Qt.ItemIsSelectable |  Qt.ItemIsEnabled )
            self.ui.tblLocalLayers.setItem(
                row, self.COLUMN_LAYERS, layers_item)
            data_source_item.setFlags( Qt.ItemIsSelectable |  Qt.ItemIsEnabled )
            self.ui.tblLocalLayers.setItem(
                row, self.COLUMN_DATA_SOURCE, data_source_item)                
                
# create combo box in schema column filled with all schema names of the selected database               
            cmb_schema = QComboBox()
            cmb_schema.setEditable(True)
            cmb_schema.addItems(schema_list)
            self.ui.tblLocalLayers.setCellWidget(row, self.COLUMN_SCHEMA_NAME, cmb_schema)

            table_name_item.setFlags( Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled )
            self.ui.tblLocalLayers.setItem(
                row, self.COLUMN_TABLE_NAME, table_name_item)

            geometry_type_item.setFlags( Qt.ItemIsSelectable |  Qt.ItemIsEnabled )
            self.ui.tblLocalLayers.setItem(
                row, self.COLUMN_GEOMETRY_TYPE, geometry_type_item)
                
            srid_item.setFlags( Qt.ItemIsSelectable |  Qt.ItemIsEnabled )
            self.ui.tblLocalLayers.setItem(row, self.COLUMN_SRID, srid_item)

        if self.local_data_sources.count() > 0:
            self.ui.tblLocalLayers.resizeColumnsToContents()
            self.ui.tblLocalLayers.setColumnWidth(self.COLUMN_LAYERS, 100)
            self.ui.tblLocalLayers.setColumnWidth(self.COLUMN_DATA_SOURCE, 100)
            self.ui.tblLocalLayers.sortItems(self.COLUMN_DATA_SOURCE)
            self.ui.tblLocalLayers.setSortingEnabled(False)
        else:
            self.ui.btnUploadData.setEnabled(False)

        self.statusBar().showMessage(self.tr("Updated local data sources"))

    def __wkbTypeString(self, wkbType):
        if wkbType == QgsWkbTypes.Unknown:
            return "WkbUnknown"
        elif wkbType == QgsWkbTypes.Point:
            return "WkbPoint"
        elif wkbType == QgsWkbTypes.LineString:
            return "WkbLineString"
        elif wkbType == QgsWkbTypes.MultiLineString:
            return "WkbMultiLineString"
        elif wkbType == QgsWkbTypes.Polygon:
            return "WkbPolygon"
        elif wkbType == QgsWkbTypes.MultiPoint:
            return "WkbMultiPoint"
        elif wkbType == QgsWkbTypes.MultiPolygon:
            return "WkbMultiPolygon"
        elif wkbType == QgsWkbTypes.NoGeometry:
            return "WkbNoGeometry"
        elif wkbType == QgsWkbTypes.Point25D:
            return "WkbPoint25D"
        elif wkbType == QgsWkbTypes.LineString25D:
            return "WkbLineString25D"
        elif wkbType == QgsWkbTypes.Polygon25D:
            return "WkbPolygon25D"
        elif wkbType == QgsWkbTypes.MultiPoint25D:
            return "WkbMultiPoint25D"
        elif wkbType == QgsWkbTypes.MultiLineString25D:
            return "WkbMultiLineString25D"
        elif wkbType == QgsWkbTypes.MultiPolygon25D:
            return "WkbMultiPolygon25D"
        elif wkbType == QgsWkbTypes.LineStringZM:
            return "WkbLineStringZM"
        elif wkbType == QgsWkbTypes.MultiLineStringZM:
            return "WkbMultiLineStringZM"
        
        return self.tr("Unknown type")

#    @staticmethod
    def launder_pg_name(self,  name):
        # OGRPGDataSource::LaunderName
        # return re.sub(r"[#'-]", '_', unicode(name).lower())
        input_string = str(name).lower().encode('ascii', 'replace')
        input_string = input_string.replace(b" ",b"_")    
        input_string = input_string.replace(b".",b"_")    

        # check if table_name starts with number
        
        if re.search("^\d", input_string.decode('utf-8')):
           input_string = '_'+input_string.decode('utf-8') 
        
        try:
            return input_string.decode('utf-8')
        except:
            return input_string

    def refresh_local_data_sources(self):
        self.do_update_local_data_sources = True
        self.update_local_layers()
        self.activate_upload_button()
        
#
    def update_data_sources_table_names(self):
        
        schema_list = []
        schema_list = self.fetch_schemas(self.ui.cbUploadDatabase.currentText())
            
        if self.local_data_sources.count() == 0:
            self.data_sources_table_names.clear()
        else:
            # remove table names without data sources
            keys_to_remove = []
            for key in list(self.data_sources_table_names.keys()):
                if self.local_data_sources.layers(key) is None:
                    keys_to_remove.append(key)

            for key in keys_to_remove:
                del self.data_sources_table_names[key]

            # update table names
            if schema_list != None:
                for row in range(0, self.ui.tblLocalLayers.rowCount()):
                    data_source = self.ui.tblLocalLayers.item(row, self.COLUMN_DATA_SOURCE).text()
                    cmb_schema = QComboBox()
                    cmb_schema.setEditable(True)
                    cmb_schema.addItems(schema_list)
                    self.ui.tblLocalLayers.setCellWidget(row, self.COLUMN_SCHEMA_NAME, cmb_schema)                
                    table_name = self.ui.tblLocalLayers.item(row, self.COLUMN_TABLE_NAME).text()
                    self.data_sources_table_names[data_source] = table_name

    def activate_upload_button(self):
        if not self.storage_exceeded:
            self.ui.btnUploadData.setEnabled(self.local_data_sources.count() > 0)
            self.ui.btnPublishMap.setDisabled(self.storage_exceeded)
        else:
            self.ui.btnUploadData.setDisabled(self.storage_exceeded)
            self.ui.btnPublishMap.setDisabled(self.storage_exceeded)

    def upload_data(self):
        if self.check_login():
            if self.local_data_sources.count() == 0:
                return

            if self.db_connections.count() == 0:
                QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab."))
                return

            if not self.ui.cbUploadDatabase.currentIndex() >= 0:
                QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data."))
                return

            db_name = self.ui.cbUploadDatabase.currentText()

            if not self.db_connections.isPortOpen(db_name):
                uri = self.db_connections.cloud_layer_uri(db_name, "", "")
                host = str(uri.host())
                port = uri.port()
                QMessageBox.critical(self, self.tr("Network Error"),
                                     self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port)))
                return

            # disable update of local data sources during upload, as there are
            # temporary layers added and removed
            self.do_update_local_data_sources = False
            self.statusBar().showMessage(self.tr("Uploading data..."))
            self.setCursor(Qt.WaitCursor)
            self.ui.btnUploadData.hide()
            self.ui.spinner.start()
            self.ui.progressWidget.show()

            # Map<data_source, {schema: schema, table: table, layers: layers}>
            data_sources_items = {}
            for row in range(0, self.ui.tblLocalLayers.rowCount()):
                data_source = unicode(
                    self.ui.tblLocalLayers.item(
                        row, self.COLUMN_DATA_SOURCE).text())
                layers = self.local_data_sources.layers(data_source)
                if layers is not None:
                    schema_name = unicode(
                        self.ui.tblLocalLayers.cellWidget(
                            row, self.COLUMN_SCHEMA_NAME).currentText())                    
                    table_name = unicode(
                        self.ui.tblLocalLayers.item(
                            row, self.COLUMN_TABLE_NAME).text())
                    data_sources_items[data_source] = {
                        u'schema': unicode(schema_name), u'table': unicode(table_name), u'layers': layers}

            login_info = self.api.check_login(version_info=self._version_info())
            try:            
                self.maxSize = login_info['max_storage']
                self.maxDBs = login_info['max_dbs']
            except:
                self.maxSize = 50
                self.maxDBs = 5

            try:
                self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize))
                upload_ok = True
            except Exception as e:
                ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()
                upload_ok = False

            self.ui.spinner.stop()
            self.ui.progressWidget.hide()
            self.ui.btnUploadData.show()
            self.unsetCursor()
            self.statusBar().showMessage("")
            # Refresh local layers
            self.do_update_local_data_sources = True
            self.update_local_layers()
            # Refresh used space after upload
            self.db_size(self.db_connections)

            if upload_ok:
                # Show save project dialog
                save_dialog = QDialog(self)
                save_dialog.setWindowTitle(self.tr("Save Project"))
                save_dialog.setLayout(QVBoxLayout())
                header = QWidget()
                header.setLayout(QVBoxLayout())
                label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database."))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                label = QLabel(self.tr("Choose were to save the modified project:"))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                save_dialog.layout().setContentsMargins(0, 0, 0, 0)
                save_dialog.layout().addWidget(header)
                initialPath = QgsProject.instance().fileName()
                if not initialPath:
                    initialPath = QSettings().value("/UI/lastProjectDir", ".")
                fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files"))
                fd.setParent(save_dialog, Qt.Widget)
                fd.setOption(QFileDialog.DontUseNativeDialog)
                fd.setAcceptMode(QFileDialog.AcceptSave)
                save_dialog.layout().addWidget(fd)
                header.layout().setContentsMargins(fd.layout().contentsMargins())
                fd.accepted.connect(save_dialog.accept)
                fd.rejected.connect(save_dialog.reject)
                if save_dialog.exec_() == QDialog.Accepted:
                    files = list(fd.selectedFiles())
                    if files:
                        QgsProject.instance().setFileName(files[0])
                        self.iface.actionSaveProject().trigger()

                # Switch to map tab
                self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)

    def _push_message(self, title, text, level=0, duration=0):
        # QGIS >= 2.0
        if hasattr(self.iface, 'messageBar') and hasattr(self.iface.messageBar(), 'pushMessage'):
            self.iface.messageBar().pushMessage(title, text, level, duration)
        else:
            QMessageBox.information(self, title, text)

    def show_api_error(self, result):
        if 'error' in result:
            QMessageBox.critical(
                self, self.tr("QGIS Cloud Error"), "%s" % result['error'])
            self.statusBar().showMessage(self.tr("Error"))
            return True
        else:
            return False


    @pyqtSlot(str)
    def on_cmb_schema_currentIndexChanged(self, p0):
        """
        Slot documentation goes here.
        
        @param p0 DESCRIPTION
        @type str
        """
        # TODO: not implemented yet
        self.fetch_schemas(p0)
        
        
    def fetch_schemas(self,  db):
        if db != '' and self.ui.cbUploadDatabase.currentIndex() >= 0:
            conn = self.db_connections.db(db).psycopg_connection()
            cursor = conn.cursor()
            sql = """
                    select *
                    from pg_catalog.pg_namespace
                    where nspowner <> 10
                      and nspname <> 'topology'
            """
            schema_list = []
            schema_list.append('public')
            cursor.execute(sql)
            for record in cursor:
                schema_list.append(list(record)[0])
            cursor.close()
            conn.close
            return schema_list
        else:
            return None

    def db_size(self,  db_connections):
        usedSpace = 0
        self.numDbs = len(list(db_connections._dbs.keys()))
        for db in list(db_connections._dbs.keys()):
            try:
                conn = db_connections.db(db).psycopg_connection()
            except:
                continue
            cursor = conn.cursor()
            sql = "SELECT pg_database_size('" + str(db) + "')"
            cursor.execute(sql)
            usedSpace += int(cursor.fetchone()[0])-(11*1024*1024)
            cursor.close()
            conn.close

        # Used space in MB
        usedSpace /= 1024 * 1024

        login_info = self.api.check_login(version_info=self._version_info())
        
        try:            
            self.maxSize = login_info['max_storage']
            self.maxDBs = login_info['max_dbs']
        except:
            self.maxSize = 50
            self.maxDBs = 5

        lblPalette = QPalette(self.ui.lblDbSize.palette())
        usage = usedSpace / float(self.maxSize)
        self.storage_exceeded = False
    
        if usage < 0.8:
            bg_color = QColor(255, 0, 0, 0)
            text_color = QColor(Qt.black)
        elif usage >= 0.8 and usage < 1:
            bg_color = QColor(255, 0, 0, 100)
            text_color = QColor(Qt.white)
        elif usage >= 1:
            bg_color = QColor(255, 0, 0, 255)
            text_color = QColor(Qt.white)
            self.storage_exceeded = True

        lblPalette.setColor(QPalette.Window, QColor(bg_color))
        lblPalette.setColor(QPalette.Foreground,QColor(text_color))
        
        self.ui.lblDbSize.setAutoFillBackground(True)
        self.ui.lblDbSize.setPalette(lblPalette)
        self.ui.lblDbSize.setText(
            self.tr("Used DB Storage: ") + "%d / %d MB" % (usedSpace, self.maxSize))

        self.ui.lblDbSizeUpload.setAutoFillBackground(True)
        self.ui.lblDbSizeUpload.setPalette(lblPalette)
        self.ui.lblDbSizeUpload.setText(
            self.tr("Used DB Storage: ") + "%d / %d MB" % (usedSpace, self.maxSize))
        self.ui.btnUploadData.setDisabled(self.storage_exceeded)
        self.ui.btnPublishMap.setDisabled(self.storage_exceeded)
    def __init__(self, iface, version):
        QDockWidget.__init__(self, None)
        self.iface = iface
        self.clouddb = True
        self.version = version
        # Set up the user interface from Designer.
        self.ui = Ui_QgisCloudPlugin()
        self.ui.setupUi(self)
        self.storage_exceeded = True
        
        myAbout = DlgAbout()
        self.ui.aboutText.setText(
            myAbout.aboutString() +
            myAbout.contribString() +
            myAbout.licenseString() +
            "<p>Versions:<ul>" +
            "<li>QGIS: %s</li>" % str(Qgis.QGIS_VERSION).encode("utf-8") +
            "<li>Python: %s</li>" % sys.version.replace("\n", " ") +
            "<li>OS: %s</li>" % platform.platform() +
            "</ul></p>")
            
        data_protection_link = """<a href="http://qgiscloud.com/pages/privacy">%s</a>""" % (self.tr("Privacy Policy"))
            
        self.ui.lblVersionPlugin.setText("%s &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%s" % (self.version,  data_protection_link))
        self.ui.lblVersionPlugin.setOpenExternalLinks(True)            

        self.ui.tblLocalLayers.setColumnCount(6)
        header = ["Layers","Table Schema","Table name", "Geometry type", "SRID","Data Source"]
        self.ui.tblLocalLayers.setHorizontalHeaderLabels(header)
        self.ui.tblLocalLayers.resizeColumnsToContents()
#        self.ui.tblLocalLayers.setEditTriggers(QAbstractItemView.NoEditTriggers)
        
        self.ui.btnUploadData.setEnabled(False)
        self.ui.btnPublishMap.setEnabled(False)
        self.ui.btnMapDelete.setEnabled(False)
        self.ui.progressWidget.hide()
        self.ui.btnLogout.hide()
        self.ui.lblLoginStatus.hide()
        self.ui.widgetServices.hide()
        self.ui.widgetDatabases.setEnabled(False)
        self.ui.widgetMaps.setEnabled(False)
        self.ui.labelOpenLayersPlugin.hide()

        try:
            from .openlayers_menu import OpenlayersMenu
            self.ui.btnBackgroundLayer.setMenu(OpenlayersMenu(self.iface))
        except:
                self.ui.btnBackgroundLayer.hide()
                self.ui.labelOpenLayersPlugin.show()

        # map<data source, table name>
        self.data_sources_table_names = {}
        # flag to disable update of local data sources during upload
        self.do_update_local_data_sources = True

        self.ui.btnLogin.clicked.connect(self.check_login)
        self.ui.btnDbCreate.clicked.connect(self.create_database)
        self.ui.btnDbDelete.clicked.connect(self.delete_database)
        self.ui.btnDbRefresh.clicked.connect(self.refresh_databases)
        self.ui.btnMapDelete.clicked.connect(self.delete_map)
        self.ui.btnMapLoad.clicked.connect(self.map_load)
        self.ui.tabMaps.itemDoubleClicked.connect(self.map_load)
        self.ui.tabDatabases.itemSelectionChanged.connect(self.select_database)
        self.ui.tabMaps.itemSelectionChanged.connect(self.select_map)
        self.ui.btnPublishMap.clicked.connect(self.publish_map)
        self.ui.btnRefreshLocalLayers.clicked.connect(self.refresh_local_data_sources)
        self.ui.cbUploadDatabase.currentTextChanged.connect(self.update_data_sources_table_names)
        self.iface.newProjectCreated.connect(self.reset_load_data)
        self.iface.projectRead.connect(self.reset_load_data)

        self.PROJECT_INSTANCE.layerWillBeRemoved.connect(self.remove_layer)
        self.PROJECT_INSTANCE.layerWasAdded.connect(self.add_layer)
        
        self.ui.cbUploadDatabase.currentIndexChanged.connect(lambda idx: self.activate_upload_button())
        self.ui.btnUploadData.clicked.connect(self.upload_data)

        self.ui.editServer.textChanged.connect(self.serverURL)
        self.ui.resetUrlBtn.clicked.connect(self.resetApiUrl)

        self.read_settings()
        self.api = API()
        self.db_connections = DbConnections()
        self.local_data_sources = LocalDataSources()
        self.data_upload = DataUpload(
            self.iface, self.statusBar(), self.ui.lblProgress, self.api,
            self.db_connections)

        if self.URL == "":
            self.ui.editServer.setText(self.api.api_url())
        else:
            self.ui.editServer.setText(self.URL)

        self.palette_red = QPalette(self.ui.lblVersionPlugin.palette())
        self.palette_red.setColor(QPalette.WindowText, Qt.red)
Esempio n. 15
0
    def __init__(self, parent=None):

        QWidget.__init__(self, parent)
        palette = QPalette(self.palette())
        palette.setColor(palette.Background, Qt.transparent)
        self.setPalette(palette)
Esempio n. 16
0
    def accept(self):
        self.settings.setValue("/Processing/dialogBase", self.saveGeometry())

        checkCRS = ProcessingConfig.getSetting(
            ProcessingConfig.WARN_UNMATCHING_CRS)
        try:
            self.setParamValues()
            if checkCRS and not self.alg.checkInputCRS():
                reply = QMessageBox.question(
                    self, self.tr("Unmatching CRS's"),
                    self.tr('Layers do not all use the same CRS. This can '
                            'cause unexpected results.\nDo you want to '
                            'continue?'), QMessageBox.Yes | QMessageBox.No,
                    QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            checkExtentCRS = ProcessingConfig.getSetting(
                ProcessingConfig.WARN_UNMATCHING_EXTENT_CRS)
            if checkExtentCRS and self.checkExtentCRS():
                reply = QMessageBox.question(
                    self, self.tr("Extent CRS"),
                    self.
                    tr('Extent parameters must use the same CRS as the input layers.\n'
                       'Your input layers do not have the same extent as the project, '
                       'so the extent might be in a wrong CRS if you have selected it from the canvas.\n'
                       'Do you want to continue?'),
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            msg = self.alg._checkParameterValuesBeforeExecuting()
            if msg:
                QMessageBox.warning(self,
                                    self.tr('Unable to execute algorithm'),
                                    msg)
                return
            self.btnRun.setEnabled(False)
            self.btnClose.setEnabled(False)
            buttons = self.mainWidget.iterateButtons
            self.iterateParam = None

            for i in range(len(list(buttons.values()))):
                button = list(buttons.values())[i]
                if button.isChecked():
                    self.iterateParam = list(buttons.keys())[i]
                    break

            self.progressBar.setMaximum(0)
            self.lblProgress.setText(self.tr('Processing algorithm...'))
            # Make sure the Log tab is visible before executing the algorithm
            try:
                self.tabWidget.setCurrentIndex(1)
                self.repaint()
            except:
                pass

            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

            self.setInfo(
                self.tr('<b>Algorithm %s starting...</b>') % self.alg.name)

            if self.iterateParam:
                if runalgIterating(self.alg, self.iterateParam, self.feedback):
                    self.finish()
                else:
                    QApplication.restoreOverrideCursor()
                    self.resetGUI()
            else:
                command = self.alg.getAsCommand()
                if command:
                    ProcessingLog.addToLog(ProcessingLog.LOG_ALGORITHM,
                                           command)
                if runalg(self.alg, self.feedback):
                    self.finish()
                else:
                    QApplication.restoreOverrideCursor()
                    self.resetGUI()
        except AlgorithmDialogBase.InvalidParameterValue as e:
            try:
                self.buttonBox.accepted.connect(
                    lambda e=e: e.widget.setPalette(QPalette()))
                palette = e.widget.palette()
                palette.setColor(QPalette.Base, QColor(255, 255, 0))
                e.widget.setPalette(palette)
            except:
                pass
            self.bar.clearWidgets()
            self.bar.pushMessage("",
                                 "Wrong or missing parameter value: %s" %
                                 e.parameter.description,
                                 level=QgsMessageBar.WARNING,
                                 duration=5)
Esempio n. 17
0
    def runAlgorithm(self):
        self.feedback = self.createFeedback()
        self.context = dataobjects.createContext(self.feedback)

        checkCRS = ProcessingConfig.getSetting(
            ProcessingConfig.WARN_UNMATCHING_CRS)
        try:
            parameters = self.getParameterValues()

            if checkCRS and not self.algorithm().validateInputCrs(
                    parameters, self.context):
                reply = QMessageBox.question(
                    self, self.tr("Unmatching CRS's"),
                    self.tr('Parameters do not all use the same CRS. This can '
                            'cause unexpected results.\nDo you want to '
                            'continue?'), QMessageBox.Yes | QMessageBox.No,
                    QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            ok, msg = self.algorithm().checkParameterValues(
                parameters, self.context)
            if not ok:
                QMessageBox.warning(self,
                                    self.tr('Unable to execute algorithm'),
                                    msg)
                return
            self.runButton().setEnabled(False)
            self.cancelButton().setEnabled(False)
            buttons = self.mainWidget().iterateButtons
            self.iterateParam = None

            for i in range(len(list(buttons.values()))):
                button = list(buttons.values())[i]
                if button.isChecked():
                    self.iterateParam = list(buttons.keys())[i]
                    break

            self.clearProgress()
            self.setProgressText(
                QCoreApplication.translate('AlgorithmDialog',
                                           'Processing algorithm…'))

            self.setInfo(QCoreApplication.translate(
                'AlgorithmDialog',
                '<b>Algorithm \'{0}\' starting&hellip;</b>').format(
                    self.algorithm().displayName()),
                         escapeHtml=False)

            self.feedback.pushInfo(self.tr('Input parameters:'))
            display_params = []
            for k, v in parameters.items():
                display_params.append("'" + k + "' : " + self.algorithm(
                ).parameterDefinition(k).valueAsPythonString(v, self.context))
            self.feedback.pushCommandInfo('{ ' + ', '.join(display_params) +
                                          ' }')
            self.feedback.pushInfo('')
            start_time = time.time()

            if self.iterateParam:
                # Make sure the Log tab is visible before executing the algorithm
                try:
                    self.showLog()
                    self.repaint()
                except:
                    pass

                self.cancelButton().setEnabled(
                    self.algorithm().flags()
                    & QgsProcessingAlgorithm.FlagCanCancel)
                if executeIterating(self.algorithm(), parameters,
                                    self.iterateParam, self.context,
                                    self.feedback):
                    self.feedback.pushInfo(
                        self.tr('Execution completed in {0:0.2f} seconds').
                        format(time.time() - start_time))
                    self.cancelButton().setEnabled(False)
                    self.finish(True, parameters, self.context, self.feedback)
                else:
                    self.cancelButton().setEnabled(False)
                    self.resetGui()
            else:
                command = self.algorithm().asPythonCommand(
                    parameters, self.context)
                if command:
                    ProcessingLog.addToLog(command)
                QgsGui.instance().processingRecentAlgorithmLog().push(
                    self.algorithm().id())
                self.cancelButton().setEnabled(
                    self.algorithm().flags()
                    & QgsProcessingAlgorithm.FlagCanCancel)

                def on_complete(ok, results):
                    if ok:
                        self.feedback.pushInfo(
                            self.tr('Execution completed in {0:0.2f} seconds').
                            format(time.time() - start_time))
                        self.feedback.pushInfo(self.tr('Results:'))
                        self.feedback.pushCommandInfo(pformat(results))
                    else:
                        self.feedback.reportError(
                            self.tr('Execution failed after {0:0.2f} seconds').
                            format(time.time() - start_time))
                    self.feedback.pushInfo('')

                    if self.feedback_dialog is not None:
                        self.feedback_dialog.close()
                        self.feedback_dialog.deleteLater()
                        self.feedback_dialog = None

                    self.cancelButton().setEnabled(False)

                    if not self.in_place:
                        self.finish(ok, results, self.context, self.feedback)
                    elif ok:
                        self.close()

                    self.feedback = None
                    self.context = None

                if not self.in_place and not (
                        self.algorithm().flags()
                        & QgsProcessingAlgorithm.FlagNoThreading):
                    # Make sure the Log tab is visible before executing the algorithm
                    self.showLog()

                    task = QgsProcessingAlgRunnerTask(self.algorithm(),
                                                      parameters, self.context,
                                                      self.feedback)
                    if task.isCanceled():
                        on_complete(False, {})
                    else:
                        task.executed.connect(on_complete)
                        self.setCurrentTask(task)
                else:
                    self.proxy_progress = QgsProxyProgressTask(
                        QCoreApplication.translate(
                            "AlgorithmDialog", "Executing “{}”").format(
                                self.algorithm().displayName()))
                    QgsApplication.taskManager().addTask(self.proxy_progress)
                    self.feedback.progressChanged.connect(
                        self.proxy_progress.setProxyProgress)
                    self.feedback_dialog = self.createProgressDialog()
                    self.feedback_dialog.show()
                    if self.in_place:
                        ok, results = execute_in_place(self.algorithm(),
                                                       parameters,
                                                       self.context,
                                                       self.feedback)
                    else:
                        ok, results = execute(self.algorithm(), parameters,
                                              self.context, self.feedback)
                    self.feedback.progressChanged.disconnect()
                    self.proxy_progress.finalize(ok)
                    on_complete(ok, results)

        except AlgorithmDialogBase.InvalidParameterValue as e:
            try:
                self.buttonBox().accepted.connect(
                    lambda e=e: e.widget.setPalette(QPalette()))
                palette = e.widget.palette()
                palette.setColor(QPalette.Base, QColor(255, 255, 0))
                e.widget.setPalette(palette)
            except:
                pass
            self.messageBar().clearWidgets()
            self.messageBar().pushMessage(
                "",
                self.tr("Wrong or missing parameter value: {0}").format(
                    e.parameter.description()),
                level=Qgis.Warning,
                duration=5)
        except AlgorithmDialogBase.InvalidOutputExtension as e:
            try:
                self.buttonBox().accepted.connect(
                    lambda e=e: e.widget.setPalette(QPalette()))
                palette = e.widget.palette()
                palette.setColor(QPalette.Base, QColor(255, 255, 0))
                e.widget.setPalette(palette)
            except:
                pass
            self.messageBar().clearWidgets()
            self.messageBar().pushMessage("",
                                          e.message,
                                          level=Qgis.Warning,
                                          duration=5)
Esempio n. 18
0
    def runAlgorithm(self):
        self.feedback = self.createFeedback()
        self.context = dataobjects.createContext(self.feedback)
        self.context.setLogLevel(self.logLevel())

        checkCRS = ProcessingConfig.getSetting(
            ProcessingConfig.WARN_UNMATCHING_CRS)
        try:
            parameters = self.createProcessingParameters()

            if checkCRS and not self.algorithm().validateInputCrs(
                    parameters, self.context):
                reply = QMessageBox.question(
                    self, self.tr("Unmatching CRS's"),
                    self.tr('Parameters do not all use the same CRS. This can '
                            'cause unexpected results.\nDo you want to '
                            'continue?'), QMessageBox.Yes | QMessageBox.No,
                    QMessageBox.No)
                if reply == QMessageBox.No:
                    return
            ok, msg = self.algorithm().checkParameterValues(
                parameters, self.context)
            if not ok:
                QMessageBox.warning(self,
                                    self.tr('Unable to execute algorithm'),
                                    msg)
                return

            self.blockControlsWhileRunning()
            self.setExecutedAnyResult(True)
            self.cancelButton().setEnabled(False)

            self.iterateParam = None

            for param in self.algorithm().parameterDefinitions():
                if isinstance(
                        parameters.get(param.name(), None),
                        QgsProcessingFeatureSourceDefinition
                ) and parameters[param.name(
                )].flags & QgsProcessingFeatureSourceDefinition.FlagCreateIndividualOutputPerInputFeature:
                    self.iterateParam = param.name()
                    break

            self.clearProgress()
            self.feedback.pushVersionInfo(self.algorithm().provider())
            if self.algorithm().provider().warningMessage():
                self.feedback.reportError(
                    self.algorithm().provider().warningMessage())

            self.setProgressText(
                QCoreApplication.translate('AlgorithmDialog',
                                           'Processing algorithm…'))

            self.setInfo(QCoreApplication.translate(
                'AlgorithmDialog',
                '<b>Algorithm \'{0}\' starting&hellip;</b>').format(
                    self.algorithm().displayName()),
                         escapeHtml=False)

            self.feedback.pushInfo(self.tr('Input parameters:'))
            display_params = []
            for k, v in parameters.items():
                display_params.append("'" + k + "' : " + self.algorithm(
                ).parameterDefinition(k).valueAsPythonString(v, self.context))
            self.feedback.pushCommandInfo('{ ' + ', '.join(display_params) +
                                          ' }')
            self.feedback.pushInfo('')
            start_time = time.time()

            def elapsed_time(start_time, result):
                delta_t = time.time() - start_time
                hours = int(delta_t / 3600)
                minutes = int((delta_t % 3600) / 60)
                seconds = delta_t - hours * 3600 - minutes * 60

                str_hours = [self.tr("hour"), self.tr("hours")][hours > 1]
                str_minutes = [self.tr("minute"),
                               self.tr("minutes")][minutes > 1]
                str_seconds = [self.tr("second"),
                               self.tr("seconds")][seconds != 1]

                if hours > 0:
                    elapsed = '{0} {1:0.2f} {2} ({3} {4} {5} {6} {7:0.0f} {2})'.format(
                        result, delta_t, str_seconds, hours, str_hours,
                        minutes, str_minutes, seconds)
                elif minutes > 0:
                    elapsed = '{0} {1:0.2f} {2} ({3} {4} {5:0.0f} {2})'.format(
                        result, delta_t, str_seconds, minutes, str_minutes,
                        seconds)
                else:
                    elapsed = '{0} {1:0.2f} {2}'.format(
                        result, delta_t, str_seconds)

                return (elapsed)

            if self.iterateParam:
                # Make sure the Log tab is visible before executing the algorithm
                try:
                    self.showLog()
                    self.repaint()
                except:
                    pass

                self.cancelButton().setEnabled(
                    self.algorithm().flags()
                    & QgsProcessingAlgorithm.FlagCanCancel)
                if executeIterating(self.algorithm(), parameters,
                                    self.iterateParam, self.context,
                                    self.feedback):
                    self.feedback.pushInfo(
                        self.tr(
                            elapsed_time(start_time,
                                         'Execution completed in')))
                    self.cancelButton().setEnabled(False)
                    self.finish(True, parameters, self.context, self.feedback)
                else:
                    self.cancelButton().setEnabled(False)
                    self.resetGui()
            else:
                command = self.algorithm().asPythonCommand(
                    parameters, self.context)
                if command:
                    ProcessingLog.addToLog(command)
                QgsGui.instance().processingRecentAlgorithmLog().push(
                    self.algorithm().id())
                self.cancelButton().setEnabled(
                    self.algorithm().flags()
                    & QgsProcessingAlgorithm.FlagCanCancel)

                def on_complete(ok, results):
                    if ok:
                        self.feedback.pushInfo(
                            self.tr(
                                elapsed_time(start_time,
                                             'Execution completed in')))
                        self.feedback.pushInfo(self.tr('Results:'))
                        r = {
                            k: v
                            for k, v in results.items()
                            if k not in ('CHILD_RESULTS', 'CHILD_INPUTS')
                        }
                        self.feedback.pushCommandInfo(pformat(r))
                    else:
                        self.feedback.reportError(
                            self.tr(
                                elapsed_time(start_time,
                                             'Execution failed after')))
                    self.feedback.pushInfo('')

                    if self.feedback_dialog is not None:
                        self.feedback_dialog.close()
                        self.feedback_dialog.deleteLater()
                        self.feedback_dialog = None

                    self.cancelButton().setEnabled(False)

                    self.finish(ok,
                                results,
                                self.context,
                                self.feedback,
                                in_place=self.in_place)

                    self.feedback = None
                    self.context = None

                if not self.in_place and not (
                        self.algorithm().flags()
                        & QgsProcessingAlgorithm.FlagNoThreading):
                    # Make sure the Log tab is visible before executing the algorithm
                    self.showLog()

                    task = QgsProcessingAlgRunnerTask(self.algorithm(),
                                                      parameters, self.context,
                                                      self.feedback)
                    if task.isCanceled():
                        on_complete(False, {})
                    else:
                        task.executed.connect(on_complete)
                        self.setCurrentTask(task)
                else:
                    self.proxy_progress = QgsProxyProgressTask(
                        QCoreApplication.translate(
                            "AlgorithmDialog", "Executing “{}”").format(
                                self.algorithm().displayName()))
                    QgsApplication.taskManager().addTask(self.proxy_progress)
                    self.feedback.progressChanged.connect(
                        self.proxy_progress.setProxyProgress)
                    self.feedback_dialog = self.createProgressDialog()
                    self.feedback_dialog.show()
                    if self.in_place:
                        ok, results = execute_in_place(self.algorithm(),
                                                       parameters,
                                                       self.context,
                                                       self.feedback)
                    else:
                        ok, results = execute(self.algorithm(), parameters,
                                              self.context, self.feedback)
                    self.feedback.progressChanged.disconnect()
                    self.proxy_progress.finalize(ok)
                    on_complete(ok, results)

        except AlgorithmDialogBase.InvalidParameterValue as e:
            try:
                self.buttonBox().accepted.connect(
                    lambda e=e: e.widget.setPalette(QPalette()))
                palette = e.widget.palette()
                palette.setColor(QPalette.Base, QColor(255, 255, 0))
                e.widget.setPalette(palette)
            except:
                pass
            self.messageBar().clearWidgets()
            self.messageBar().pushMessage(
                "",
                self.tr("Wrong or missing parameter value: {0}").format(
                    e.parameter.description()),
                level=Qgis.Warning,
                duration=5)
        except AlgorithmDialogBase.InvalidOutputExtension as e:
            try:
                self.buttonBox().accepted.connect(
                    lambda e=e: e.widget.setPalette(QPalette()))
                palette = e.widget.palette()
                palette.setColor(QPalette.Base, QColor(255, 255, 0))
                e.widget.setPalette(palette)
            except:
                pass
            self.messageBar().clearWidgets()
            self.messageBar().pushMessage("",
                                          e.message,
                                          level=Qgis.Warning,
                                          duration=5)