Пример #1
0
class HistoryDialog(QDialog, Ui_HistoryDialogPythonConsole):
    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.parent = parent
        self.setWindowTitle(
            QCoreApplication.translate("PythonConsole",
                                       "Python Console - Command History"))
        self.listView.setToolTip(
            QCoreApplication.translate("PythonConsole",
                                       "Double-click on item to execute"))
        self.model = QStandardItemModel(self.listView)

        self._reloadHistory()

        self.deleteScut = QShortcut(QKeySequence(Qt.Key_Delete), self)
        self.deleteScut.activated.connect(self._deleteItem)
        self.listView.doubleClicked.connect(self._runHistory)
        self.reloadHistory.clicked.connect(self._reloadHistory)
        self.saveHistory.clicked.connect(self._saveHistory)

    def _runHistory(self, item):
        cmd = item.data(Qt.DisplayRole)
        self.parent.runCommand(cmd)

    def _saveHistory(self):
        self.parent.writeHistoryFile(True)

    def _reloadHistory(self):
        self.model.clear()
        for i in self.parent.history:
            item = QStandardItem(i)
            if sys.platform.startswith('win'):
                item.setSizeHint(QSize(18, 18))
            self.model.appendRow(item)

        self.listView.setModel(self.model)
        self.listView.scrollToBottom()

    def _deleteItem(self):
        itemsSelected = self.listView.selectionModel().selectedIndexes()
        if itemsSelected:
            item = itemsSelected[0].row()
            # Remove item from the command history (just for the current session)
            self.parent.history.pop(item)
            self.parent.softHistory.pop(item)
            if item < self.parent.softHistoryIndex:
                self.parent.softHistoryIndex -= 1
            self.parent.setText(
                self.parent.softHistory[self.parent.softHistoryIndex])
            self.parent.move_cursor_to_end()
            # Remove row from the command history dialog
            self.model.removeRow(item)
Пример #2
0
class HistoryDialog(QDialog, Ui_HistoryDialogPythonConsole):

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.parent = parent
        self.setWindowTitle(QCoreApplication.translate("PythonConsole",
                                                       "Python Console - Command History"))
        self.listView.setToolTip(QCoreApplication.translate("PythonConsole",
                                                            "Double click on item to execute"))
        self.model = QStandardItemModel(self.listView)

        self._reloadHistory()

        self.deleteScut = QShortcut(QKeySequence(Qt.Key_Delete), self)
        self.deleteScut.activated.connect(self._deleteItem)
        self.listView.doubleClicked.connect(self._runHistory)
        self.reloadHistory.clicked.connect(self._reloadHistory)
        self.saveHistory.clicked.connect(self._saveHistory)

    def _runHistory(self, item):
        cmd = item.data(Qt.DisplayRole)
        self.parent.runCommand(cmd)

    def _saveHistory(self):
        self.parent.writeHistoryFile(True)

    def _reloadHistory(self):
        self.model.clear()
        for i in self.parent.history:
            item = QStandardItem(i)
            if sys.platform.startswith('win'):
                item.setSizeHint(QSize(18, 18))
            self.model.appendRow(item)

        self.listView.setModel(self.model)
        self.listView.scrollToBottom()

    def _deleteItem(self):
        itemsSelected = self.listView.selectionModel().selectedIndexes()
        if itemsSelected:
            item = itemsSelected[0].row()
            ## Remove item from the command history (just for the current session)
            self.parent.history.pop(item)
            self.parent.historyIndex -= 1
            ## Remove row from the command history dialog
            self.model.removeRow(item)
class ThinGreyscaleDialog(QDialog, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """Constructor."""
        self.iface = iface
        self.plugin_dir = dirname(__file__)
        self.THINGREYSCALE = self.tr('ThinGreyscale')
        self.BROWSE = self.tr('Browse')
        self.CANCEL = self.tr('Cancel')
        self.CLOSE = self.tr('Close')
        self.HELP = self.tr('Help')
        self.OK = self.tr('OK')
        self.DEFAULTPROVIDER = 'GTiff'
        self.DEFAULTEXTENSION = '.tif'
        self.EXTRAEXTENSION = ' *.tiff'
        super(ThinGreyscaleDialog, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)

        self.showInfo("Connecting UI components")
        okButton = self.button_box.button(QDialogButtonBox.Ok)
        okButton.setText(self.OK)
        cancelButton = self.button_box.button(QDialogButtonBox.Cancel)
        cancelButton.setText(self.CANCEL)
        cancelButton.setEnabled(False)
        closeButton = self.button_box.button(QDialogButtonBox.Close)
        closeButton.setText(self.CLOSE)
        browseButton = self.browseButton
        browseButton.setText(self.BROWSE)
        self.calcHistPushButton.setEnabled(False)
        self.listModel = QStandardItemModel(self.levelsListView)
        self.levelsListView.setModel(self.listModel)
        self.levelsListView.sizeHintForColumn(20)
        #self.levelValuesCheckBox.setEnabled(False)
        # Help button
        helpButton = self.helpButton
        helpButton.setText(self.HELP)

        # Connect signals
        self.showInfo("Connecting signals")
        okButton.clicked.connect(self.startWorker)
        cancelButton.clicked.connect(self.killWorker)
        closeButton.clicked.connect(self.reject)
        helpButton.clicked.connect(self.help)
        browseButton.clicked.connect(self.browse)

        inpIndexCh = self.inputRaster.currentIndexChanged['QString']
        inpIndexCh.connect(self.layerchanged)
        bandCh = self.bandComboBox.currentIndexChanged['QString']
        bandCh.connect(self.bandChanged)
        #self.iface.legendInterface().itemAdded.connect(
        #    self.layerlistchanged)
        #self.iface.legendInterface().itemRemoved.connect(
        #    self.layerlistchanged)
        #QObject.disconnect(self.button_box, SIGNAL("rejected()"), self.reject)
        self.button_box.rejected.disconnect(self.reject)
        calchistPr = self.calcHistPushButton.clicked
        calchistPr.connect(self.calculateHistogram)
        sugglevPr = self.suggestlevelsPushButton.clicked
        sugglevPr.connect(self.suggestLevels)
        addlevPr = self.addlevelPushButton.clicked
        addlevPr.connect(self.addLevel)
        dellevPr = self.deletelevelsPushButton.clicked
        dellevPr.connect(self.removeLevel)

        maxvalCh = self.maxValueSpinBox.valueChanged
        maxvalCh.connect(self.minmaxvalueChanged)
        maxvalFi = self.maxValueSpinBox.editingFinished
        maxvalFi.connect(self.minmaxvalueEdFinished)
        minvalCh = self.minValueSpinBox.valueChanged
        minvalCh.connect(self.minmaxvalueChanged)
        minvalFi = self.minValueSpinBox.editingFinished
        minvalFi.connect(self.minmaxvalueEdFinished)

        # Set instance variables
        #self.mem_layer = None
        self.worker = None
        self.inputlayerid = None
        self.inputlayer = None
        self.layerlistchanging = False
        self.minvalue = 1
        self.inputrasterprovider = None
        self.histobins = 50
        self.setupScene = QGraphicsScene(self)
        self.histoGraphicsView.setScene(self.setupScene)
        # Is the layer band of an integer type
        self.intband = False
        self.histogramAvailable = False
        self.histo = None
        self.histopadding = 1

    def startWorker(self):
        """Initialises and starts the worker thread."""
        try:
            layerindex = self.inputRaster.currentIndex()
            layerId = self.inputRaster.itemData(layerindex)
            inputlayer = QgsProject.instance().mapLayer(layerId)
            #inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
            if inputlayer is None:
                self.showError(self.tr('No input layer defined'))
                return
            # create a reference to the layer that is being processed
            # (for use when creating the resulting raster layer)
            self.thinninglayer = inputlayer
            self.levels = []
            #self.levelsListView.selectAll()
            #selected = self.levelsListView.selectedIndexes()
            if self.levelsListView.model().rowCount() == 0:
                self.showInfo("Levels must be specified!")
                return
            for i in range(self.levelsListView.model().rowCount()):
                levelstring = self.levelsListView.model().item(i).text()
            #for i in selected:
            #    levelstring = self.levelsListView.model().itemData(i)[0]
                if self.intband:
                    self.levels.append(int(levelstring))
                else:
                    self.levels.append(float(levelstring))
            #self.levelsListView.clearSelection()
            # create a new worker instance
            worker = Worker(inputlayer, self.levels, self.intband)
            # configure the QgsMessageBar
            msgBar = self.iface.messageBar().createMessage(
                                        self.tr('Skeletonising'), '')
            self.aprogressBar = QProgressBar()
            self.aprogressBar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            acancelButton = QPushButton()
            acancelButton.setText(self.CANCEL)
            acancelButton.clicked.connect(self.killWorker)
            msgBar.layout().addWidget(self.aprogressBar)
            msgBar.layout().addWidget(acancelButton)
            # Has to be popped after the thread has finished (in
            # workerFinished).
            self.iface.messageBar().pushWidget(msgBar,
                                        Qgis.Info)
            self.messageBar = msgBar
            # start the worker in a new thread
            thread = QThread(self)
            worker.moveToThread(thread)
            worker.finished.connect(self.workerFinished)
            worker.error.connect(self.workerError)
            worker.status.connect(self.workerInfo)
            worker.progress.connect(self.progressBar.setValue)
            worker.progress.connect(self.aprogressBar.setValue)
            worker.iterprogress.connect(self.iterProgressBar.setValue)
            thread.started.connect(worker.run)
            thread.start()
            self.thread = thread
            self.worker = worker
            self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
            self.button_box.button(QDialogButtonBox.Close).setEnabled(False)
            self.button_box.button(QDialogButtonBox.Cancel).setEnabled(True)
        except:
            import traceback
            self.showError(traceback.format_exc())
        else:
            pass

    def workerFinished(self, ok, ret):
        """Handles the output from the worker and cleans up after the
           worker has finished."""
        # clean up the worker and thread
        self.showInfo("Handling the result")
        self.worker.deleteLater()
        self.thread.quit()
        self.thread.wait()
        self.thread.deleteLater()
        # remove widget from message bar (pop)
        self.iface.messageBar().popWidget(self.messageBar)
        if ok and ret is not None:
            #self.showInfo("Ret: "+str(ret[10,]))
            # Transformation:
            self.minx = self.thinninglayer.extent().xMinimum()
            self.maxx = self.thinninglayer.extent().xMaximum()
            self.miny = self.thinninglayer.extent().yMinimum()
            self.maxy = self.thinninglayer.extent().yMaximum()
            self.rows = self.thinninglayer.height()
            self.cols = self.thinninglayer.width()
            self.xres = (self.maxx - self.minx) / float(self.cols)
            self.yres = (self.maxy - self.miny) / float(self.rows)
            geotransform = (self.minx, self.xres, 0, self.maxy, 0, -self.yres)
            try:
                format = self.DEFAULTPROVIDER
                driver = gdal.GetDriverByName(format)
                NOVALUE = 0
                metadata = driver.GetMetadata()
                fileName = self.outputRaster.text()
                if self.outputRaster.text() == "":
                    self.showInfo("No output file specified, " +
                                         "creating a temporary file")
                    # Get a temporary file
                    fileName = mktemp(prefix='greyskel',
                           suffix=self.DEFAULTEXTENSION)
                fileInfo = QFileInfo(fileName)
                filepath = fileInfo.absolutePath()
                baseName = fileInfo.baseName()
                suffix = fileInfo.suffix()
                thisfilename = filepath + baseName + '.' + suffix
                thisfilename = fileName
                self.showInfo("File name: " + thisfilename)
                gdaldatatype = gdal.GDT_Byte
                skelmatrix = None
                if self.levelValuesCheckBox.isChecked():
                    # Transform the pixel values back to the original
                    # level values
                    my_dict = {}
                    # Add zero to handle the "empty" pixels
                    my_dict[0] = 0
                    for i in range(len(self.levels)):
                        my_dict[i + 1] = self.levels[i]
                    skelmatrix = np.vectorize(my_dict.__getitem__,
                                              otypes=[np.float])(ret)
                    gdaldatatype = gdal.GDT_Int32
                    if not self.intband:
                        gdaldatatype = gdal.GDT_Float32
                else:
                    skelmatrix = ret
                outDataset = driver.Create(thisfilename, self.cols,
                                           self.rows, 1, gdaldatatype)
                if self.thinninglayer.dataProvider().crs() is not None:
                    srs = self.thinninglayer.dataProvider().crs()
                    outDataset.SetProjection(srs.toWkt().encode('ascii',
                                                               'ignore'))
                skeletonband = outDataset.GetRasterBand(1)
                skeletonband.WriteArray(skelmatrix)
                skeletonband.SetNoDataValue(NOVALUE)
                #stats = skeletonband.GetStatistics(False, True)
                #skeletonband.SetStatistics(stats[0], stats[1],
                #                                 stats[2], stats[3])
                outDataset.SetGeoTransform(geotransform)
                outDataset = None  # To close the file
                # report the result
                rlayer = QgsRasterLayer(thisfilename, baseName)
                self.layerlistchanging = True
                #QgsMapLayerRegistry.instance().addMapLayer(rlayer)
                QgsProject.instance().addMapLayer(rlayer)
                self.layerlistchanging = False
            except:
                import traceback
                self.showError("Can't write the skeleton file:  %s" %
                                   self.outputRaster.text() + ' - ' +
                                   traceback.format_exc())
                okb = self.button_box.button(QDialogButtonBox.Ok)
                okb.setEnabled(True)
                closb = self.button_box.button(QDialogButtonBox.Close)
                closb.setEnabled(True)
                cancb = self.button_box.button(QDialogButtonBox.Cancel)
                cancb.setEnabled(False)
                return
            QgsMessageLog.logMessage(self.tr('ThinGreyscale finished'),
                                self.THINGREYSCALE, Qgis.Info)
        else:
            # notify the user that something went wrong
            if not ok:
                self.showError(self.tr('Aborted') + '!')
            else:
                self.showError(self.tr('No skeleton created') + '!')
        self.progressBar.setValue(0.0)
        #self.aprogressBar.setValue(0.0)
        self.iterProgressBar.setValue(0.0)
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
        self.button_box.button(QDialogButtonBox.Close).setEnabled(True)
        self.button_box.button(QDialogButtonBox.Cancel).setEnabled(False)

    def workerError(self, exception_string):
        """Report an error from the worker."""
        #QgsMessageLog.logMessage(self.tr('Worker failed - exception') +
        #                         ': ' + str(exception_string),
        #                         self.THINGREYSCALE,
        #                         QgsMessageLog.CRITICAL)
        self.showError(exception_string)

    def workerInfo(self, message_string):
        """Report an info message from the worker."""
        QgsMessageLog.logMessage(self.tr('Worker') + ': ' + message_string,
                                 self.THINGREYSCALE, Qgis.Info)

    def layerchanged(self, number=0):
        """Do the necessary updates after a layer selection has
           been changed."""
        self.showInfo("Layer changed")
        # If the layer list is being updated, don't do anything
        if self.layerlistchanging:
            return
        layerindex = self.inputRaster.currentIndex()
        layerId = self.inputRaster.itemData(layerindex)
        self.inputlayerid = layerId
        #self.inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
        self.inputlayer = QgsProject.instance().mapLayer(layerId)
        if self.inputlayer is not None:
            self.inputrasterprovider = self.inputlayer.dataProvider()
            self.bandComboBox.clear()
            bandcount = self.inputlayer.bandCount()
            #self.showInfo("Layer bandcount: "+str(bandcount))
            for i in range(bandcount):
                self.bandComboBox.addItem(self.inputlayer.bandName(i + 1), i)
                #self.showInfo("Band " + str(i) + ": " +
                #                self.inputlayer.bandName(i+1))
            # Check if the driver supports Create() or CreateCopy()
            #gdalmetadata = self.inputlayer.metadata()
            #self.showInfo("Layer metadata: " +
            #                str(gdalmetadata.encode('utf-8')))
            #provstring = '<p>GDAL provider</p>\n'
            #providerpos = gdalmetadata.find(provstring)
            #brpos = gdalmetadata.find('<br>', providerpos + len(provstring))
            #self.gdalprovider = gdalmetadata[int(providerpos +
            #                             len(provstring)):int(brpos)]
            #self.showInfo('GDAL provider: '+self.gdalprovider)
            #drivername = self.gdalprovider.encode('ascii', 'ignore')
            #theDriver = gdal.GetDriverByName(drivername)
            #if theDriver is None:
            #    self.showInfo("Unable to get the raster driver")
            #else:
            #data    theMetadata = theDriver.GetMetadata()
                #self.showInfo("Driver metadata: "+str(theMetadata))
                #if ((gdal.DCAP_CREATE in theMetadata) and
                #        theMetadata[gdal.DCAP_CREATE] == 'YES'):
                #    self.canCreate = True
                #if (theMetadata.has_key(gdal.DCAP_CREATECOPY) and
                #if ((gdal.DCAP_CREATECOPY in theMetadata) and
                #        theMetadata[gdal.DCAP_CREATECOPY] == 'YES'):
                #    self.canCreateCopy = True
                #self.showInfo('raster provider type: ' +
                #                str(self.inputlayer.providerType()))
                # Determine the file suffix
                #self.gdalext = ""
                #if gdal.DMD_EXTENSION in theMetadata:
                #    self.gdalext = "." + theMetadata[gdal.DMD_EXTENSION]
                #else:
                #    self.showInfo("No extension available in GDAL metadata")
                # by parsing the layer metadata looking for
                #           "Dataset Description"
                #descstring = 'Dataset Description</p>\n<p>'
                #descpos = gdalmetadata.find(descstring)
                #ppos = gdalmetadata.find('</p>',descpos+len(descstring))
                #filename = gdalmetadata[descpos+len(descstring):ppos]
                #self.gdalext = splitext(filename)[1]
                #self.showInfo('GDAL extension: '+self.gdalext)
                # Determine the datatype
                #datatypestring = 'Data Type</p>\n<p>'
                #datatypepos = gdalmetadata.find(datatypestring)
                #ppos = gdalmetadata.find('</p>',
                #                   datatypepos + len(datatypestring))
                #datatypedesc = gdalmetadata[datatypepos +
                #                            len(datatypestring):ppos]
                #shortdesc = datatypedesc.split()[0]
                #self.showInfo('GDAL data type: GDT_'+shortdesc)
                # Call the findGdalDatatype function
                #self.findGdalDatatype(shortdesc)
            #   self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
            self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
            self.calcHistPushButton.setEnabled(True)
            self.suggestlevelsPushButton.setEnabled(True)

    def bandChanged(self):
        band = self.bandComboBox.currentIndex() + 1
        self.showInfo("Band changed: " + str(band))
        statistics = self.inputrasterprovider.bandStatistics(band)
        #self.showInfo("Band statistics: " + str(statistics.minimumValue) +
        #                            " - " + str(statistics.maximumValue) +
        #                            " - " + str(statistics.mean))
        self.bandmin = statistics.minimumValue
        self.bandmax = statistics.maximumValue
        dt = self.inputrasterprovider.dataType(band)
        # Integer data type
        if (dt == Qgis.Byte or dt == Qgis.UInt16 or dt == Qgis.Int16
                            or dt == Qgis.UInt32 or dt == Qgis.Int32):
            self.intband = True
            self.minValueSpinBox.setDecimals(0)
            self.maxValueSpinBox.setDecimals(0)
            self.levelSpinBox.setDecimals(0)
            self.bandMinLabel.setText(str(int(statistics.minimumValue)))
            self.bandMaxLabel.setText(str(int(statistics.maximumValue)))
        else:
            self.intband = False
            self.minValueSpinBox.setDecimals(5)
            self.maxValueSpinBox.setDecimals(5)
            self.levelSpinBox.setDecimals(5)
            minlabtext = "{0:.5f}".format(statistics.minimumValue)
            self.bandMinLabel.setText(minlabtext)
            maxlabtext = "{0:.5f}".format(statistics.maximumValue)
            self.bandMaxLabel.setText(maxlabtext)
        #self.minValueSpinBox.setMinimum(statistics.minimumValue)
        self.maxValueSpinBox.setMinimum(statistics.minimumValue)
        #self.minValueSpinBox.setMaximum(statistics.maximumValue)
        self.maxValueSpinBox.setMaximum(statistics.maximumValue)
        #self.minValueSpinBox.setValue(statistics.minimumValue)
        if not (statistics.statsGathered & statistics.Mean):
            bandmean = (statistics.minimumValue + statistics.maximumValue) / 2
        else:
            #self.showInfo("statsgathered: " + str(statistics.statsGathered))
            bandmean = statistics.mean
        if self.intband:
            self.minValueSpinBox.setValue(int(ceil(bandmean)))
        else:
            self.minValueSpinBox.setValue(bandmean)
        self.maxValueSpinBox.setValue(statistics.maximumValue)
        self.histMinValue.setText(str(statistics.minimumValue))
        self.histMaxValue.setText(str(statistics.maximumValue))
        self.levelSpinBox.setMinimum(statistics.minimumValue)
        self.levelSpinBox.setMaximum(statistics.maximumValue)
        self.histogramAvailable = False
        #if self.inputrasterprovider.hasStatistics(band):
        #if statistics.statsGathered:
            #histogram = statistics.histogramVector
            #self.showInfo("Histogram: " + str(histogram))
            #range = min to max
            #np.histogram(band, 50, range)

    def minmaxvalueChanged(self):
        #if self.minValueSpinBox is None:
        #    return
        minvalue = self.minValueSpinBox.value()
        #if minvalue is None:
        #    return
        #if self.maxValueSpinBox is None:
        #    return
        maxvalue = self.maxValueSpinBox.value()
        #if maxvalue is None:
        #   return
        if isnan(maxvalue) or isnan(minvalue):
            return
        self.showInfo("minvalue: " + str(minvalue) + " Maxvalue: " +
                                                       str(maxvalue))
        #if self.intband:
        #    minvalue = int(minvalue)
        #    maxvalue = int(maxvalue)
        if abs(maxvalue - minvalue) < 0.00001:
        #if maxvalue == maxvalue:
            self.calcHistPushButton.setEnabled(False)
        else:
            self.calcHistPushButton.setEnabled(True)
        # Update the min and max value spinboxes
        self.minValueSpinBox.setMaximum(maxvalue)
        self.maxValueSpinBox.setMinimum(minvalue)
        self.minValueSpinBox.setMinimum(self.bandmin)

    def minmaxvalueEdFinished(self):
        minvalue = self.minValueSpinBox.value()
        maxvalue = self.maxValueSpinBox.value()
        if self.intband:
            minvalue = int(minvalue)
            maxvalue = int(maxvalue)
        self.showInfo("minvalue: " + str(minvalue) + " Maxvalue: " +
                                    str(maxvalue))
        # Update the spin box for adding levels
        self.levelSpinBox.setMinimum(minvalue)
        self.levelSpinBox.setMaximum(maxvalue)
        if self.levelSpinBox.value() < minvalue:
            self.levelSpinBox.setValue(minvalue)
        if self.levelSpinBox.value() > maxvalue:
            self.levelSpinBox.setValue(maxvalue)
        # Update the min and max value spinboxes
        self.minValueSpinBox.setMaximum(maxvalue)
        self.maxValueSpinBox.setMinimum(minvalue)

        # Adjust the levels:
        i = 0
        while self.levelsListView.model().item(i):
        #for i in range(self.levelsListView.model().rowCount()):
            #self.showInfo("Element: " +
            #       str(self.levelsListView.model().item(i).text()))
            #continue
            value = float(self.levelsListView.model().item(i).text())
            if value < minvalue:
                if i == 0:
                    self.levelsListView.model().item(i).setText(str(minvalue))
                    i = i + 1
                else:
                    self.levelsListView.model().removeRow(i)
            elif value > maxvalue:
                if i == self.levelsListView.model().rowCount() - 1:
                    self.levelsListView.model().item(i).setText(str(maxvalue))
                    i = i + 1
                else:
                    self.levelsListView.model().removeRow(i)
            else:
                i = i + 1
        self.drawHistogram()

    def calculateHistogram(self):
        self.showInfo("Calculating histogram...")
        if self.inputlayer is None:
            return
        
        self.showInfo("Calculating histogram...")
        # Check if there is only one value
        myrange = (self.minValueSpinBox.value(),
                   self.maxValueSpinBox.value())
        self.inputextent = self.inputlayer.extent()
        self.inputrdp = self.inputlayer.dataProvider()
        width = self.inputlayer.width()
        height = self.inputlayer.height()
        if width == 0 or height == 0:
            self.showInfo("Image has zero width or height")
            return
        extwidth = self.inputextent.width()
        extheight = self.inputextent.height()
        # Read the raster block and get the maximum value
        rasterblock = self.inputrdp.block(1, self.inputextent,
                                          width, height)
        # Create a numpy array version of the image
        imageMat = np.zeros((height, width), dtype=np.float16)
        # This one takes a lot of time!
        for row in range(height):
            for column in range(width):
                imageMat[row, column] = rasterblock.value(row, column)
                self.showInfo("Image: " + str(height) + ", " + str(width) + " - " + str(imageMat[row, column]))
        self.histo = np.histogram(imageMat, self.histobins, myrange)
        #relevantpixels = imageMat[np.where(imageMat >= bandval)]
        minlevel = float(self.bandMinLabel.text())
        relevantpixels = imageMat[np.where(imageMat >= minlevel)]
        #self.showInfo("Histogram: " + str(self.histo))
        nanpercentage = 100.0 - 100.0 * len(relevantpixels) / (width * height)
        self.bandNANLabel.setText("{0:.1f}".format(nanpercentage))
        #self.showInfo("Percentage NAN: " + str(100.0 - 100.0 *
        #                    len(relevantpixels) / (width * height)))
        #self.showInfo("First element: " + str(self.histo[0]))
        #self.showInfo("First element, first: " + str(self.histo[0][0]))
        #self.showInfo("First element, second: " + str(self.histo[0][1]))
        self.histMinValue.setText(str(self.minValueSpinBox.value()))
        self.histMaxValue.setText(str(self.maxValueSpinBox.value()))
        if self.intband:
            self.histMinValue.setText(str(int(self.minValueSpinBox.value())))
            self.histMaxValue.setText(str(int(self.maxValueSpinBox.value())))
        self.histogramAvailable = True
        self.drawHistogram()

    def drawHistogram(self):
        #if self.inputlayer is None:
        #    return
        self.showInfo("Drawing histogram...")
        viewprect = QRectF(self.histoGraphicsView.viewport().rect())
        self.histoGraphicsView.setSceneRect(viewprect)
        self.setupScene.clear()
        self.setupScene.update()
        histbottom = self.histoGraphicsView.sceneRect().bottom()
        histtop = self.histoGraphicsView.sceneRect().top()
        left = self.histoGraphicsView.sceneRect().left() + self.histopadding
        right = self.histoGraphicsView.sceneRect().right() - self.histopadding
        histheight = histbottom - histtop
        histwidth = right - left
        step = 1.0 * histwidth / self.histobins
        maxlength = histheight
        padding = 1
        ll = QPoint(self.histopadding - 1, histheight - padding)
        start = QPointF(self.histoGraphicsView.mapToScene(ll))

        # Check if there is only one value
        #myrange = (self.minValueSpinBox.value(),self.maxValueSpinBox.value())
        if self.histogramAvailable:
            maxvalue = 0.0
            for i in range(len(self.histo[0])):
                if self.histo[0][i] > maxvalue:
                    maxvalue = self.histo[0][i]
            if maxvalue == 0:
                return
            self.maxBinNumber.setText(str(maxvalue))
            # Create the histogram:
            #self.showInfo("maxvalue: " + str(maxvalue))
            #self.showInfo("maxlength: " + str(maxlength))
            #self.showInfo("step: " + str(step))
            for i in range(self.histobins):
                binnumber = self.histo[0][i]
                if binnumber == 0:
                    continue
                height = (1.0 * self.histo[0][i] / maxvalue *
                                          (maxlength - padding))
                rectangle = QGraphicsRectItem(start.x() + step * i,
                                          start.y(),
                                          step,
                                          -height)
                rectangle.setPen(QPen(QColor(102, 102, 102)))
                rectangle.setBrush(QBrush(QColor(240, 240, 240)))
                self.setupScene.addItem(rectangle)
                #self.showInfo(str(i) + ": " + str(height))
            #if self.levelsListView.model().rowCount() > 0:
        # Add lines for the levels
        minvalue = float(self.histMinValue.text())
        maxvalue = float(self.histMaxValue.text())
        datarange = maxvalue - minvalue
        if datarange == 0:
            return
        i = 0
        while self.levelsListView.model().item(i):
            #self.showInfo("Element: " +
            #       str(self.levelsListView.model().item(i).text()))
            #continue
            value = float(self.levelsListView.model().item(i).text())
            xvalue = start.x() + histwidth * (value - minvalue) / datarange
            line = QGraphicsLineItem(xvalue, 0, xvalue, histheight)
            if i == 0 or i == (self.levelsListView.model().rowCount() - 1):
                line.setPen(QPen(QColor(204, 0, 0)))
            else:
                line.setPen(QPen(QColor(0, 204, 0)))
            self.setupScene.addItem(line)
            i = i + 1

    def suggestLevels(self):
        self.listModel.clear()
        self.showInfo("Suggesting levels")
        levels = self.levelsSpinBox.value()
        startvalue = self.minValueSpinBox.value()
        endvalue = self.maxValueSpinBox.value()
        increment = (endvalue - startvalue) / levels
        for i in range(levels + 1):
            value = startvalue + increment * i
            if self.intband:
                value = int(value)
            item = QStandardItem(str(value))
            self.listModel.appendRow(item)
        self.drawHistogram()

    def addLevel(self):
        newvalue = self.levelSpinBox.value()
        if self.intband:
            newvalue = int(newvalue)
        for i in range(self.listModel.rowCount()):
            # Check if the value is already in the list
            if self.listModel.item(i).text() == str(newvalue):
                return
            else:
                # Maintain a sorted list of distances
                if (float(self.listModel.item(i).text()) >
                                 float(str(newvalue))):
                    item = QStandardItem(str(newvalue))
                    self.listModel.insertRow(i, item)
                    self.drawHistogram()
                    return
        item = QStandardItem(str(newvalue))
        self.listModel.appendRow(item)
        #if self.histogramAvailable:
        #    addLevelsToHistogram()
        self.drawHistogram()

    def removeLevel(self):
        self.levelsListView.setUpdatesEnabled(False)
        indexes = self.levelsListView.selectedIndexes()
        indexes.sort()
        for i in range(len(indexes) - 1, -1, -1):
            self.listModel.removeRow(indexes[i].row())
        self.levelsListView.setUpdatesEnabled(True)
        #if self.histogramAvailable:
        #    removeLevelFromHistogram()
        self.drawHistogram()

    def layerlistchanged(self):
        self.layerlistchanging = True
        self.showInfo("Layer list changed")
        # Repopulate the input layer combo box
        # Save the currently selected input layer
        inputlayerid = self.inputlayerid
        self.inputRaster.clear()
        for alayer in self.iface.legendInterface().layers():
            if alayer.type() == QgsMapLayer.RasterLayer:
                gdalmetadata = alayer.metadata()
                # Skip WMS layers
                WMSstring = 'Web Map Service'
                wmspos = gdalmetadata.find(WMSstring)
                if wmspos != -1:
                    continue
                self.inputRaster.addItem(alayer.name(), alayer.id())
        # Set the previous selection
        for i in range(self.inputRaster.count()):
            if self.inputRaster.itemData(i) == inputlayerid:
                self.inputRaster.setCurrentIndex(i)
        self.layerlistchanging = False
        #self.updateui()

    def updateui(self):
        """Do the necessary updates after a layer selection has
           been changed."""
        #if self.layerlistchanged:
        #    return
        #self.outputRaster.setText(self.inputRaster.currentText() +
        #                           '_' + 'thinned')
        layerindex = self.inputRaster.currentIndex()
        layerId = self.inputRaster.itemData(layerindex)
        #inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
        inputlayer = QgsProject.instance().mapLayer(layerId)
        if inputlayer is not None:
            pass
        else:
            pass

    def findGdalDatatype(self, shortdesc):
            gdaldatatype = None
            # // Unknown or unspecified type
            # GDT_Unknown = GDALDataType(C.GDT_Unknown)
            if shortdesc == 'Unknown':
                gdaldatatype = gdal.GDT_Unknown
            # // Eight bit unsigned integer
            # GDT_Byte = GDALDataType(C.GDT_Byte)
            elif shortdesc == 'Byte':
                gdaldatatype = gdal.GDT_Byte
            # // Sixteen bit unsigned integer
            # GDT_UInt16 = GDALDataType(C.GDT_UInt16)
            elif shortdesc == 'UInt16':
                gdaldatatype = gdal.GDT_UInt16
            # // Sixteen bit signed integer
            # GDT_Int16 = GDALDataType(C.GDT_Int16)
            elif shortdesc == 'Int16':
                gdaldatatype = gdal.GDT_Int16
            # // Thirty two bit unsigned integer
            # GDT_UInt32 = GDALDataType(C.GDT_UInt32)
            elif shortdesc == 'UInt32':
                gdaldatatype = gdal.GDT_UInt32
            # // Thirty two bit signed integer
            # GDT_Int32 = GDALDataType(C.GDT_Int32)
            elif shortdesc == 'Int32':
                gdaldatatype = gdal.GDT_Int32
            # // Thirty two bit floating point
            # GDT_Float32 = GDALDataType(C.GDT_Float32)
            elif shortdesc == 'Float32':
                gdaldatatype = gdal.GDT_Float32
            # // Sixty four bit floating point
            # GDT_Float64 = GDALDataType(C.GDT_Float64)
            elif shortdesc == 'Float64':
                gdaldatatype = gdal.GDT_Float64
            # // Complex Int16
            # GDT_CInt16 = GDALDataType(C.GDT_CInt16)
            elif shortdesc == 'CInt16':
                gdaldatatype = gdal.CInt16
            # // Complex Int32
            # GDT_CInt32 = GDALDataType(C.GDT_CInt32)
            elif shortdesc == 'CInt32':
                gdaldatatype = gdal.CInt32
            # // Complex Float32
            # GDT_CFloat32 = GDALDataType(C.GDT_CFloat32)
            elif shortdesc == 'CFloat32':
                gdaldatatype = gdal.CFloat32
            # // Complex Float64
            # GDT_CFloat64 = GDALDataType(C.GDT_CFloat64)
            elif shortdesc == 'CFloat64':
                gdaldatatype = gdal.CFloat64
            # // maximum type # + 1
            # GDT_TypeCount = GDALDataType(C.GDT_TypeCount)
            elif shortdesc == 'TypeCount':
                gdaldatatype = gdal.TypeCount
            self.gdaldatatype = gdaldatatype

    def killWorker(self):
        """Kill the worker thread."""
        if self.worker is not None:
            QgsMessageLog.logMessage(self.tr('Killing worker'),
                                     self.THINGREYSCALE, Qgis.Info)
            self.worker.kill()

    def showError(self, text):
        """Show an error."""
        self.iface.messageBar().pushMessage(self.tr('Error'), text,
                                            level=QgsMessageBar.CRITICAL,
                                            duration=3)
        QgsMessageLog.logMessage('Error: ' + text, self.THINGREYSCALE,
                                 QgsMessageLog.CRITICAL)

    def showWarning(self, text):
        """Show a warning."""
        self.iface.messageBar().pushMessage(self.tr('Warning'), text,
                                            level=QgsMessageBar.WARNING,
                                            duration=2)
        QgsMessageLog.logMessage('Warning: ' + text, self.THINGREYSCALE,
                                 QgsMessageLog.WARNING)

    def showInfo(self, text):
        """Show info."""
        self.iface.messageBar().pushMessage(self.tr('Info'), text,
                                            level=Qgis.Info,
                                            duration=2)
        QgsMessageLog.logMessage('Info: ' + text, self.THINGREYSCALE,
                                 Qgis.Info)

    # def help(self):
        # #QDesktopServices.openUrl(QUrl.fromLocalFile(self.plugin_dir +
        #                                 "/help/build/html/index.html"))
        # QDesktopServices.openUrl(QUrl.fromLocalFile(self.plugin_dir +
        #                                            "/help/index.html"))
        # #showPluginHelp()

    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        return QCoreApplication.translate('ThinGreyScaleDialog', message)

    def browse(self):
        settings = QSettings()
        key = '/UI/lastShapefileDir'
        outDir = settings.value(key)
        home = outDir
        #outDir = expanduser("~")
        #filter = (self.DEFAULTPROVIDER + " (*" +
        #             self.DEFAULTEXTENSION + ");;All files (*)")
        filter = (self.DEFAULTPROVIDER + " (*" +
                     self.DEFAULTEXTENSION + self.EXTRAEXTENSION + ")")
        #if (self.gdalprovider != self.DEFAULTPROVIDER and
        #                                     (self.canCreateCopy or
        #                                           self.canCreate)):
        #    filter = (self.gdalprovider + " (*" + self.gdalext +
        #                                          ");;" + filter)
        outFilePath = QFileDialog.getSaveFileName(self,
                                   'Specify file name for skeleton',
                                                     outDir, filter)
        outFilePath = unicode(outFilePath)
        if outFilePath:
            root, ext = splitext(outFilePath)
            if ext.lower() != '.tif' and ext.lower() != '.tiff':
                outFilePath = '%s.tif' % outFilePath
            outDir = dirname(outFilePath)
            settings.setValue(key, outDir)
        #        (self.canCreateCopy or self.canCreate):
        #    fileName = splitext(str(fileName))[0]+self.gdalext
        self.outputRaster.setText(outFilePath)

    # Overriding
    def resizeEvent(self, event):
        #self.showInfo("resizeEvent")
        self.calculateHistogram()

    def help(self):
        #QDesktopServices.openUrl(QUrl.fromLocalFile(
        #                 self.plugin_dir + "/help/html/index.html"))
        showPluginHelp(None, "help/html/index")

    # Implement the accept method to avoid exiting the dialog when
    # starting the work
    def accept(self):
        """Accept override."""
        pass

    # Implement the reject method to have the possibility to avoid
    # exiting the dialog when cancelling
    def reject(self):
        """Reject override."""
        # exit the dialog
        QDialog.reject(self)
Пример #4
0
class PosiviewProperties(QgsOptionsDialogBase, Ui_PosiviewPropertiesBase):
    '''
    GUI class classdocs for the Configuration dialog
    '''
    applyChanges = pyqtSignal(dict)

    def __init__(self, project, parent=None):
        '''
        Setup dialog widgets with the project properties
        '''
        super(PosiviewProperties, self).__init__("PosiViewProperties", parent)
        self.setupUi(self)
        self.groupBox_6.hide()
        self.initOptionsBase(False)
        self.restoreOptionsBaseUi()
        self.comboBoxParser.addItems(PARSERS)
        self.comboBoxProviderType.addItems(DEVICE_TYPES)
        self.project = project
        self.projectProperties = project.properties()
        self.mToolButtonLoad.setDefaultAction(self.actionLoadConfiguration)
        self.mToolButtonSave.setDefaultAction(self.actionSaveConfiguration)

        self.mobileModel = QStringListModel()
        self.mobileListModel = QStringListModel()
        self.mMobileListView.setModel(self.mobileListModel)
        self.mobileProviderModel = QStandardItemModel()
        self.mobileProviderModel.setHorizontalHeaderLabels(
            ('Provider', 'Filter'))
        self.mMobileProviderTableView.setModel(self.mobileProviderModel)

        self.providerListModel = QStringListModel()
        self.mDataProviderListView.setModel(self.providerListModel)
        self.comboBoxProviders.setModel(self.providerListModel)
        self.setupModelData(self.projectProperties)
        self.setupGeneralData(self.projectProperties)

    def setupModelData(self, properties):
        self.mobileListModel.setStringList(sorted(
            properties['Mobiles'].keys()))
        self.providerListModel.setStringList(
            sorted(properties['Provider'].keys()))

    def setupGeneralData(self, properties):
        self.lineEditCruise.setText(properties['Mission']['cruise'])
        self.lineEditDive.setText(properties['Mission']['dive'])
        self.lineEditStation.setText(properties['Mission']['station'])
        self.lineEditRecorderPath.setText(properties['RecorderPath'])
        self.checkBoxAutoRecording.setChecked(properties['AutoRecord'])
        self.spinBoxNotifyDuration.setValue(properties['NotifyDuration'])
        self.checkBoxUtcClock.setChecked(properties['ShowUtcClock'])
        self.checkBoxWithSuffix.setChecked(properties['DefaultFormat'] & 4)
        self.comboBoxDefaultPositionFormat.setCurrentIndex(
            (properties['DefaultFormat']) & 3)

    def updateGeneralData(self):
        self.projectProperties['Mission']['cruise'] = self.lineEditCruise.text(
        )
        self.projectProperties['Mission']['dive'] = self.lineEditDive.text()
        self.projectProperties['Mission'][
            'station'] = self.lineEditStation.text()
        self.projectProperties[
            'RecorderPath'] = self.lineEditRecorderPath.text()
        self.projectProperties[
            'AutoRecord'] = self.checkBoxAutoRecording.isChecked()
        self.projectProperties[
            'NotifyDuration'] = self.spinBoxNotifyDuration.value()
        self.projectProperties[
            'ShowUtcClock'] = self.checkBoxUtcClock.isChecked()
        self.projectProperties[
            'DefaultFormat'] = self.comboBoxDefaultPositionFormat.currentIndex(
            )
        if self.checkBoxWithSuffix.isChecked():
            self.projectProperties['DefaultFormat'] |= 4

    def getColor(self, value):
        try:
            return QColor.fromRgba(int(value))
        except ValueError:
            return QColor(value)

    @pyqtSlot(QAbstractButton, name='on_buttonBox_clicked')
    def onButtonBoxClicked(self, button):
        role = self.buttonBox.buttonRole(button)
        if role == QDialogButtonBox.ApplyRole or role == QDialogButtonBox.AcceptRole:
            self.updateGeneralData()
            self.applyChanges.emit(self.projectProperties)

    @pyqtSlot(name='on_actionSaveConfiguration_triggered')
    def onActionSaveConfigurationTriggered(self):
        ''' Save the current configuration
        '''
        fn, __ = QFileDialog.getSaveFileName(None,
                                             'Save PosiView configuration', '',
                                             'Configuration (*.ini *.conf)')
        if fn:
            if not os.path.splitext(fn)[1]:
                fn += u'.conf'
            self.project.store(fn)

    @pyqtSlot(name='on_actionLoadConfiguration_triggered')
    def onActionLoadConfigurationTriggered(self):
        ''' Load configuration from file
        '''
        fn, __ = QFileDialog.getOpenFileName(None,
                                             'Save PosiView configuration', '',
                                             'Configuration (*.ini *.conf)')
        self.projectProperties = self.project.read(fn)
        self.setupModelData(self.projectProperties)
        self.setupGeneralData(self.projectProperties)

    @pyqtSlot(QModelIndex, name='on_mMobileListView_clicked')
    def editMobile(self, index):
        ''' Populate the widgets with the selected mobiles properties
        '''
        if index.isValid():
            self.populateMobileWidgets(index)

    @pyqtSlot(str, name='on_comboBoxMobileType_currentIndexChanged')
    def mobileTypeChanged(self, mType):
        if mType == 'SHAPE':
            self.lineEditMobileShape.setEnabled(True)
        else:
            self.lineEditMobileShape.setEnabled(False)

    @pyqtSlot(QModelIndex, name='on_mMobileListView_activated')
    def activated(self, index):
        pass

    @pyqtSlot(name='on_toolButtonAddMobile_clicked')
    def addMobile(self):
        self.mobileListModel.insertRow(self.mobileListModel.rowCount())
        index = self.mobileListModel.index(self.mobileListModel.rowCount() - 1)
        self.lineEditMobileName.setText('NewMobile')
        self.mobileListModel.setData(index, 'NewMobile', Qt.DisplayRole)
        self.mMobileListView.setCurrentIndex(index)
        self.applyMobile()

    @pyqtSlot(name='on_pushButtonApplyMobile_clicked')
    def applyMobile(self):
        index = self.mMobileListView.currentIndex()
        if index.isValid() and not self.lineEditMobileName.text() == '':
            mobile = dict()
            mobile['Name'] = self.lineEditMobileName.text()
            mobile['type'] = self.comboBoxMobileType.currentText()
            try:
                t = eval(self.lineEditMobileShape.text())
                if t.__class__ is tuple or t.__class__ is dict:
                    mobile['shape'] = t
            except SyntaxError:
                mobile['shape'] = ((0.0, -0.5), (0.3, 0.5), (0.0, 0.2), (-0.5,
                                                                         0.5))
            mobile['length'] = self.doubleSpinBoxMobileLength.value()
            mobile['width'] = self.doubleSpinBoxMobileWidth.value()
            mobile['defaultIcon'] = self.checkBoxDefaultIcon.isChecked()
            mobile['defaultIconFilled'] = self.checkBoxDefIconFilled.isChecked(
            )
            mobile['offsetX'] = self.doubleSpinBoxXOffset.value()
            mobile['offsetY'] = self.doubleSpinBoxYOffset.value()
            mobile['zValue'] = self.spinBoxZValue.value()
            mobile['color'] = self.mColorButtonMobileColor.color().rgba()
            mobile['fillColor'] = self.mColorButtonMobileFillColor.color(
            ).rgba()
            mobile['timeout'] = self.spinBoxMobileTimeout.value() * 1000
            mobile['nofixNotify'] = self.spinBoxMobileNotification.value()
            mobile['fadeOut'] = self.checkBoxFadeOut.isChecked()
            mobile['trackLength'] = self.spinBoxTrackLength.value()
            mobile['trackColor'] = self.mColorButtonMobileTrackColor.color(
            ).rgba()
            mobile['showLabel'] = self.checkBoxShowLabel.isChecked()
            provs = dict()
            for r in range(self.mobileProviderModel.rowCount()):
                try:
                    fil = int(
                        self.mobileProviderModel.item(r,
                                                      1).data(Qt.DisplayRole))
                except Exception:
                    fil = self.mobileProviderModel.item(r,
                                                        1).data(Qt.DisplayRole)
                    if not fil:
                        fil = None
                provs[self.mobileProviderModel.item(r, 0).data(
                    Qt.DisplayRole)] = fil
            mobile['provider'] = provs
            currName = self.mobileListModel.data(index, Qt.DisplayRole)
            if not currName == mobile['Name']:
                del self.projectProperties['Mobiles'][currName]
                self.mobileListModel.setData(index, mobile['Name'],
                                             Qt.DisplayRole)
            self.projectProperties['Mobiles'][mobile['Name']] = mobile

    def populateMobileWidgets(self, index):
        mobile = self.projectProperties['Mobiles'][self.mobileListModel.data(
            index, Qt.DisplayRole)]
        self.lineEditMobileName.setText(mobile.get('Name'))
        self.comboBoxMobileType.setCurrentIndex(
            self.comboBoxMobileType.findText(
                mobile.setdefault('type', 'BOX').upper()))
        if mobile['type'] == 'SHAPE':
            self.lineEditMobileShape.setText(str(mobile['shape']))
            self.lineEditMobileShape.setEnabled(True)
            self.doubleSpinBoxXOffset.setEnabled(True)
            self.doubleSpinBoxYOffset.setEnabled(True)
        else:
            self.lineEditMobileShape.setEnabled(False)
            self.doubleSpinBoxXOffset.setEnabled(False)
            self.doubleSpinBoxYOffset.setEnabled(False)
            self.lineEditMobileShape.clear()
        self.doubleSpinBoxMobileLength.setValue(mobile.get('length', 20.0))
        self.doubleSpinBoxMobileWidth.setValue(mobile.get('width', 5.0))
        self.checkBoxDefaultIcon.setChecked(mobile.get('defaultIcon', True))
        self.checkBoxDefIconFilled.setChecked(
            mobile.get('defaultIconFilled', False))
        self.doubleSpinBoxXOffset.setValue(mobile.get('offsetX', 0.0))
        self.doubleSpinBoxYOffset.setValue(mobile.get('offsetY', 0.0))
        self.spinBoxZValue.setValue(mobile.get('zValue', 100))
        self.mColorButtonMobileColor.setColor(
            self.getColor(mobile.get('color', 'black')))
        self.mColorButtonMobileFillColor.setColor(
            self.getColor(mobile.get('fillColor', 'green')))
        self.spinBoxMobileTimeout.setValue(mobile.get('timeout', 3000) / 1000)
        self.spinBoxMobileNotification.setValue(mobile.get('nofixNotify', 0))
        self.checkBoxFadeOut.setChecked(mobile.get('fadeOut', False))
        self.spinBoxTrackLength.setValue(mobile.get('trackLength', 100))
        self.mColorButtonMobileTrackColor.setColor(
            self.getColor(mobile.get('trackColor', 'green')))
        self.checkBoxShowLabel.setChecked(mobile.get('showLabel', False))
        r = 0
        self.mobileProviderModel.removeRows(
            0, self.mobileProviderModel.rowCount())
        if 'provider' in mobile:
            for k, v in list(mobile['provider'].items()):
                prov = QStandardItem(k)
                val = QStandardItem(str(v))
                self.mobileProviderModel.setItem(r, 0, prov)
                self.mobileProviderModel.setItem(r, 1, val)
                r += 1

    @pyqtSlot(name='on_toolButtonRemoveMobile_clicked')
    def removeMobile(self):
        idx = self.mMobileListView.currentIndex()
        if idx.isValid():
            self.projectProperties['Mobiles'].pop(
                self.mobileListModel.data(idx, Qt.DisplayRole))
            self.mobileListModel.removeRows(idx.row(), 1)
            idx = self.mMobileListView.currentIndex()
            if idx.isValid():
                self.populateMobileWidgets(idx)

    @pyqtSlot(name='on_toolButtonRefreshMobileProvider_clicked')
    def refreshMobileProvider(self):
        prov = self.comboBoxProviders.currentText()
        if prov == '':
            return
        fil = None
        if self.lineEditProviderFilter.text() != '':
            fil = self.lineEditProviderFilter.text()
        items = self.mobileProviderModel.findItems(prov, Qt.MatchExactly, 0)
        if items:
            for item in items:
                self.mobileProviderModel.setItem(item.row(), 1,
                                                 QStandardItem(fil))
        else:
            self.mobileProviderModel.appendRow(
                [QStandardItem(prov), QStandardItem(fil)])

    @pyqtSlot(name='on_toolButtonRemoveMobileProvider_clicked')
    def removeMobileProvider(self):
        idx = self.mMobileProviderTableView.currentIndex()
        if idx.isValid():
            self.mobileProviderModel.removeRow(idx.row())

    @pyqtSlot(name='on_pushButtonApplyDataProvider_clicked')
    def applyDataProvider(self):
        index = self.mDataProviderListView.currentIndex()
        if index.isValid() and not self.lineEditProviderName.text() == '':
            provider = dict()
            provider['Name'] = self.lineEditProviderName.text()
            provider['DataDeviceType'] = self.comboBoxProviderType.currentText(
            )
            if provider['DataDeviceType'] in NETWORK_TYPES:
                provider['Host'] = self.lineEditProviderHostName.text()
                provider['Port'] = self.spinBoxProviderPort.value()
            provider['Parser'] = self.comboBoxParser.currentText()
            currName = self.providerListModel.data(index, Qt.DisplayRole)
            if not currName == provider['Name']:
                del self.projectProperties['Provider'][currName]
                self.providerListModel.setData(index, provider['Name'],
                                               Qt.DisplayRole)
            self.projectProperties['Provider'][provider['Name']] = provider

    @pyqtSlot(QModelIndex, name='on_mDataProviderListView_clicked')
    def editDataProvider(self, index):
        '''
        '''
        if index.isValid():
            self.populateDataProviderWidgets(index)

    def populateDataProviderWidgets(self, index):
        provider = self.projectProperties['Provider'][
            self.providerListModel.data(index, Qt.DisplayRole)]
        self.lineEditProviderName.setText(provider.get('Name'))
        self.comboBoxProviderType.setCurrentIndex(
            self.comboBoxProviderType.findText(
                provider.setdefault('DataDeviceType', 'UDP').upper()))
        if provider['DataDeviceType'] in NETWORK_TYPES:
            self.stackedWidgetDataDevice.setCurrentIndex(0)
            self.lineEditProviderHostName.setText(
                provider.setdefault('Host', '0.0.0.0'))
            self.spinBoxProviderPort.setValue(
                int(provider.setdefault('Port', 2000)))

        self.comboBoxParser.setCurrentIndex(
            self.comboBoxParser.findText(
                provider.setdefault('Parser', 'NONE').upper()))

    @pyqtSlot(name='on_toolButtonAddDataProvider_clicked')
    def addDataProvider(self):
        self.providerListModel.insertRow(self.providerListModel.rowCount())
        index = self.providerListModel.index(
            self.providerListModel.rowCount() - 1)
        self.lineEditProviderName.setText('NewDataProvider')
        self.providerListModel.setData(index, 'NewDataProvider',
                                       Qt.DisplayRole)
        self.mDataProviderListView.setCurrentIndex(index)
        self.applyDataProvider()

    @pyqtSlot(name='on_toolButtonRemoveDataProvider_clicked')
    def removeDataProvider(self):
        idx = self.mDataProviderListView.currentIndex()
        if idx.isValid():
            self.projectProperties['Provider'].pop(
                self.providerListModel.data(idx, Qt.DisplayRole))
            self.providerListModel.removeRows(idx.row(), 1)
            idx = self.mDataProviderListView.currentIndex()
            if idx.isValid():
                self.populateDataProviderWidgets(idx)

    @pyqtSlot(name='on_toolButtonSelectLogPath_clicked')
    def selectRecorderPath(self):
        path = QFileDialog.getExistingDirectory(
            self, self.tr('Select Recorder Path'),
            self.lineEditRecorderPath.text(),
            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        if path != '':
            self.lineEditRecorderPath.setText(path)

    @pyqtSlot(QPoint, name='on_lineEditMobileShape_customContextMenuRequested')
    def mobileShapeContextMenu(self, pos):
        menu = QMenu(self.lineEditMobileShape)
        vesselAction = menu.addAction(self.tr('Vessel'))
        rovAction = menu.addAction(self.tr('ROV'))
        auvAction = menu.addAction(self.tr('AUV'))
        arrowAction = menu.addAction(self.tr('Arrow'))
        selectedAction = menu.exec_(self.lineEditMobileShape.mapToGlobal(pos))
        if selectedAction == vesselAction:
            self.lineEditMobileShape.setText(
                u'((0, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.3))'
            )
        elif selectedAction == rovAction:
            self.lineEditMobileShape.setText(
                u'((0.3, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.3), (-0.3, -0.5))'
            )
        elif selectedAction == auvAction:
            self.lineEditMobileShape.setText(
                u'((0, -0.5), (0.4, -0.3), (0.5, -0.3), (0.5, -0.2), (0.4, -0.2), (0.4, 0.3), (0.5, 0.3), (0.5, 0.4), (0.4, 0.4), (0.0, 0.5), \
             (-0.4, 0.4), (-0.5, 0.4), (-0.5, 0.3), (-0.4, 0.3), (-0.4, -0.2), (-0.5, -0.2), (-0.5, -0.3), (-0.4, -0.3))'
            )
        elif selectedAction == arrowAction:
            self.lineEditMobileShape.setText(
                u'((0, -0.5), (0.5, 0.5), (0, 0), (-0.5, 0.5))')

    @pyqtSlot(name='on_buttonBox_helpRequested')
    def showHelp(self):
        """Display application help to the user."""
        help_file = os.path.join(
            os.path.split(os.path.dirname(__file__))[0], 'help', 'index.html')
        QDesktopServices.openUrl(QUrl.fromLocalFile(help_file))
class ThinGreyscaleDialog(QDialog, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """Constructor."""
        self.iface = iface
        self.plugin_dir = dirname(__file__)
        self.THINGREYSCALE = self.tr('ThinGreyscale')
        self.BROWSE = self.tr('Browse')
        self.CANCEL = self.tr('Cancel')
        self.CLOSE = self.tr('Close')
        self.HELP = self.tr('Help')
        self.OK = self.tr('OK')
        self.DEFAULTPROVIDER = 'GTiff'
        self.DEFAULTEXTENSION = '.tif'
        self.EXTRAEXTENSION = ' *.tiff'
        super(ThinGreyscaleDialog, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)

        self.showInfo("Connecting UI components")
        okButton = self.button_box.button(QDialogButtonBox.Ok)
        okButton.setText(self.OK)
        cancelButton = self.button_box.button(QDialogButtonBox.Cancel)
        cancelButton.setText(self.CANCEL)
        cancelButton.setEnabled(False)
        closeButton = self.button_box.button(QDialogButtonBox.Close)
        closeButton.setText(self.CLOSE)
        browseButton = self.browseButton
        browseButton.setText(self.BROWSE)
        self.calcHistPushButton.setEnabled(False)
        self.listModel = QStandardItemModel(self.levelsListView)
        self.levelsListView.setModel(self.listModel)
        self.levelsListView.sizeHintForColumn(20)
        #self.levelValuesCheckBox.setEnabled(False)
        # Help button
        helpButton = self.helpButton
        helpButton.setText(self.HELP)

        # Connect signals
        self.showInfo("Connecting signals")
        okButton.clicked.connect(self.startWorker)
        cancelButton.clicked.connect(self.killWorker)
        closeButton.clicked.connect(self.reject)
        helpButton.clicked.connect(self.help)
        browseButton.clicked.connect(self.browse)

        inpIndexCh = self.inputRaster.currentIndexChanged['QString']
        inpIndexCh.connect(self.layerchanged)
        bandCh = self.bandComboBox.currentIndexChanged['QString']
        bandCh.connect(self.bandChanged)
        #self.iface.legendInterface().itemAdded.connect(
        #    self.layerlistchanged)
        #self.iface.legendInterface().itemRemoved.connect(
        #    self.layerlistchanged)
        #QObject.disconnect(self.button_box, SIGNAL("rejected()"), self.reject)
        self.button_box.rejected.disconnect(self.reject)
        calchistPr = self.calcHistPushButton.clicked
        calchistPr.connect(self.calculateHistogram)
        sugglevPr = self.suggestlevelsPushButton.clicked
        sugglevPr.connect(self.suggestLevels)
        addlevPr = self.addlevelPushButton.clicked
        addlevPr.connect(self.addLevel)
        dellevPr = self.deletelevelsPushButton.clicked
        dellevPr.connect(self.removeLevel)

        maxvalCh = self.maxValueSpinBox.valueChanged
        maxvalCh.connect(self.minmaxvalueChanged)
        maxvalFi = self.maxValueSpinBox.editingFinished
        maxvalFi.connect(self.minmaxvalueEdFinished)
        minvalCh = self.minValueSpinBox.valueChanged
        minvalCh.connect(self.minmaxvalueChanged)
        minvalFi = self.minValueSpinBox.editingFinished
        minvalFi.connect(self.minmaxvalueEdFinished)

        # Set instance variables
        #self.mem_layer = None
        self.worker = None
        self.inputlayerid = None
        self.inputlayer = None
        self.layerlistchanging = False
        self.minvalue = 1
        self.inputrasterprovider = None
        self.histobins = 50
        self.setupScene = QGraphicsScene(self)
        self.histoGraphicsView.setScene(self.setupScene)
        # Is the layer band of an integer type
        self.intband = False
        self.histogramAvailable = False
        self.histo = None
        self.histopadding = 1

    def startWorker(self):
        """Initialises and starts the worker thread."""
        try:
            layerindex = self.inputRaster.currentIndex()
            layerId = self.inputRaster.itemData(layerindex)
            inputlayer = QgsProject.instance().mapLayer(layerId)
            #inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
            if inputlayer is None:
                self.showError(self.tr('No input layer defined'))
                return
            # create a reference to the layer that is being processed
            # (for use when creating the resulting raster layer)
            self.thinninglayer = inputlayer
            self.levels = []
            #self.levelsListView.selectAll()
            #selected = self.levelsListView.selectedIndexes()
            if self.levelsListView.model().rowCount() == 0:
                self.showInfo("Levels must be specified!")
                return
            for i in range(self.levelsListView.model().rowCount()):
                levelstring = self.levelsListView.model().item(i).text()
                #for i in selected:
                #    levelstring = self.levelsListView.model().itemData(i)[0]
                if self.intband:
                    self.levels.append(int(levelstring))
                else:
                    self.levels.append(float(levelstring))
            #self.levelsListView.clearSelection()
            # create a new worker instance
            worker = Worker(inputlayer, self.levels, self.intband)
            # configure the QgsMessageBar
            msgBar = self.iface.messageBar().createMessage(
                self.tr('Skeletonising'), '')
            self.aprogressBar = QProgressBar()
            self.aprogressBar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            acancelButton = QPushButton()
            acancelButton.setText(self.CANCEL)
            acancelButton.clicked.connect(self.killWorker)
            msgBar.layout().addWidget(self.aprogressBar)
            msgBar.layout().addWidget(acancelButton)
            # Has to be popped after the thread has finished (in
            # workerFinished).
            self.iface.messageBar().pushWidget(msgBar, Qgis.Info)
            self.messageBar = msgBar
            # start the worker in a new thread
            thread = QThread(self)
            worker.moveToThread(thread)
            worker.finished.connect(self.workerFinished)
            worker.error.connect(self.workerError)
            worker.status.connect(self.workerInfo)
            worker.progress.connect(self.progressBar.setValue)
            worker.progress.connect(self.aprogressBar.setValue)
            worker.iterprogress.connect(self.iterProgressBar.setValue)
            thread.started.connect(worker.run)
            thread.start()
            self.thread = thread
            self.worker = worker
            self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
            self.button_box.button(QDialogButtonBox.Close).setEnabled(False)
            self.button_box.button(QDialogButtonBox.Cancel).setEnabled(True)
        except:
            import traceback
            self.showError(traceback.format_exc())
        else:
            pass

    def workerFinished(self, ok, ret):
        """Handles the output from the worker and cleans up after the
           worker has finished."""
        # clean up the worker and thread
        self.showInfo("Handling the result")
        self.worker.deleteLater()
        self.thread.quit()
        self.thread.wait()
        self.thread.deleteLater()
        # remove widget from message bar (pop)
        self.iface.messageBar().popWidget(self.messageBar)
        if ok and ret is not None:
            #self.showInfo("Ret: "+str(ret[10,]))
            # Transformation:
            self.minx = self.thinninglayer.extent().xMinimum()
            self.maxx = self.thinninglayer.extent().xMaximum()
            self.miny = self.thinninglayer.extent().yMinimum()
            self.maxy = self.thinninglayer.extent().yMaximum()
            self.rows = self.thinninglayer.height()
            self.cols = self.thinninglayer.width()
            self.xres = (self.maxx - self.minx) / float(self.cols)
            self.yres = (self.maxy - self.miny) / float(self.rows)
            geotransform = (self.minx, self.xres, 0, self.maxy, 0, -self.yres)
            try:
                format = self.DEFAULTPROVIDER
                driver = gdal.GetDriverByName(format)
                NOVALUE = 0
                metadata = driver.GetMetadata()
                fileName = self.outputRaster.text()
                if self.outputRaster.text() == "":
                    self.showInfo("No output file specified, " +
                                  "creating a temporary file")
                    # Get a temporary file
                    fileName = mktemp(prefix='greyskel',
                                      suffix=self.DEFAULTEXTENSION)
                fileInfo = QFileInfo(fileName)
                filepath = fileInfo.absolutePath()
                baseName = fileInfo.baseName()
                suffix = fileInfo.suffix()
                thisfilename = filepath + baseName + '.' + suffix
                thisfilename = fileName
                self.showInfo("File name: " + thisfilename)
                gdaldatatype = gdal.GDT_Byte
                skelmatrix = None
                if self.levelValuesCheckBox.isChecked():
                    # Transform the pixel values back to the original
                    # level values
                    my_dict = {}
                    # Add zero to handle the "empty" pixels
                    my_dict[0] = 0
                    for i in range(len(self.levels)):
                        my_dict[i + 1] = self.levels[i]
                    skelmatrix = np.vectorize(my_dict.__getitem__,
                                              otypes=[np.float])(ret)
                    gdaldatatype = gdal.GDT_Int32
                    if not self.intband:
                        gdaldatatype = gdal.GDT_Float32
                else:
                    skelmatrix = ret
                outDataset = driver.Create(thisfilename, self.cols, self.rows,
                                           1, gdaldatatype)
                if self.thinninglayer.dataProvider().crs() is not None:
                    srs = self.thinninglayer.dataProvider().crs()
                    outDataset.SetProjection(srs.toWkt().encode(
                        'ascii', 'ignore'))
                skeletonband = outDataset.GetRasterBand(1)
                skeletonband.WriteArray(skelmatrix)
                skeletonband.SetNoDataValue(NOVALUE)
                #stats = skeletonband.GetStatistics(False, True)
                #skeletonband.SetStatistics(stats[0], stats[1],
                #                                 stats[2], stats[3])
                outDataset.SetGeoTransform(geotransform)
                outDataset = None  # To close the file
                # report the result
                rlayer = QgsRasterLayer(thisfilename, baseName)
                self.layerlistchanging = True
                #QgsMapLayerRegistry.instance().addMapLayer(rlayer)
                QgsProject.instance().addMapLayer(rlayer)
                self.layerlistchanging = False
            except:
                import traceback
                self.showError("Can't write the skeleton file:  %s" %
                               self.outputRaster.text() + ' - ' +
                               traceback.format_exc())
                okb = self.button_box.button(QDialogButtonBox.Ok)
                okb.setEnabled(True)
                closb = self.button_box.button(QDialogButtonBox.Close)
                closb.setEnabled(True)
                cancb = self.button_box.button(QDialogButtonBox.Cancel)
                cancb.setEnabled(False)
                return
            QgsMessageLog.logMessage(self.tr('ThinGreyscale finished'),
                                     self.THINGREYSCALE, Qgis.Info)
        else:
            # notify the user that something went wrong
            if not ok:
                self.showError(self.tr('Aborted') + '!')
            else:
                self.showError(self.tr('No skeleton created') + '!')
        self.progressBar.setValue(0.0)
        #self.aprogressBar.setValue(0.0)
        self.iterProgressBar.setValue(0.0)
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
        self.button_box.button(QDialogButtonBox.Close).setEnabled(True)
        self.button_box.button(QDialogButtonBox.Cancel).setEnabled(False)

    def workerError(self, exception_string):
        """Report an error from the worker."""
        #QgsMessageLog.logMessage(self.tr('Worker failed - exception') +
        #                         ': ' + str(exception_string),
        #                         self.THINGREYSCALE,
        #                         QgsMessageLog.CRITICAL)
        self.showError(exception_string)

    def workerInfo(self, message_string):
        """Report an info message from the worker."""
        QgsMessageLog.logMessage(
            self.tr('Worker') + ': ' + message_string, self.THINGREYSCALE,
            Qgis.Info)

    def layerchanged(self, number=0):
        """Do the necessary updates after a layer selection has
           been changed."""
        self.showInfo("Layer changed")
        # If the layer list is being updated, don't do anything
        if self.layerlistchanging:
            return
        layerindex = self.inputRaster.currentIndex()
        layerId = self.inputRaster.itemData(layerindex)
        self.inputlayerid = layerId
        #self.inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
        self.inputlayer = QgsProject.instance().mapLayer(layerId)
        if self.inputlayer is not None:
            self.inputrasterprovider = self.inputlayer.dataProvider()
            self.bandComboBox.clear()
            bandcount = self.inputlayer.bandCount()
            #self.showInfo("Layer bandcount: "+str(bandcount))
            for i in range(bandcount):
                self.bandComboBox.addItem(self.inputlayer.bandName(i + 1), i)
                #self.showInfo("Band " + str(i) + ": " +
                #                self.inputlayer.bandName(i+1))
            # Check if the driver supports Create() or CreateCopy()
            #gdalmetadata = self.inputlayer.metadata()
            #self.showInfo("Layer metadata: " +
            #                str(gdalmetadata.encode('utf-8')))
            #provstring = '<p>GDAL provider</p>\n'
            #providerpos = gdalmetadata.find(provstring)
            #brpos = gdalmetadata.find('<br>', providerpos + len(provstring))
            #self.gdalprovider = gdalmetadata[int(providerpos +
            #                             len(provstring)):int(brpos)]
            #self.showInfo('GDAL provider: '+self.gdalprovider)
            #drivername = self.gdalprovider.encode('ascii', 'ignore')
            #theDriver = gdal.GetDriverByName(drivername)
            #if theDriver is None:
            #    self.showInfo("Unable to get the raster driver")
            #else:
            #data    theMetadata = theDriver.GetMetadata()
            #self.showInfo("Driver metadata: "+str(theMetadata))
            #if ((gdal.DCAP_CREATE in theMetadata) and
            #        theMetadata[gdal.DCAP_CREATE] == 'YES'):
            #    self.canCreate = True
            #if (theMetadata.has_key(gdal.DCAP_CREATECOPY) and
            #if ((gdal.DCAP_CREATECOPY in theMetadata) and
            #        theMetadata[gdal.DCAP_CREATECOPY] == 'YES'):
            #    self.canCreateCopy = True
            #self.showInfo('raster provider type: ' +
            #                str(self.inputlayer.providerType()))
            # Determine the file suffix
            #self.gdalext = ""
            #if gdal.DMD_EXTENSION in theMetadata:
            #    self.gdalext = "." + theMetadata[gdal.DMD_EXTENSION]
            #else:
            #    self.showInfo("No extension available in GDAL metadata")
            # by parsing the layer metadata looking for
            #           "Dataset Description"
            #descstring = 'Dataset Description</p>\n<p>'
            #descpos = gdalmetadata.find(descstring)
            #ppos = gdalmetadata.find('</p>',descpos+len(descstring))
            #filename = gdalmetadata[descpos+len(descstring):ppos]
            #self.gdalext = splitext(filename)[1]
            #self.showInfo('GDAL extension: '+self.gdalext)
            # Determine the datatype
            #datatypestring = 'Data Type</p>\n<p>'
            #datatypepos = gdalmetadata.find(datatypestring)
            #ppos = gdalmetadata.find('</p>',
            #                   datatypepos + len(datatypestring))
            #datatypedesc = gdalmetadata[datatypepos +
            #                            len(datatypestring):ppos]
            #shortdesc = datatypedesc.split()[0]
            #self.showInfo('GDAL data type: GDT_'+shortdesc)
            # Call the findGdalDatatype function
            #self.findGdalDatatype(shortdesc)
            #   self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
            self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
            self.calcHistPushButton.setEnabled(True)
            self.suggestlevelsPushButton.setEnabled(True)

    def bandChanged(self):
        band = self.bandComboBox.currentIndex() + 1
        self.showInfo("Band changed: " + str(band))
        statistics = self.inputrasterprovider.bandStatistics(band)
        #self.showInfo("Band statistics: " + str(statistics.minimumValue) +
        #                            " - " + str(statistics.maximumValue) +
        #                            " - " + str(statistics.mean))
        self.bandmin = statistics.minimumValue
        self.bandmax = statistics.maximumValue
        dt = self.inputrasterprovider.dataType(band)
        # Integer data type
        if (dt == Qgis.Byte or dt == Qgis.UInt16 or dt == Qgis.Int16
                or dt == Qgis.UInt32 or dt == Qgis.Int32):
            self.intband = True
            self.minValueSpinBox.setDecimals(0)
            self.maxValueSpinBox.setDecimals(0)
            self.levelSpinBox.setDecimals(0)
            self.bandMinLabel.setText(str(int(statistics.minimumValue)))
            self.bandMaxLabel.setText(str(int(statistics.maximumValue)))
        else:
            self.intband = False
            self.minValueSpinBox.setDecimals(5)
            self.maxValueSpinBox.setDecimals(5)
            self.levelSpinBox.setDecimals(5)
            minlabtext = "{0:.5f}".format(statistics.minimumValue)
            self.bandMinLabel.setText(minlabtext)
            maxlabtext = "{0:.5f}".format(statistics.maximumValue)
            self.bandMaxLabel.setText(maxlabtext)
        #self.minValueSpinBox.setMinimum(statistics.minimumValue)
        self.maxValueSpinBox.setMinimum(statistics.minimumValue)
        #self.minValueSpinBox.setMaximum(statistics.maximumValue)
        self.maxValueSpinBox.setMaximum(statistics.maximumValue)
        #self.minValueSpinBox.setValue(statistics.minimumValue)
        if not (statistics.statsGathered & statistics.Mean):
            bandmean = (statistics.minimumValue + statistics.maximumValue) / 2
        else:
            #self.showInfo("statsgathered: " + str(statistics.statsGathered))
            bandmean = statistics.mean
        if self.intband:
            self.minValueSpinBox.setValue(int(ceil(bandmean)))
        else:
            self.minValueSpinBox.setValue(bandmean)
        self.maxValueSpinBox.setValue(statistics.maximumValue)
        self.histMinValue.setText(str(statistics.minimumValue))
        self.histMaxValue.setText(str(statistics.maximumValue))
        self.levelSpinBox.setMinimum(statistics.minimumValue)
        self.levelSpinBox.setMaximum(statistics.maximumValue)
        self.histogramAvailable = False
        #if self.inputrasterprovider.hasStatistics(band):
        #if statistics.statsGathered:
        #histogram = statistics.histogramVector
        #self.showInfo("Histogram: " + str(histogram))
        #range = min to max
        #np.histogram(band, 50, range)

    def minmaxvalueChanged(self):
        #if self.minValueSpinBox is None:
        #    return
        minvalue = self.minValueSpinBox.value()
        #if minvalue is None:
        #    return
        #if self.maxValueSpinBox is None:
        #    return
        maxvalue = self.maxValueSpinBox.value()
        #if maxvalue is None:
        #   return
        if isnan(maxvalue) or isnan(minvalue):
            return
        self.showInfo("minvalue: " + str(minvalue) + " Maxvalue: " +
                      str(maxvalue))
        #if self.intband:
        #    minvalue = int(minvalue)
        #    maxvalue = int(maxvalue)
        if abs(maxvalue - minvalue) < 0.00001:
            #if maxvalue == maxvalue:
            self.calcHistPushButton.setEnabled(False)
        else:
            self.calcHistPushButton.setEnabled(True)
        # Update the min and max value spinboxes
        self.minValueSpinBox.setMaximum(maxvalue)
        self.maxValueSpinBox.setMinimum(minvalue)
        self.minValueSpinBox.setMinimum(self.bandmin)

    def minmaxvalueEdFinished(self):
        minvalue = self.minValueSpinBox.value()
        maxvalue = self.maxValueSpinBox.value()
        if self.intband:
            minvalue = int(minvalue)
            maxvalue = int(maxvalue)
        self.showInfo("minvalue: " + str(minvalue) + " Maxvalue: " +
                      str(maxvalue))
        # Update the spin box for adding levels
        self.levelSpinBox.setMinimum(minvalue)
        self.levelSpinBox.setMaximum(maxvalue)
        if self.levelSpinBox.value() < minvalue:
            self.levelSpinBox.setValue(minvalue)
        if self.levelSpinBox.value() > maxvalue:
            self.levelSpinBox.setValue(maxvalue)
        # Update the min and max value spinboxes
        self.minValueSpinBox.setMaximum(maxvalue)
        self.maxValueSpinBox.setMinimum(minvalue)

        # Adjust the levels:
        i = 0
        while self.levelsListView.model().item(i):
            #for i in range(self.levelsListView.model().rowCount()):
            #self.showInfo("Element: " +
            #       str(self.levelsListView.model().item(i).text()))
            #continue
            value = float(self.levelsListView.model().item(i).text())
            if value < minvalue:
                if i == 0:
                    self.levelsListView.model().item(i).setText(str(minvalue))
                    i = i + 1
                else:
                    self.levelsListView.model().removeRow(i)
            elif value > maxvalue:
                if i == self.levelsListView.model().rowCount() - 1:
                    self.levelsListView.model().item(i).setText(str(maxvalue))
                    i = i + 1
                else:
                    self.levelsListView.model().removeRow(i)
            else:
                i = i + 1
        self.drawHistogram()

    def calculateHistogram(self):
        self.showInfo("Calculating histogram...")
        if self.inputlayer is None:
            return

        self.showInfo("Calculating histogram...")
        # Check if there is only one value
        myrange = (self.minValueSpinBox.value(), self.maxValueSpinBox.value())
        self.inputextent = self.inputlayer.extent()
        self.inputrdp = self.inputlayer.dataProvider()
        width = self.inputlayer.width()
        height = self.inputlayer.height()
        if width == 0 or height == 0:
            self.showInfo("Image has zero width or height")
            return
        extwidth = self.inputextent.width()
        extheight = self.inputextent.height()
        # Read the raster block and get the maximum value
        rasterblock = self.inputrdp.block(1, self.inputextent, width, height)
        # Create a numpy array version of the image
        imageMat = np.zeros((height, width), dtype=np.float16)
        # This one takes a lot of time!
        for row in range(height):
            for column in range(width):
                imageMat[row, column] = rasterblock.value(row, column)
                self.showInfo("Image: " + str(height) + ", " + str(width) +
                              " - " + str(imageMat[row, column]))
        self.histo = np.histogram(imageMat, self.histobins, myrange)
        #relevantpixels = imageMat[np.where(imageMat >= bandval)]
        minlevel = float(self.bandMinLabel.text())
        relevantpixels = imageMat[np.where(imageMat >= minlevel)]
        #self.showInfo("Histogram: " + str(self.histo))
        nanpercentage = 100.0 - 100.0 * len(relevantpixels) / (width * height)
        self.bandNANLabel.setText("{0:.1f}".format(nanpercentage))
        #self.showInfo("Percentage NAN: " + str(100.0 - 100.0 *
        #                    len(relevantpixels) / (width * height)))
        #self.showInfo("First element: " + str(self.histo[0]))
        #self.showInfo("First element, first: " + str(self.histo[0][0]))
        #self.showInfo("First element, second: " + str(self.histo[0][1]))
        self.histMinValue.setText(str(self.minValueSpinBox.value()))
        self.histMaxValue.setText(str(self.maxValueSpinBox.value()))
        if self.intband:
            self.histMinValue.setText(str(int(self.minValueSpinBox.value())))
            self.histMaxValue.setText(str(int(self.maxValueSpinBox.value())))
        self.histogramAvailable = True
        self.drawHistogram()

    def drawHistogram(self):
        #if self.inputlayer is None:
        #    return
        self.showInfo("Drawing histogram...")
        viewprect = QRectF(self.histoGraphicsView.viewport().rect())
        self.histoGraphicsView.setSceneRect(viewprect)
        self.setupScene.clear()
        self.setupScene.update()
        histbottom = self.histoGraphicsView.sceneRect().bottom()
        histtop = self.histoGraphicsView.sceneRect().top()
        left = self.histoGraphicsView.sceneRect().left() + self.histopadding
        right = self.histoGraphicsView.sceneRect().right() - self.histopadding
        histheight = histbottom - histtop
        histwidth = right - left
        step = 1.0 * histwidth / self.histobins
        maxlength = histheight
        padding = 1
        ll = QPoint(self.histopadding - 1, histheight - padding)
        start = QPointF(self.histoGraphicsView.mapToScene(ll))

        # Check if there is only one value
        #myrange = (self.minValueSpinBox.value(),self.maxValueSpinBox.value())
        if self.histogramAvailable:
            maxvalue = 0.0
            for i in range(len(self.histo[0])):
                if self.histo[0][i] > maxvalue:
                    maxvalue = self.histo[0][i]
            if maxvalue == 0:
                return
            self.maxBinNumber.setText(str(maxvalue))
            # Create the histogram:
            #self.showInfo("maxvalue: " + str(maxvalue))
            #self.showInfo("maxlength: " + str(maxlength))
            #self.showInfo("step: " + str(step))
            for i in range(self.histobins):
                binnumber = self.histo[0][i]
                if binnumber == 0:
                    continue
                height = (1.0 * self.histo[0][i] / maxvalue *
                          (maxlength - padding))
                rectangle = QGraphicsRectItem(start.x() + step * i, start.y(),
                                              step, -height)
                rectangle.setPen(QPen(QColor(102, 102, 102)))
                rectangle.setBrush(QBrush(QColor(240, 240, 240)))
                self.setupScene.addItem(rectangle)
                #self.showInfo(str(i) + ": " + str(height))
            #if self.levelsListView.model().rowCount() > 0:
        # Add lines for the levels
        minvalue = float(self.histMinValue.text())
        maxvalue = float(self.histMaxValue.text())
        datarange = maxvalue - minvalue
        if datarange == 0:
            return
        i = 0
        while self.levelsListView.model().item(i):
            #self.showInfo("Element: " +
            #       str(self.levelsListView.model().item(i).text()))
            #continue
            value = float(self.levelsListView.model().item(i).text())
            xvalue = start.x() + histwidth * (value - minvalue) / datarange
            line = QGraphicsLineItem(xvalue, 0, xvalue, histheight)
            if i == 0 or i == (self.levelsListView.model().rowCount() - 1):
                line.setPen(QPen(QColor(204, 0, 0)))
            else:
                line.setPen(QPen(QColor(0, 204, 0)))
            self.setupScene.addItem(line)
            i = i + 1

    def suggestLevels(self):
        self.listModel.clear()
        self.showInfo("Suggesting levels")
        levels = self.levelsSpinBox.value()
        startvalue = self.minValueSpinBox.value()
        endvalue = self.maxValueSpinBox.value()
        increment = (endvalue - startvalue) / levels
        for i in range(levels + 1):
            value = startvalue + increment * i
            if self.intband:
                value = int(value)
            item = QStandardItem(str(value))
            self.listModel.appendRow(item)
        self.drawHistogram()

    def addLevel(self):
        newvalue = self.levelSpinBox.value()
        if self.intband:
            newvalue = int(newvalue)
        for i in range(self.listModel.rowCount()):
            # Check if the value is already in the list
            if self.listModel.item(i).text() == str(newvalue):
                return
            else:
                # Maintain a sorted list of distances
                if (float(self.listModel.item(i).text()) > float(
                        str(newvalue))):
                    item = QStandardItem(str(newvalue))
                    self.listModel.insertRow(i, item)
                    self.drawHistogram()
                    return
        item = QStandardItem(str(newvalue))
        self.listModel.appendRow(item)
        #if self.histogramAvailable:
        #    addLevelsToHistogram()
        self.drawHistogram()

    def removeLevel(self):
        self.levelsListView.setUpdatesEnabled(False)
        indexes = self.levelsListView.selectedIndexes()
        indexes.sort()
        for i in range(len(indexes) - 1, -1, -1):
            self.listModel.removeRow(indexes[i].row())
        self.levelsListView.setUpdatesEnabled(True)
        #if self.histogramAvailable:
        #    removeLevelFromHistogram()
        self.drawHistogram()

    def layerlistchanged(self):
        self.layerlistchanging = True
        self.showInfo("Layer list changed")
        # Repopulate the input layer combo box
        # Save the currently selected input layer
        inputlayerid = self.inputlayerid
        self.inputRaster.clear()
        for alayer in self.iface.legendInterface().layers():
            if alayer.type() == QgsMapLayer.RasterLayer:
                gdalmetadata = alayer.metadata()
                # Skip WMS layers
                WMSstring = 'Web Map Service'
                wmspos = gdalmetadata.find(WMSstring)
                if wmspos != -1:
                    continue
                self.inputRaster.addItem(alayer.name(), alayer.id())
        # Set the previous selection
        for i in range(self.inputRaster.count()):
            if self.inputRaster.itemData(i) == inputlayerid:
                self.inputRaster.setCurrentIndex(i)
        self.layerlistchanging = False
        #self.updateui()

    def updateui(self):
        """Do the necessary updates after a layer selection has
           been changed."""
        #if self.layerlistchanged:
        #    return
        #self.outputRaster.setText(self.inputRaster.currentText() +
        #                           '_' + 'thinned')
        layerindex = self.inputRaster.currentIndex()
        layerId = self.inputRaster.itemData(layerindex)
        #inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
        inputlayer = QgsProject.instance().mapLayer(layerId)
        if inputlayer is not None:
            pass
        else:
            pass

    def findGdalDatatype(self, shortdesc):
        gdaldatatype = None
        # // Unknown or unspecified type
        # GDT_Unknown = GDALDataType(C.GDT_Unknown)
        if shortdesc == 'Unknown':
            gdaldatatype = gdal.GDT_Unknown
        # // Eight bit unsigned integer
        # GDT_Byte = GDALDataType(C.GDT_Byte)
        elif shortdesc == 'Byte':
            gdaldatatype = gdal.GDT_Byte
        # // Sixteen bit unsigned integer
        # GDT_UInt16 = GDALDataType(C.GDT_UInt16)
        elif shortdesc == 'UInt16':
            gdaldatatype = gdal.GDT_UInt16
        # // Sixteen bit signed integer
        # GDT_Int16 = GDALDataType(C.GDT_Int16)
        elif shortdesc == 'Int16':
            gdaldatatype = gdal.GDT_Int16
        # // Thirty two bit unsigned integer
        # GDT_UInt32 = GDALDataType(C.GDT_UInt32)
        elif shortdesc == 'UInt32':
            gdaldatatype = gdal.GDT_UInt32
        # // Thirty two bit signed integer
        # GDT_Int32 = GDALDataType(C.GDT_Int32)
        elif shortdesc == 'Int32':
            gdaldatatype = gdal.GDT_Int32
        # // Thirty two bit floating point
        # GDT_Float32 = GDALDataType(C.GDT_Float32)
        elif shortdesc == 'Float32':
            gdaldatatype = gdal.GDT_Float32
        # // Sixty four bit floating point
        # GDT_Float64 = GDALDataType(C.GDT_Float64)
        elif shortdesc == 'Float64':
            gdaldatatype = gdal.GDT_Float64
        # // Complex Int16
        # GDT_CInt16 = GDALDataType(C.GDT_CInt16)
        elif shortdesc == 'CInt16':
            gdaldatatype = gdal.CInt16
        # // Complex Int32
        # GDT_CInt32 = GDALDataType(C.GDT_CInt32)
        elif shortdesc == 'CInt32':
            gdaldatatype = gdal.CInt32
        # // Complex Float32
        # GDT_CFloat32 = GDALDataType(C.GDT_CFloat32)
        elif shortdesc == 'CFloat32':
            gdaldatatype = gdal.CFloat32
        # // Complex Float64
        # GDT_CFloat64 = GDALDataType(C.GDT_CFloat64)
        elif shortdesc == 'CFloat64':
            gdaldatatype = gdal.CFloat64
        # // maximum type # + 1
        # GDT_TypeCount = GDALDataType(C.GDT_TypeCount)
        elif shortdesc == 'TypeCount':
            gdaldatatype = gdal.TypeCount
        self.gdaldatatype = gdaldatatype

    def killWorker(self):
        """Kill the worker thread."""
        if self.worker is not None:
            QgsMessageLog.logMessage(self.tr('Killing worker'),
                                     self.THINGREYSCALE, Qgis.Info)
            self.worker.kill()

    def showError(self, text):
        """Show an error."""
        self.iface.messageBar().pushMessage(self.tr('Error'),
                                            text,
                                            level=QgsMessageBar.CRITICAL,
                                            duration=3)
        QgsMessageLog.logMessage('Error: ' + text, self.THINGREYSCALE,
                                 QgsMessageLog.CRITICAL)

    def showWarning(self, text):
        """Show a warning."""
        self.iface.messageBar().pushMessage(self.tr('Warning'),
                                            text,
                                            level=QgsMessageBar.WARNING,
                                            duration=2)
        QgsMessageLog.logMessage('Warning: ' + text, self.THINGREYSCALE,
                                 QgsMessageLog.WARNING)

    def showInfo(self, text):
        """Show info."""
        self.iface.messageBar().pushMessage(self.tr('Info'),
                                            text,
                                            level=Qgis.Info,
                                            duration=2)
        QgsMessageLog.logMessage('Info: ' + text, self.THINGREYSCALE,
                                 Qgis.Info)

    # def help(self):
    # #QDesktopServices.openUrl(QUrl.fromLocalFile(self.plugin_dir +
    #                                 "/help/build/html/index.html"))
    # QDesktopServices.openUrl(QUrl.fromLocalFile(self.plugin_dir +
    #                                            "/help/index.html"))
    # #showPluginHelp()

    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        return QCoreApplication.translate('ThinGreyScaleDialog', message)

    def browse(self):
        settings = QSettings()
        key = '/UI/lastShapefileDir'
        outDir = settings.value(key)
        home = outDir
        #outDir = expanduser("~")
        #filter = (self.DEFAULTPROVIDER + " (*" +
        #             self.DEFAULTEXTENSION + ");;All files (*)")
        filter = (self.DEFAULTPROVIDER + " (*" + self.DEFAULTEXTENSION +
                  self.EXTRAEXTENSION + ")")
        #if (self.gdalprovider != self.DEFAULTPROVIDER and
        #                                     (self.canCreateCopy or
        #                                           self.canCreate)):
        #    filter = (self.gdalprovider + " (*" + self.gdalext +
        #                                          ");;" + filter)
        outFilePath = QFileDialog.getSaveFileName(
            self, 'Specify file name for skeleton', outDir, filter)
        outFilePath = unicode(outFilePath)
        if outFilePath:
            root, ext = splitext(outFilePath)
            if ext.lower() != '.tif' and ext.lower() != '.tiff':
                outFilePath = '%s.tif' % outFilePath
            outDir = dirname(outFilePath)
            settings.setValue(key, outDir)
        #        (self.canCreateCopy or self.canCreate):
        #    fileName = splitext(str(fileName))[0]+self.gdalext
        self.outputRaster.setText(outFilePath)

    # Overriding
    def resizeEvent(self, event):
        #self.showInfo("resizeEvent")
        self.calculateHistogram()

    def help(self):
        #QDesktopServices.openUrl(QUrl.fromLocalFile(
        #                 self.plugin_dir + "/help/html/index.html"))
        showPluginHelp(None, "help/html/index")

    # Implement the accept method to avoid exiting the dialog when
    # starting the work
    def accept(self):
        """Accept override."""
        pass

    # Implement the reject method to have the possibility to avoid
    # exiting the dialog when cancelling
    def reject(self):
        """Reject override."""
        # exit the dialog
        QDialog.reject(self)
Пример #6
0
class TemplateDocumentSelector(WIDGET, BASE):
    """
    Dialog for selecting a document template from the saved list.
    """
    def __init__(self,
                 parent=None,
                 selectMode=True,
                 filter_data_source='',
                 access_templates=None):
        QDialog.__init__(self, parent)
        self.setupUi(self)

        self.notifBar = NotificationBar(self.vlNotification)

        self._mode = selectMode

        # Filter templates by the specified table name
        self._filter_data_source = filter_data_source

        # Document templates in current profile
        self._profile_templates = []

        self._current_profile = current_profile()

        # Load current profile templates
        self._load_current_profile_templates()

        self.access_templates = access_templates or []

        if selectMode:
            self.buttonBox.setVisible(True)
            self.manageButtonBox.setVisible(False)
            currHeight = self.size().height()
            self.resize(200, currHeight)

        else:
            self.buttonBox.setVisible(False)
            self.manageButtonBox.setVisible(True)
            self.setWindowTitle(
                QApplication.translate("TemplateDocumentSelector",
                                       "Template Manager"))

        # Configure manage buttons
        btnEdit = self.manageButtonBox.button(QDialogButtonBox.Ok)
        btnEdit.setText(
            QApplication.translate("TemplateDocumentSelector", "Edit..."))
        btnEdit.setIcon(GuiUtils.get_icon("edit.png"))

        btnDelete = self.manageButtonBox.button(QDialogButtonBox.Save)
        btnDelete.setText(
            QApplication.translate("TemplateDocumentSelector", "Delete"))
        btnDelete.setIcon(GuiUtils.get_icon("delete.png"))

        # Connect signals
        self.buttonBox.accepted.connect(self.onAccept)
        btnEdit.clicked.connect(self.onEditTemplate)
        btnDelete.clicked.connect(self.onDeleteTemplate)

        # Get saved document templates then add to the model
        templates = documentTemplates()

        self._docItemModel = QStandardItemModel(parent)
        self._docItemModel.setColumnCount(2)

        # Append current profile templates to the model.
        for dt in self._profile_templates:

            if self._template_contains_filter_table(
                    dt):  # and dt.name in self.access_templates:
                doc_name_item = self._createDocNameItem(dt.name)
                file_path_item = QStandardItem(dt.path)
                self._docItemModel.appendRow([doc_name_item, file_path_item])

        self.lstDocs.setModel(self._docItemModel)

    def _load_current_profile_templates(self):
        # Loads only those templates that refer to tables in the current
        # profile.
        if self._current_profile is None:
            return

        # Get saved document templates then add to the model
        templates = documentTemplates()

        profile_tables = self._current_profile.table_names()

        # Get templates for the current profile
        for name, path in templates.items():
            doc_temp = DocumentTemplate.build_from_path(name, path)
            if doc_temp.data_source is None:
                continue

            # Assert data source is in the current profile
            if doc_temp.data_source.referenced_table_name in profile_tables or \
                    doc_temp.data_source.name() in user_non_profile_views():
                self._add_doc_temp(doc_temp)
                # self._profile_templates.append(doc_temp)

    def _add_doc_temp(self, doc_temp):
        found = False
        for template in self._profile_templates:
            if template.name == doc_temp.name:
                found = True
                break
        if not found:
            self._profile_templates.append(doc_temp)

    def _template_contains_filter_table(self, document_template):
        # Returns true if the template refers to the filter data source

        # If no filter data source defined then always return True

        if document_template.data_source._dataSourceName in user_non_profile_views(
        ):
            return True

        if not self._filter_data_source:
            return True

        referenced_table = document_template.referenced_table_name

        if referenced_table == self._filter_data_source:
            return True

        return False

    @property
    def mode(self):
        return self._mode

    @property
    def filter_data_source(self):
        return self._filter_data_source

    def _createDocNameItem(self, docName):
        """
        Create a template document standard item.
        """
        # Set icon
        icon = QIcon()
        icon.addPixmap(GuiUtils.get_icon_pixmap("document.png"), QIcon.Normal,
                       QIcon.Off)

        dnItem = QStandardItem(icon, docName)

        return dnItem

    def onEditTemplate(self):
        """
        Slot raised to edit document template.
        """
        self.notifBar.clear()

        if self.documentMapping() is None:
            self.notifBar.insertErrorNotification(QApplication.translate("TemplateDocumentSelector", \
                                                                         "Please select a document template to edit"))
            return

        templateName, filePath = self.documentMapping()

        docName, ok = QInputDialog.getText(self, \
                                           QApplication.translate("TemplateDocumentSelector", "Edit Template"), \
                                           QApplication.translate("TemplateDocumentSelector",
                                                                  "Please enter the new template name below"), \
                                           text=templateName)
        if ok and docName == "":
            self.notifBar.insertErrorNotification(QApplication.translate("TemplateDocumentSelector", \
                                                                         "Template name cannot be empty"))
            return

        elif docName == templateName:
            return

        elif ok and docName != "":
            result, newTemplatePath = self._editTemplate(filePath, docName)

            if result:
                # Update view
                mIndices = self._selectedMappings()

                docNameItem = self._docItemModel.itemFromIndex(mIndices[0])
                filePathItem = self._docItemModel.itemFromIndex(mIndices[1])

                docNameItem.setText(docName)
                filePathItem.setText(newTemplatePath)

                self.notifBar.insertSuccessNotification(QApplication.translate("TemplateDocumentSelector", \
                                                                               "'{0}' template has been successfully updated".format(
                                                                                   docName)))

            else:
                self.notifBar.insertErrorNotification(QApplication.translate("TemplateDocumentSelector", \
                                                                             "Error: '{0}' template could not be updated".format(
                                                                                 templateName)))

    def onDeleteTemplate(self):
        """
        Slot raised to delete document template.
        """
        self.notifBar.clear()

        if self.documentMapping() == None:
            self.notifBar.insertErrorNotification(QApplication.translate("TemplateDocumentSelector", \
                                                                         "Please select a document template to delete"))
            return

        templateName, filePath = self.documentMapping()

        result = QMessageBox.warning(self, QApplication.translate("TemplateDocumentSelector", \
                                                                  "Confirm delete"),
                                     QApplication.translate("TemplateDocumentSelector", \
                                                            "Are you sure you want to delete '{0}' template?" \
                                                            "This action cannot be undone.\nClick Yes to proceed " \
                                                            "or No to cancel.".format(templateName)),
                                     QMessageBox.Yes | QMessageBox.No)

        if result == QMessageBox.No:
            return

        status = self._deleteDocument(filePath)

        if status:
            # Remove item from list using model index row number
            selectedDocNameIndices = self.lstDocs.selectionModel(
            ).selectedRows(0)
            row = selectedDocNameIndices[0].row()
            self._docItemModel.removeRow(row)
            self.notifBar.insertSuccessNotification(QApplication.translate("TemplateDocumentSelector", \
                                                                           "'{0}' template has been successfully removed".format(
                                                                               templateName)))

        else:
            self.notifBar.insertErrorNotification(QApplication.translate("TemplateDocumentSelector", \
                                                                         "Error: '{0}' template could not be removed".format(
                                                                             templateName)))

    def onAccept(self):
        """
        Slot raised to close the dialog only when a selection has been made by the user.
        """
        self.notifBar.clear()

        if self.documentMapping() == None:
            self.notifBar.insertErrorNotification(QApplication.translate("TemplateDocumentSelector", \
                                                                         "Please select a document"))
            return

        self.accept()

    def _selectedMappings(self):
        """
        Returns the model indices for the selected row.
        """
        selectedDocNameIndices = self.lstDocs.selectionModel().selectedRows(0)
        selectedFilePathIndices = self.lstDocs.selectionModel().selectedRows(1)

        if len(selectedDocNameIndices) == 0:
            return None

        docNameIndex = selectedDocNameIndices[0]
        filePathIndex = selectedFilePathIndices[0]

        return (docNameIndex, filePathIndex)

    def documentMapping(self):
        """
        Returns a tuple containing the selected document name and the corresponding file name.
        """
        mIndices = self._selectedMappings()

        if mIndices == None:
            return None

        docNameItem = self._docItemModel.itemFromIndex(mIndices[0])
        filePathItem = self._docItemModel.itemFromIndex(mIndices[1])

        return (docNameItem.text(), filePathItem.text())

    def _editTemplate(self, templatePath, newName):
        """
        Updates the template document to use the new name.
        """
        templateFile = QFile(templatePath)

        if not templateFile.open(QIODevice.ReadOnly):
            QMessageBox.critical(self, QApplication.translate("TemplateDocumentSelector", "Open Operation Error"), \
                                 "{0}\n{1}".format(
                                     QApplication.translate("TemplateDocumentSelector", "Cannot read template file."), \
                                     templateFile.errorString()
                                 ))
            return (False, "")

        templateDoc = QDomDocument()

        if templateDoc.setContent(templateFile):
            composerElement = templateDoc.documentElement()
            titleAttr = composerElement.attributeNode("_title")
            if not titleAttr.isNull():
                titleAttr.setValue(newName)

            # Try remove file
            status = templateFile.remove()

            if not status:
                return (False, "")

            # Create new file
            newTemplatePath = self._composerTemplatesPath(
            ) + "/" + newName + ".sdt"
            newTemplateFile = QFile(newTemplatePath)

            if not newTemplateFile.open(QIODevice.WriteOnly):
                QMessageBox.critical(self, QApplication.translate("TemplateDocumentSelector", "Save Operation Error"), \
                                     "{0}\n{1}".format(QApplication.translate("TemplateDocumentSelector",
                                                                              "Could not save template file."), \
                                                       newTemplateFile.errorString()
                                                       ))
                return (False, "")

            if newTemplateFile.write(templateDoc.toByteArray()) == -1:
                QMessageBox.critical(self, QApplication.translate("TemplateDocumentSelector", "Save Error"), \
                                     QApplication.translate("TemplateDocumentSelector",
                                                            "Could not save template file."))
                return (False, "")

            newTemplateFile.close()

            return (True, newTemplatePath)

    def _deleteDocument(self, templatePath):
        """
        Delete the document template from the file system.
        """
        docFile = QFile(templatePath)

        return docFile.remove()

    def _composerTemplatesPath(self):
        """
        Reads the path of composer templates in the registry.
        """
        regConfig = RegistryConfig()
        keyName = "ComposerTemplates"

        valueCollection = regConfig.read([keyName])

        if len(valueCollection) == 0:
            return None

        else:
            return valueCollection[keyName]