class RasterLegendSensitive(QObject): def __init__(self, iface, treeView, ckEnabled): super(RasterLegendSensitive, self).__init__() self.tree = TreeLegend(treeView) self.ckEnabled = ckEnabled # self.layer = self.worker = self.thread = self.transparencyLayer = None self.isExtentLayer = self.valuesFullExtent = None self.hasConnect = self.hasConnectTree = None self.iface = iface self.legend = iface.legendInterface() self.canvas = iface.mapCanvas() self.msgBar = iface.messageBar() self.nameModulus = "RasterLegendSensitive" # self.initThread() self._connect() self._connectTree() def __del__(self): del self.tree self.finishThread() if not self.hasConnect: self._connect(False) if not self.layer is None: self.setTransparenceLayer([]) def initThread(self): self.thread = QThread(self) self.thread.setObjectName(self.nameModulus) self.worker = WorkerRasterLegendSensitive() self.worker.moveToThread(self.thread) self._connectWorker() def finishThread(self): self._connectWorker(False) self.worker.deleteLater() self.thread.wait() self.thread.deleteLater() self.thread = self.worker = None def _connectWorker(self, isConnect=True): ss = [{ 'signal': self.thread.started, 'slot': self.worker.run }, { 'signal': self.worker.finished, 'slot': self.finishedWorker }, { 'signal': self.worker.messageStatus, 'slot': self.messageStatusWorker }] if isConnect: for item in ss: item['signal'].connect(item['slot']) else: for item in ss: item['signal'].disconnect(item['slot']) def _connect(self, isConnect=True): ss = [{ 'signal': self.legend.currentLayerChanged, 'slot': self.selectLayer }, { 'signal': QgsMapLayerRegistry.instance().layerWillBeRemoved, 'slot': self.removeLayer }, { 'signal': self.canvas.extentsChanged, 'slot': self.changeSensitiveLegend }] if isConnect: self.hasConnect = True for item in ss: item['signal'].connect(item['slot']) else: self.hasConnect = False for item in ss: item['signal'].disconnect(item['slot']) def _connectTree(self, isConnect=True): ss = [{ 'signal': self.tree.toggledLegend, 'slot': self.setTransparenceLayer }, { 'signal': self.tree.descriptionLegend, 'slot': self.sendClipboard }] if isConnect: self.hasConnectTree = True for item in ss: item['signal'].connect(item['slot']) else: self.hasConnectTree = False for item in ss: item['signal'].disconnect(item['slot']) def _resetLayer(self): if self.thread.isRunning(): self.worker.isKilled = True self.layer = None self.tree.setHeader() self.tree.layer = None def setEnabled(self, isEnabled=True): if not isEnabled and self.thread.isRunning(): self.worker.isKilled = True # self._connect(isEnabled) self._connectTree(isEnabled) self.tree.setEnabled(isEnabled) # if isEnabled: activeLayer = self.iface.activeLayer() if activeLayer == self.layer: if activeLayer is None: return self.changeSensitiveLegend() else: self.selectLayer(activeLayer) @pyqtSlot(list) def finishedWorker(self, values): self.thread.quit() self.msgBar.popWidget() if not self.worker.isKilled: if len(values) > 0: # Never Happing otherwise... self.tree.setLegend(values) if self.isExtentLayer: self.valuesFullExtent = values else: # When PAN/ZOOM/... self.thread.wait() if self.ckEnabled.checkState() == Qt.Checked: self.changeSensitiveLegend() @pyqtSlot(str) def messageStatusWorker(self, msg): self.msgBar.popWidget() self.msgBar.pushMessage(self.nameModulus, msg, QgsMessageBar.INFO) @pyqtSlot(list) def setTransparenceLayer(self, visibleItems): def refreshLayer(): if hasattr(self.layer, "setCacheImage"): self.layer.setCacheImage(None) # Refresh else: self.layer.triggerRepaint() def setTransparence(value, visible): t = QgsRasterTransparency.TransparentSingleValuePixel() t.min = t.max = value percent = 100.0 if not visible else 0.0 t.percentTransparent = percent return t valuesTransparent = [] item = 0 for visible in visibleItems: valuesTransparent.append(setTransparence(item, visible)) item += 1 self.transparencyLayer.setTransparentSingleValuePixelList( valuesTransparent) refreshLayer() del valuesTransparent[:] @pyqtSlot(str) def sendClipboard(self, description): mapSettings = self.canvas.mapSettings() crsCanvas = mapSettings.destinationCrs() extentCanvas = self.canvas.extent() extentLayer = self.layer.extent() if self.layer.crs() != crsCanvas: extentCanvas = mapSettings.mapToLayerCoordinates( self.layer, extentCanvas) if extentCanvas == extentLayer or extentCanvas.contains(extentLayer): msg = "Calculate for all extent of layer '%s'\n\n%s" % ( self.layer.name(), description) else: msg = "Calculate for subset of layer '%s' (extend: %s)\n\n%s" % ( self.layer.name(), extentCanvas.toString(), description) clip = QApplication.clipboard() clip.setText(msg) self.msgBar.pushMessage(self.nameModulus, "Copy to Clipboard", QgsMessageBar.INFO, 5) @pyqtSlot('QgsMapLayer') def selectLayer(self, layer): def processLegend(): self.tree.setLayer(layer) if not self.valuesFullExtent is None: # Save legend with all extent layer del self.valuesFullExtent[:] self.valuesFullExtent = None (self.layer, self.transparencyLayer) = (layer, layer.renderer().rasterTransparency()) self.worker.setLegendReadBlock(layer) self.changeSensitiveLegend() if not self.layer is None: if not self.layer in self.legend.layers(): self.removeLayer(self.layer.id()) else: self.setTransparenceLayer([]) self._resetLayer() if not layer is None and layer.type() == QgsMapLayer.RasterLayer: legendItems = layer.legendSymbologyItems() total = len(legendItems) if total > 0: # Had a classification processLegend() @pyqtSlot(str) def removeLayer(self, idLayer): if not self.layer is None and self.layer.id() == idLayer: msg = "Layer '%s' was removed" % self.tree.getLayerName() self.msgBar.pushMessage(self.nameModulus, msg, QgsMessageBar.WARNING, 5) self._resetLayer() @pyqtSlot() def changeSensitiveLegend(self): if self.layer is None: return if self.thread.isRunning(): self.worker.isKilled = True return mapSettings = self.canvas.mapSettings() crsCanvas = mapSettings.destinationCrs() extentCanvas = self.canvas.extent() extentLayer = self.layer.extent() resX = self.layer.rasterUnitsPerPixelX() resY = self.layer.rasterUnitsPerPixelY() if self.layer.crs() != crsCanvas: extentCanvas = mapSettings.mapToLayerCoordinates( self.layer, extentCanvas) if not extentCanvas.intersects(extentLayer): self.msgBar.popWidget() self.msgBar.pushMessage( self.nameModulus, "View not intersects Raster '%s'" % self.layer.name(), QgsMessageBar.WARNING, 5) self.tree.setLegend([]) return if extentCanvas == extentLayer or extentCanvas.contains(extentLayer): self.isExtentLayer = True if not self.valuesFullExtent is None: self.tree.setLegend(self.valuesFullExtent) return extent = extentLayer delta = 0 else: self.isExtentLayer = False extent = extentCanvas.intersect(extentLayer) delta = 1 widthRead = int(extent.width() / resX) + delta heightRead = int(extent.height() / resY) + delta self.worker.setProcessImage(extent, widthRead, heightRead) self.thread.start()
class SensitiveLegendRaster(QObject): def __init__(self): super(SensitiveLegendRaster, self).__init__() # QThread self.layer = self.worker = self.thread = None self.canvas = iface.mapCanvas() self.msgBar = iface.messageBar() self.legend = iface.legendInterface() self.nameModulus = "Script_Sensitive_Legend" # self.initThread() self._connect() # self.selectLayer(iface.activeLayer()) def __del__(self): self.finishThread() self._connect(False) def printMsgBar(self, msg, typeMsg=QgsMessageBar.INFO): self.msgBar.popWidget() if typeMsg == QgsMessageBar.INFO: self.msgBar.pushMessage("SensitiveLegendRaster Script", msg, typeMsg) else: self.msgBar.pushMessage("SensitiveLegendRaster Script", msg, typeMsg, 5) def initThread(self): self.thread = QThread(self) self.thread.setObjectName(self.nameModulus) self.worker = WorkerSensitiveLegendRaster() self.worker.moveToThread(self.thread) self._connectWorker() def finishThread(self): self._connectWorker(False) self.worker.deleteLater() self.thread.wait() self.thread.deleteLater() self.thread = self.worker = None def _connectWorker(self, isConnect=True): ss = [ {"signal": self.thread.started, "slot": self.worker.run}, {"signal": self.worker.finished, "slot": self.finishedWorker}, {"signal": self.worker.messageResult, "slot": self.messageResultWorker}, {"signal": self.worker.messageStatus, "slot": self.messageStatusWorker}, ] if isConnect: for item in ss: item["signal"].connect(item["slot"]) else: for item in ss: item["signal"].disconnect(item["slot"]) def _connect(self, isConnect=True): ss = [ {"signal": self.legend.currentLayerChanged, "slot": self.selectLayer}, {"signal": QgsMapLayerRegistry.instance().layerWillBeRemoved, "slot": self.unselectLayer}, {"signal": self.canvas.extentsChanged, "slot": self.changeSensitiveLegend}, ] if isConnect: for item in ss: item["signal"].connect(item["slot"]) else: for item in ss: item["signal"].disconnect(item["slot"]) @pyqtSlot() def finishedWorker(self): self.thread.quit() if self.worker.isKilled: # When PAN/ZOOM/... self.thread.wait() self.changeSensitiveLegend() @pyqtSlot(str) def messageResultWorker(self, msg): self.printMsgBar(msg) @pyqtSlot(str) def messageStatusWorker(self, msg): self.printMsgBar(msg) @pyqtSlot("QgsMapLayer") def selectLayer(self, layer): if self.thread.isRunning(): return isOk = True msg = "" typeMsg = QgsMessageBar.WARNING if not layer is None and layer.type() == QgsMapLayer.RasterLayer: legendColorAll = layer.legendSymbologyItems() if len(legendColorAll) > 0: # Had a classification self.layer = layer self.worker.setLegendReadBlock(layer) msg = "Raster Layer '%s' actived" % layer.name() typeMsg = QgsMessageBar.INFO else: msg = "Raster Layer '%s' need be a classification" % layer.name() isOk = False else: if layer is None: msg = "Active a Raster layer" else: msg = "Layer '%s' need be a Raster" % layer.name() isOk = False self.printMsgBar(msg, typeMsg) return isOk @pyqtSlot(str) def unselectLayer(self, idLayer): if idLayer == self.layer.id(): if self.thread.isRunning(): self.worker.isKilled = True msg = "Raster Layer '%s' was removed" % self.layer.name() self.printMsgBar(msg, QgsMessageBar.WARNING) self.layer = None @pyqtSlot() def changeSensitiveLegend(self): if self.layer is None: return if self.thread.isRunning(): self.worker.isKilled = True return mapSettings = self.canvas.mapSettings() crsCanvas = mapSettings.destinationCrs() extentCanvas = self.canvas.extent() extentLayer = self.layer.extent() resX = self.layer.rasterUnitsPerPixelX() resY = self.layer.rasterUnitsPerPixelY() if self.layer.crs() != crsCanvas: extentCanvas = mapSettings.mapToLayerCoordinates(self.layer, extentCanvas) if not extentCanvas.intersects(extentLayer): self.printMsgBar("View not intersects Raster '%s'" % self.layer.name, QgsMessageBar.WARNING) return keysLegend = range(len(self.worker.legendAll)) # [ idClass1, idClass2, ... ] [ 0..N-1] if extentCanvas == extentLayer or extentCanvas.contains(extentLayer): legendsView = map(lambda x: "(%s)%s" % (x, self.worker.legendAll[x]), keysLegend) msg = "[%d] = %s" % (len(legendsView), " ".join(legendsView)) self.printMsgBar(msg) return extent = extentCanvas.intersect(extentLayer) widthRead = int(extent.width() / resX) + 1 heightRead = int(extent.height() / resY) + 1 self.worker.setProcessImage(extent, widthRead, heightRead) self.thread.start()
class CatalogOTF(QObject): # Signals settedLayer = pyqtSignal("QgsVectorLayer") removedLayer = pyqtSignal(str) killed = pyqtSignal(str) changedNameLayer = pyqtSignal(str, str) changedTotal = pyqtSignal(str, str) changedIconRun = pyqtSignal(str, bool) def __init__(self, iface, tableCOTF): def connecTableCOTF(): self.settedLayer.connect(tableCOTF.insertRow) self.removedLayer.connect(tableCOTF.removeRow) self.changedNameLayer.connect(tableCOTF.changedNameLayer) self.changedTotal.connect(tableCOTF.changedTotal) self.changedIconRun.connect(tableCOTF.changedIconRun) self.killed.connect(tableCOTF.killed) super(CatalogOTF, self).__init__() self.iface = iface self.canvas = iface.mapCanvas() self.ltv = iface.layerTreeView() self.model = self.ltv.layerTreeModel() self.ltgRoot = QgsProject.instance().layerTreeRoot() self.msgBar = iface.messageBar() self.legendTMS = LegendTMS('Catalog OTF') self.legendRaster = LegendRaster('Catalog OTF') self._initThread() connecTableCOTF() self.model.dataChanged.connect(self.dataChanged) QgsMapLayerRegistry.instance().layersWillBeRemoved.connect( self.layersWillBeRemoved) # Catalog layer removed self.layer = self.layerName = self.nameFieldSource = self.nameFieldDate = None self.ltgCatalog = self.ltgCatalogName = self.visibleSourceLayers = self.hasCanceled = None def __del__(self): self._finishThread() del self.legendTMS del self.legendRaster QgsMapLayerRegistry.instance().layersWillBeRemoved.disconnect( self.layersWillBeRemoved) # Catalog layer removed def _initThread(self): self.thread = QThread(self) self.thread.setObjectName("QGIS_Plugin_%s" % NAME_PLUGIN.replace(' ', '_')) self.worker = WorkerPopulateGroup(self.addLegendLayerWorker) self.worker.moveToThread(self.thread) self._connectWorker() def _finishThread(self): self._connectWorker(False) self.worker.deleteLater() self.thread.wait() self.thread.deleteLater() self.thread = self.worker = None def _connectWorker(self, isConnect=True): ss = [{ 'signal': self.thread.started, 'slot': self.worker.run }, { 'signal': self.worker.finished, 'slot': self.finishedPG }, { 'signal': self.worker.messageStatus, 'slot': self.messageStatusPG }, { 'signal': self.worker.messageError, 'slot': self.messageErrorPG }] if isConnect: for item in ss: item['signal'].connect(item['slot']) else: for item in ss: item['signal'].disconnect(item['slot']) def addLegendLayerWorker(self, layer): if layer.type() == QgsMapLayer.RasterLayer: metadata = layer.metadata() if metadata.find("GDAL provider") != -1: if metadata.find("OGC Web Map Service") != -1: if self.legendTMS.hasTargetWindows(layer): self.legendTMS.setLayer(layer) else: self.legendRaster.setLayer(layer) def run(self): self.hasCanceled = False # Check in finishedPG if self.thread.isRunning(): self.worker.kill() self.hasCanceled = True msgtrans = QCoreApplication.translate( "CatalogOTF", "Canceled search for image from layer %s") msg = msgtrans % self.layerName self.msgBar.pushMessage(NAME_PLUGIN, msg, QgsMessageBar.WARNING, 2) self.changedTotal.emit(self.layer.id(), "Canceling processing") self.killed.emit(self.layer.id()) return if self.layer is None: msgtrans = QCoreApplication.translate("CatalogOTF", "Need define layer catalog") self.msgBar.pushMessage(NAME_PLUGIN, msgtrans, QgsMessageBar.WARNING, 2) return self._setGroupCatalog() self.ltgCatalogName = self.ltgCatalog.name() renderFlag = self.canvas.renderFlag() if renderFlag: self.canvas.setRenderFlag(False) self.canvas.stopRendering() self._populateGroupCatalog() if renderFlag: self.canvas.setRenderFlag(True) self.canvas.refresh() def _populateGroupCatalog(self): def getSourceVisibleLayers(): def hasVisibleRaster(ltl): return ltl.isVisible() == Qt.Checked and ltl.layer().type( ) == QgsMapLayer.RasterLayer l_ltlVisible = filter(lambda item: hasVisibleRaster(item), self.ltgCatalog.findLayers()) return map(lambda item: item.layer().source(), l_ltlVisible) def runWorker(): data = {} data['nameFieldDate'] = self.nameFieldDate data['nameFieldSource'] = self.nameFieldSource data['layer'] = self.layer data['ltgCatalog'] = self.ltgCatalog self.worker.setData(data) self.thread.start() #self.worker.run() # DEBUG self.visibleSourceLayers = getSourceVisibleLayers() self.ltgCatalog.removeAllChildren() runWorker() # See finishPG def _setGroupCatalog(self): self.ltgCatalogName = "%s - Catalog" % self.layer.name() self.ltgCatalog = self.ltgRoot.findGroup(self.ltgCatalogName) if self.ltgCatalog is None: self.ltgCatalog = self.ltgRoot.addGroup(self.ltgCatalogName) @pyqtSlot(bool) def finishedPG(self, isKilled): def setSourceVisibleLayers(): l_ltlVisible = filter( lambda item: item.layer().source() in self.visibleSourceLayers, self.ltgCatalog.findLayers()) map(lambda item: item.setVisible(Qt.Checked), l_ltlVisible) self.thread.quit() if not self.layer is None: self.changedIconRun.emit(self.layer.id(), self.layer.selectedFeatureCount() > 0) if self.hasCanceled: self.changedTotal.emit(self.layer.id(), '0') else: setSourceVisibleLayers() del self.visibleSourceLayers[:] @pyqtSlot(str) def messageStatusPG(self, msg): self.changedTotal.emit(self.layer.id(), msg) @pyqtSlot(str) def messageErrorPG(self, msg): self.msgBar.pushMessage(NAME_PLUGIN, msg, QgsMessageBar.CRITICAL, 8) @pyqtSlot('QModelIndex', 'QModelIndex') def dataChanged(self, idTL, idBR): if idTL != idBR: return if not self.ltgCatalog is None and self.ltgCatalog == self.model.index2node( idBR): name = self.ltgCatalog.name() if self.ltgCatalogName != name: self.ltgCatalogName = name return if not self.layer is None and self.ltgRoot.findLayer( self.layer.id()) == self.model.index2node(idBR): name = self.layer.name() if self.layerName != name: self.changedNameLayer.emit(self.layer.id(), name) self.layerName = name @pyqtSlot(list) def layersWillBeRemoved(self, layerIds): if self.layer is None: return if self.layer.id() in layerIds: self.removedLayer.emit(self.layer.id()) self.removeLayerCatalog() @staticmethod def getNameFieldsCatalog(layer): def getFirstFeature(): f = QgsFeature() # fr = QgsFeatureRequest( ) # First FID can be 0 or 1 depend of provider type it = layer.getFeatures(fr) isOk = it.nextFeature(f) it.close() # if not isOk or not f.isValid(): del f return None else: return f def hasAddress(feature, nameField): def asValidUrl(url): isOk = True try: urllib2.urlopen(url) except urllib2.HTTPError, e: isOk = False except urllib2.URLError, e: isOk = False # return isOk value = feature.attribute(nameField) if value is None or type(value) == QPyNullVariant: return False isUrl = value.find('http://') == 0 or value.find('https://') == 0 lenSource = len(value) isUrl = isUrl and value.rfind( 'xml', lenSource - len('xml')) == lenSource - len('xml') if isUrl: return asValidUrl(value) # fileInfo = QFileInfo(value) return fileInfo.isFile()