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)
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)
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)
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]