class MapTool(QgsMapTool): geometry_changed = pyqtSignal(QgsGeometry, bool) tool_deactivated = pyqtSignal() def __init__(self, canvas, cursorstyle=Qt.CrossCursor): self.canvas = canvas QgsMapTool.__init__(self, canvas) self.caller = self.sender() self.cursorStyle = cursorstyle self.active = False # get selection color selcolor = self.canvas.selectionColor() mycolor = QColor(selcolor.red(), selcolor.green(), selcolor.blue(), 40) self.rb = QgsRubberBand(self.canvas) self.rb.setStrokeColor(QColor(255, 0, 0, 40)) self.rb.setFillColor(mycolor) self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine)) self.rb.setWidth(2) def setCursorStyle(self): cursor = QCursor() cursor.setShape(self.cursorStyle) self.setCursor(cursor) def activate(self): self.caller.setChecked(True) self.setCursorStyle() def deactivate(self): self.canvas.scene().removeItem(self.rb) self.tool_deactivated.emit() self.caller.setChecked(False) QgsMapTool.deactivate(self) def setGeometry(self, geo): self.rb.setToGeometry(geo) def canvasReleaseEvent(self, mouseEvent): if mouseEvent.button() == Qt.LeftButton: if not self.active: self.active = True self.geometry_changed.emit(QgsGeometry(), False) self.rb.reset(QgsWkbTypes.LineGeometry) self.rb.addPoint(mouseEvent.mapPoint()) if self.rb.numberOfVertices() > 1: self.geometry_changed.emit(self.rb.asGeometry(), False) elif mouseEvent.button() == Qt.RightButton: if self.rb.numberOfVertices() > 2: self.active = False self.rb.removeLastPoint() geo = self.rb.asGeometry() self.geometry_changed.emit(geo, True) else: self.rb.reset(QgsWkbTypes.LineGeometry) def canvasMoveEvent(self, mouseEvent): if self.rb.numberOfVertices() > 1 and self.active: self.rb.removeLastPoint() self.rb.addPoint(mouseEvent.mapPoint()) pass
def highlight(): rb = QgsRubberBand( self.canvas, QGis.Polygon) rb.setBorderColor( QColor( 255, 0, 0 ) ) rb.setWidth( 2 ) rb.setToGeometry( geomRB, None ) return rb
def drawTileGrid(self, tile_min, tile_max, z): canvas = iface.mapCanvas() epsg = canvas.mapSettings().destinationCrs().authid() crsSrc = QgsCoordinateReferenceSystem(epsg) crsDest = QgsCoordinateReferenceSystem(4326) # WGS 84 / UTM zone 33N xform = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance()) for x in range(tile_min.x, tile_max.x): for y in range(tile_min.y, tile_max.y): p1 = ul(x, y, z) p2 = ul(x + 1, y + 1, z) t1 = xform.transform(QgsPointXY(p1.lng, p1.lat), QgsCoordinateTransform.ReverseTransform) t2 = xform.transform(QgsPointXY(p2.lng, p2.lat), QgsCoordinateTransform.ReverseTransform) print(f"polyline {t1} {t2}") polyline = QgsRubberBand(canvas) points = [ QgsPoint(t1.x(), t1.y()), QgsPoint(t2.x(), t1.y()), QgsPoint(t2.x(), t2.y()), QgsPoint(t1.x(), t2.y()) ] polyline.setToGeometry(QgsGeometry.fromPolyline(points), None) polyline.setColor(QColor(255, 255, 0)) polyline.setWidth(2)
def loadLines(self, lines, points, markers, suffix): no = self.project.readEntry("TUVIEW", "lines{0}no".format(suffix))[0] if no: no = int(no) for i in range(no): a = self.project.readEntry("TUVIEW", 'lines{0}x{1}'.format(suffix, i))[0] a = a.split('~~') b = self.project.readEntry("TUVIEW", 'lines{0}y{1}'.format(suffix, i))[0] b = b.split('~~') points.clear() for j in range(len(a)): x = float(a[j]) y = float(b[j]) point = QgsPoint(x, y) points.append(point) if i + 1 == no: marker = QgsVertexMarker(self.tuView.canvas) if suffix == 'cs': marker.setColor(Qt.red) marker.setIconSize(10) marker.setIconType(QgsVertexMarker.ICON_BOX) else: # 'q' marker.setColor(Qt.blue) marker.setIconSize(12) marker.setIconType(QgsVertexMarker.ICON_DOUBLE_TRIANGLE) marker.setCenter(QgsPointXY(point)) markers.append(marker) line = QgsRubberBand(self.tuView.canvas, False) line.setWidth(2) if suffix == 'cs': line.setColor(QColor(Qt.red)) else: # 'q' line.setColor(QColor(Qt.blue)) line.setToGeometry(QgsGeometry.fromPolyline(points), None) lines.append(line)
def _draw_rubberband(self, geometry, colour, width): """Draw a rubber band on the canvas. .. versionadded: 2.2.0 :param geometry: Extent that the rubber band should be drawn for. :type geometry: QgsGeometry :param colour: Colour for the rubber band. :type colour: QColor :param width: The width for the rubber band pen stroke. :type width: int :returns: Rubber band that should be set to the extent. :rtype: QgsRubberBand """ # noinspection PyArgumentList rubber_band = QgsRubberBand(self._map_canvas, geometryType=QGis.Polygon) rubber_band.setBrushStyle(Qt.NoBrush) rubber_band.setColor(colour) rubber_band.setWidth(width) rubber_band.setToGeometry(geometry, None) return rubber_band
def zoomAndShowWKT(self, wtk): geom = QgsGeometry.fromWkt(wtk) canvas = self.iface.mapCanvas() self.clear() r = QgsRubberBand(canvas, geom.type() == 3 ) r.setToGeometry(geom, None) r.setColor(QColor(0, 0, 255)) r.setFillColor(QColor(0, 0, 255, 50)) r.setWidth(3) pt = geom.pointOnSurface().asPoint() m = QgsVertexMarker(canvas) m.setCenter( pt ) m.setColor(QColor(0, 0, 255)) m.setIconSize(5) m.setIconType(QgsVertexMarker.ICON_BOX) m.setPenWidth(3) if geom.type() == 3 or geom.type() == 2: rec = geom.boundingBox() canvas.setExtent(rec) else: self.moveMapTo( pt[0], pt[1], 0) self.graphics.append(r) self.graphics.append(m) self._refresh_layers()
def _draw_rubberband(self, geometry, colour, width): """Draw a rubber band on the canvas. .. versionadded: 2.2.0 :param geometry: Extent that the rubber band should be drawn for. :type geometry: QgsGeometry :param colour: Colour for the rubber band. :type colour: QColor :param width: The width for the rubber band pen stroke. :type width: int :returns: Rubber band that should be set to the extent. :rtype: QgsRubberBand """ # noinspection PyArgumentList rubber_band = QgsRubberBand( self._map_canvas, geometryType=QGis.Polygon) rubber_band.setBrushStyle(Qt.NoBrush) rubber_band.setColor(colour) rubber_band.setWidth(width) rubber_band.setToGeometry(geometry, None) return rubber_band
class MapTool(QgsMapTool): geometry_changed = pyqtSignal(QgsGeometry,bool) tool_deactivated = pyqtSignal() def __init__(self, canvas, cursorstyle = Qt.CrossCursor): self.canvas = canvas QgsMapTool.__init__(self, canvas) self.caller = self.sender() self.cursorStyle=cursorstyle self.active = False self.center=None # get selection color selcolor =self.canvas.selectionColor() mycolor = QColor(selcolor.red(), selcolor.green(), selcolor.blue(), 40) self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rb.setStrokeColor(QColor(255, 0, 0, 40)) self.rb.setFillColor(mycolor) self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine)) self.rb.setWidth(2) def setCursorStyle(self): cursor = QCursor() cursor.setShape(self.cursorStyle) self.setCursor(cursor) def activate(self): self.caller.setChecked(True) self.setCursorStyle() def deactivate(self): self.canvas.scene().removeItem(self.rb) self.tool_deactivated.emit() self.caller.setChecked(False) QgsMapTool.deactivate(self) def setGeometry(self,geo): self.rb.setToGeometry(geo) def canvasReleaseEvent(self, mouseevent): if mouseevent.button() == Qt.LeftButton: self.active = False self.geometry_changed.emit(self.rb.asGeometry(),True) pass def canvasMoveEvent(self, mouseEvent): if self.active: cp = self.toMapCoordinates(mouseEvent.pos()) rec = QgsRectangle(self.center, cp) self.rb.setToGeometry(QgsGeometry.fromRect(rec)) self.geometry_changed.emit(self.rb.asGeometry(),True) pass def canvasPressEvent(self, e): if e.button() == Qt.LeftButton: self.active = True self.center = self.toMapCoordinates(e.pos()) self.geometry_changed.emit(QgsGeometry(),False) self.rb.reset() pass
def addGraphic(self, geom): canvas = self.iface.mapCanvas() rBand = QgsRubberBand(canvas, True) self.graphics.append(rBand) rBand.setToGeometry(geom, None) rBand.setColor(QColor(0, 0, 255, 70)) rBand.setStrokeColor(QColor(0, 0, 250, 220)) rBand.setWidth(3)
def addGraphic(self, geom ): canvas = self.iface.mapCanvas() rBand = QgsRubberBand(canvas, True) self.graphics.append( rBand ) rBand.setToGeometry( geom, None ) rBand.setColor(QtGui.QColor(0,0,255, 70)) if QGis.QGIS_VERSION_INT >= 20600: rBand.setBorderColor( QtGui.QColor(0,0,250, 220) ) rBand.setWidth(3)
def build_rubber_band(self, points): rubber_band = QgsRubberBand(self.canvas(), False) # False = not a polygon rubber_band.setToGeometry(QgsGeometry.fromPolyline(points), None) # for point in points: # rubber_band.addPoint(point) rubber_band.setColor(QColor(255, 128, 128)) rubber_band.setWidth(1) rubber_band.setBrushStyle(Qt.Dense4Pattern) return rubber_band
def addGraphic(self, geom): canvas = self.iface.mapCanvas() rBand = QgsRubberBand(canvas, True) self.graphics.append(rBand) rBand.setToGeometry(geom, None) rBand.setColor(QtGui.QColor(0, 0, 255, 70)) if QGis.QGIS_VERSION_INT >= 20600: rBand.setBorderColor(QtGui.QColor(0, 0, 250, 220)) rBand.setWidth(3)
def _setRubberBandMarker(self, geom): m = QgsRubberBand(self.qgisIface.mapCanvas(), False) # not polygon if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry: linegeom = geom elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PolygonGeometry: linegeom = QgsGeometry.fromPolylineXY(geom.asPolygon()[0]) m.setToGeometry(linegeom, None) m.setColor(QColor(self.config['rubber_color'])) m.setWidth(self.config['rubber_width']) return m
def onClickedHighlight(self): def removeRB(): rb.reset(True) self.qgisCanvas.scene().removeItem(rb) rb = QgsRubberBand(self.qgisCanvas, QGis.Polygon) rb.setBorderColor(QColor(255, 0, 0)) rb.setWidth(2) rb.setToGeometry(QgsGeometry.fromRect(self.canvas.extent()), None) QTimer.singleShot(2000, removeRB)
def _highlight(self, canvas, extent): def removeRB(): rb.reset(True) canvas.scene().removeItem(rb) rb = QgsRubberBand(canvas, QGis.Polygon) rb.setBorderColor(QColor(255, 0, 0)) rb.setWidth(2) rb.setToGeometry(QgsGeometry.fromRect(extent), None) QTimer.singleShot(2000, removeRB)
def onClickedHighlight(self): def removeRB(): rb.reset( True ) self.qgisCanvas.scene().removeItem( rb ) rb = QgsRubberBand( self.qgisCanvas, QGis.Polygon) rb.setBorderColor( QColor( 255, 0, 0 ) ) rb.setWidth( 2 ) rb.setToGeometry( QgsGeometry.fromRect( self.canvas.extent() ), None ) QTimer.singleShot( 2000, removeRB )
class CurrentSelection(QgsRubberBand): """ Position marker for the current location in the viewer. """ class AniObject(QObject): def __init__(self, band): super(CurrentSelection.AniObject, self).__init__() self.color = QColor() @pyqtProperty(int) def alpha(self): return self.color.alpha() @alpha.setter def alpha(self, value): self.color.setAlpha(value) def __init__(self, canvas): super(CurrentSelection, self).__init__(canvas) self.outline = QgsRubberBand(canvas) self.outline.setBrushStyle(Qt.NoBrush) self.outline.setWidth(5) self.outline.setIconSize(30) self.aniobject = CurrentSelection.AniObject(self) self.anim = QPropertyAnimation(self.aniobject, "alpha") self.anim.setDuration(500) self.anim.setStartValue(50) self.anim.setEndValue(100) self.anim.valueChanged.connect(self.value_changed) def setOutlineColour(self, color): self.outline.setColor(color) def setToGeometry(self, geom, layer): super(CurrentSelection, self).setToGeometry(geom, layer) self.outline.setToGeometry(geom, layer) self.anim.stop() self.anim.start() def reset(self, geomtype=QGis.Line): super(CurrentSelection, self).reset(geomtype) self.outline.reset(geomtype) self.anim.stop() def value_changed(self, value): self.setColor(self.aniobject.color) self.update() def setColor(self, color): self.aniobject.color = color super(CurrentSelection, self).setColor(color)
class MapTool(QgsMapToolIdentify): geometry_changed = pyqtSignal(QgsGeometry, bool) tool_deactivated = pyqtSignal() def __init__(self, canvas, cursorstyle=Qt.CrossCursor): self.canvas = canvas QgsMapTool.__init__(self, canvas) self.caller = self.sender() self.cursorStyle = cursorstyle self.active = False # get selection color selcolor = self.canvas.selectionColor() mycolor = QColor(selcolor.red(), selcolor.green(), selcolor.blue(), 40) self.rb = QgsRubberBand(self.canvas) self.rb.setStrokeColor(QColor(255, 0, 0, 40)) self.rb.setFillColor(mycolor) self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine)) self.rb.setWidth(2) self.center = None self.cercle = 120 #circle of 30 segments def setCursorStyle(self): cursor = QCursor() cursor.setShape(self.cursorStyle) self.setCursor(cursor) def activate(self): self.caller.setChecked(True) self.setCursorStyle() def deactivate(self): self.canvas.scene().removeItem(self.rb) self.tool_deactivated.emit() self.caller.setChecked(False) QgsMapTool.deactivate(self) def setGeometry(self, geo): self.rb.setToGeometry(geo) def canvasReleaseEvent(self, mouseEvent): self.geometry_changed.emit(QgsGeometry(), False) if mouseEvent.button() == Qt.LeftButton: results = self.identify(mouseEvent.x(), mouseEvent.y(), self.ActiveLayer, self.VectorLayer) for res in results: if res.mFeature and res.mLayer: geo = res.mFeature.geometry() self.rb.setToGeometry(geo) self.geometry_changed.emit(geo, True) break pass
def update_map(self, north, east, south, west): """ This updates the map to add the new bounding box specified by the north, east, south, west parameters. :param north: The name of the north point :param east: The name of the east point :param south: The name of the south point :param west: The name of the west point :return: """ from qgis.utils import iface from qgis.PyQt.QtCore import Qt # Creates map canvas within the widget in the window canvas = QgsMapCanvas(self.dlg.QgsMapCanvas_wid) canvas.setMinimumSize(460, 250) # Gets the basemap from the server and displays only that layer canvas_layer_list = [self.raster, self.raster] canvas.setLayers(canvas_layer_list) # Sets the coordinate reference system crsDest = QgsCoordinateReferenceSystem(4326) # destination crsSrc = canvas.mapSettings().destinationCrs() # source xform = QgsCoordinateTransform() xform.setSourceCrs(crsSrc) xform.setDestinationCrs(crsDest) canvas.setDestinationCrs(crsDest) # Creating the rubber band rectangle r = QgsRubberBand(canvas, True) # True = a polygon # Sepcifying the points of rectangle points = [[ QgsPointXY(west, north), QgsPointXY(east, north), QgsPointXY(east, south), QgsPointXY(west, south) ]] r.setToGeometry(QgsGeometry.fromPolygonXY(points), None) r.setFillColor(QColor(255, 0, 0, 50)) #R,G,B,Transparency r.setWidth(3) canvas.zoomWithCenter(north - south, east - west, True) canvas.setExtent(self.raster.extent()) canvas.zoomToFullExtent() canvas.zoomScale(2000000000) # scaling for tmp raster #canvas.zoomWithCenter(north-south,east-west,True) canvas.show()
def azimuth(self): punto1 = self.dlg.lineEdit1.text() punto2 = self.dlg.lineEdit2.text() if (punto1 == "" or punto2 == ""): QMessageBox.information(self.iface.mainWindow(), "Error", "Without coordinates") else: x1 = float(punto1.split(",")[0]) y1 = float(punto1.split(",")[1]) x2 = float(punto2.split(",")[0]) y2 = float(punto2.split(",")[1]) # create points objects p1 = QgsPoint(x1, y1) p2 = QgsPoint(x2, y2) az = round(p1.azimuth(p2), 2) if (az < 0): self.dlg.lineEditAzimuth.setText( str(az) + " (" + str(360 + az) + ")") else: self.dlg.lineEditAzimuth.setText(str(az)) # calculate distance points = [p1, p2] line = QgsGeometry.fromPolyline(points) d = QgsDistanceArea() crs = QgsProject.instance().crs() # asigna el crs del proyecto # comprobar si es dd (6) if (crs.mapUnits() == 6): # es dd d.setEllipsoid('WGS84') m = round(d.measureLength(line), 4) else: # projectada m = round(d.measureLength(line), 4) self.dlg.lineEditDistance.setText(str(m)) self.iface.actionPan().trigger() # vuelve el cursor al pan #Drawing Polyline polyline = QgsRubberBand(self.canvas, False) # False = not a polygon points = [QgsPoint(x1, y1), QgsPoint(x2, y2)] polyline.setToGeometry(QgsGeometry.fromPolyline(points), None) polyline.setColor(QColor(255, 0, 0)) polyline.setWidth(3) """
class selectExtentMapTool(QgsMapTool): def __init__(self, parentObj): self.parentObj = parentObj self.iface = parentObj.iface QgsMapTool.__init__(self, self.iface.mapCanvas()) self.contextShape = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.contextShape.setWidth(1) self.contextShape.setColor(QtCore.Qt.red) self.pressed = False def canvasPressEvent(self, event): self.pressed = True self.pressx = event.pos().x() self.pressy = event.pos().y() self.movex = event.pos().x() self.movey = event.pos().y() self.PressedPoint = self.iface.mapCanvas().getCoordinateTransform( ).toMapCoordinates(self.pressx, self.pressy) def canvasMoveEvent(self, event): if self.pressed: x = event.pos().x() y = event.pos().y() movedPoint = self.iface.mapCanvas().getCoordinateTransform( ).toMapCoordinates(x, y) self.contextShape.reset() self.contextgeom = QgsGeometry.fromRect( QgsRectangle(self.PressedPoint, movedPoint)).convertToType( QgsWkbTypes.LineGeometry) self.contextShape.setToGeometry(self.contextgeom) def canvasReleaseEvent(self, event): if self.pressed: x = event.pos().x() y = event.pos().y() releasedPoint = self.iface.mapCanvas().getCoordinateTransform( ).toMapCoordinates(x, y) self.pressed = False self.parentObj.selectedExtent = QgsRectangle( self.PressedPoint, releasedPoint) self.parentObj.iface.mapCanvas().setMapTool(None) def reset(self): self.contextShape.reset()
def add_rubberband_borehole(self, boreholeno): """ Warning - this method fails silently on error """ self.remove_canvas_vertexmarkers() # Add new rubberband points = [[ QgsPoint(6640629.039, 6087146.608), QgsPoint(640629.039, 6087146.608), QgsPoint(640629.039, 6087146.608), QgsPoint(6640629.039, 6087146.608) ]] # lower left, upper right r = QgsRubberBand(iface.mapCanvas, True) # True = a polygon r.setColor(QColor(0, 255, 0, 255)) r.setWidth(3) r.setToGeometry(QgsGeometry.fromPolygon(points), None) JupiterAux.log_info( u'rubberband added for borehole {}'.format(boreholeno))
def create(self, canvas, line_width=2, rbs_in="main_dialog"): """Create the tile as a rubber band inside the canvas given""" rubber_band = QgsRubberBand(canvas) points = [QgsPointXY(self.xmin, self.ymax), QgsPointXY(self.xmax, self.ymax), QgsPointXY(self.xmax, self.ymin), QgsPointXY(self.xmin, self.ymin)] rubber_band.setToGeometry(QgsGeometry.fromPolygonXY([points]), None) if rbs_in == "highlight": rubber_band.setColor(QColor("yellow")) else: rubber_band.setColor(self.tile_color) rubber_band.setFillColor(QColor(0, 0, 0, 0)) rubber_band.setWidth(line_width) rubber_band.show() if rbs_in == "main_dialog": self.rbs_in_main_dialog.append(rubber_band) if rbs_in == "nav_dialog": self.rbs_in_nav_dialog.append(rubber_band) if rbs_in == "highlight": return rubber_band
class ShowStreetCoordinates: """ Creates temp geoms to show the start and end coordinates of a street """ def __init__(self, iface): self.canvas = iface.mapCanvas() self.rb_line = QgsRubberBand(self.canvas, QGis.Line) self.rb_start = QgsVertexMarker(self.canvas) self.rb_end = QgsVertexMarker(self.canvas) self.style() def style(self): # Style start marker self.rb_start.setColor(QColor('blue')) self.rb_start.setIconSize(16) self.rb_start.setPenWidth(4) # Style end marker self.rb_end.setColor(QColor('red')) self.rb_end.setIconSize(16) self.rb_end.setPenWidth(4) # Style line self.rb_line.setColor(QColor('grey')) self.rb_line.setWidth(3) def show(self, coords): # Breakdown coords start = coords[0] end = coords[1] # Create start and end points start_point = QgsPoint(float(start[0]), float(start[1])) self.rb_start.setCenter(start_point) end_point = QgsPoint(float(end[0]), float(end[1])) self.rb_end.setCenter(end_point) # Create line line_pts = [start_point, end_point] line_geom = QgsGeometry().fromPolyline(line_pts) self.rb_line.setToGeometry(line_geom, None) def remove(self): self.canvas.scene().removeItem(self.rb_start) self.canvas.scene().removeItem(self.rb_end) self.canvas.scene().removeItem(self.rb_line)
def showSectionsInOverview(self): # clear existing rubberbands for rb in self.sectionsRbs: self.iface.mapCanvas().scene().removeItem(rb) self.sectionsRbs = [] # add new rubberbands for id, sec in enumerate(self.WSMProj.sections): rb = QgsRubberBand(self.iface.mapCanvas(), False) rb_geom = QgsGeometry() rb_geom.fromWkb(sec.aoi) rb.setToGeometry(rb_geom, None) if id == self.currbox.value(): fc = QtGui.QColor(self.colors[-1]) else: fc = QtGui.QColor(self.colors[min(sec.status, 1)]) rb.setColor(fc) fc.setAlpha(128) rb.setFillColor(fc) rb.setWidth(1) self.sectionsRbs.append(rb)
class GeometryDisplayer: def __init__(self, canvas ): self.canvas = canvas # main rubber self.rubber1 = QgsRubberBand(self.canvas) self.rubber1.setWidth(2) self.rubber1.setBorderColor(QColor("#f00")) self.rubber1.setFillColor(QColor("#ff6969")) # old geometry rubber self.rubber2 = QgsRubberBand(self.canvas) self.rubber2.setWidth(2) self.rubber2.setBorderColor(QColor("#bbb")) self.rubber2.setFillColor(QColor("#ccc")) def reset(self): self.rubber1.reset() self.rubber2.reset() def display(self, geom1, geom2 = None): """ @param geom1 base geometry (old geometry for an update) @param geom2 new geometry for an update """ if geom2 is None: bbox = geom1.boundingBox() self.rubber1.setToGeometry(geom1, None) else: bbox = geom1.boundingBox() bbox.combineExtentWith(geom2.boundingBox()) self.rubber1.setToGeometry(geom2, None) self.rubber2.setToGeometry(geom1, None) bbox.scale(1.5) self.canvas.setExtent(bbox)
def identify_all(self, complet_list, rb_list): self.rubber_band.reset() for rb in rb_list: rb.reset() for layer in complet_list['body']['data']['layersNames']: for feature in layer['ids']: points = [] list_coord = re.search('\((.*)\)', str(feature['geometry'])) coords = list_coord.group(1) polygon = coords.split(',') for i in range(0, len(polygon)): x, y = polygon[i].split(' ') point = QgsPointXY(float(x), float(y)) points.append(point) rb = QgsRubberBand(self.canvas) polyline = QgsGeometry.fromPolylineXY(points) rb.setToGeometry(polyline, None) rb.setColor(QColor(255, 0, 0, 100)) rb.setWidth(5) rb.show() rb_list.append(rb)
def highlight(self,geometry): def processEvents(): try: QtGui.qApp.processEvents() except: QtWidgets.QApplication.processEvents() highlight = QgsRubberBand(self.iface.mapCanvas(), geometry.type()) highlight.setColor(QtGui.QColor("#36AF6C")) highlight.setFillColor(QtGui.QColor("#36AF6C")) highlight.setWidth(2) highlight.setToGeometry(geometry,self.iface.mapCanvas().currentLayer()) processEvents() sleep(.1) highlight.hide() processEvents() sleep(.1) highlight.show() processEvents() sleep(.1) highlight.reset() processEvents()
def highlight(self,geometry): def processEvents(): try: qApp.processEvents() except: QApplication.processEvents() highlight = QgsRubberBand(self.canvas, geometry.type()) highlight.setColor(QColor("#36AF6C")) highlight.setFillColor(QColor("#36AF6C")) highlight.setWidth(2) highlight.setToGeometry(geometry,self.canvas.currentLayer()) processEvents() sleep(.1) highlight.hide() processEvents() sleep(.1) highlight.show() processEvents() sleep(.1) highlight.reset() processEvents()
def loadLines(self, lines, points, markers, suffix): no = self.project.readEntry("TUVIEW", "lines{0}no".format(suffix))[0] if no: no = int(no) for i in range(no): a = self.project.readEntry("TUVIEW", 'lines{0}x{1}'.format(suffix, i))[0] a = a.split('~~') b = self.project.readEntry("TUVIEW", 'lines{0}y{1}'.format(suffix, i))[0] b = b.split('~~') points.clear() for j in range(len(a)): x = float(a[j]) y = float(b[j]) point = QgsPoint(x, y) points.append(point) if i + 1 == no: marker = QgsVertexMarker(self.tuView.canvas) if suffix == 'cs': marker.setColor(Qt.red) marker.setIconSize(10) marker.setIconType(QgsVertexMarker.ICON_BOX) else: # 'q' marker.setColor(Qt.blue) marker.setIconSize(12) marker.setIconType( QgsVertexMarker.ICON_DOUBLE_TRIANGLE) marker.setCenter(QgsPointXY(point)) markers.append(marker) line = QgsRubberBand(self.tuView.canvas, False) line.setWidth(2) if suffix == 'cs': line.setColor(QColor(Qt.red)) else: # 'q' line.setColor(QColor(Qt.blue)) line.setToGeometry(QgsGeometry.fromPolyline(points), None) lines.append(line)
class DistanceDialog(QDialog, Ui_place_distance): def __init__(self, distance, canvas): QDialog.__init__(self) self.setupUi(self) self.settings = MySettings() # this is a reference, distance observation is modified in outer class self.distance = distance self.rubber = QgsRubberBand(canvas) self.rubber.setColor(self.settings.value("rubberColor")) self.rubber.setIconSize(self.settings.value("rubberSize")) self.x.setText("%.3f" % distance.point.x()) self.y.setText("%.3f" % distance.point.y()) self.observation.setValue(distance.observation) self.precision.setValue(distance.precision) self.observation.selectAll() @pyqtSignature("on_observation_valueChanged(double)") def on_observation_valueChanged(self, v): self.distance.observation = v self.rubber.setToGeometry(self.distance.geometry(), None) @pyqtSignature("on_precision_valueChanged(double)") def on_precision_valueChanged(self, v): self.distance.precision = v def accept(self): self.rubber.reset() QDialog.accept(self) def reject(self): self.rubber.reset() QDialog.reject(self) def closeEvent(self, e): self.rubber.reset()
def visible_aoi(self): # first clean all rubber bands [rubber_band.reset() for rubber_band in self.rubber_bands] [rubber_band.reset() for rubber_band in self.tmp_rubber_bands] self.rubber_bands = [] self.tmp_rubber_bands = [] if self.VisibleAOI.isChecked() and self.aoi_features is not None: for feat in self.aoi_features.getFeatures(): color = QColor("red") color.setAlpha(70) rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) rubber_band.setToGeometry(feat.geometry()) rubber_band.setColor(color) rubber_band.setWidth(3) self.rubber_bands.append(rubber_band) tmp_rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) tmp_rubber_band.setToGeometry(feat.geometry()) tmp_rubber_band.setColor(color) tmp_rubber_band.setWidth(3) tmp_rubber_band.setLineStyle(Qt.DotLine) self.tmp_rubber_bands.append(tmp_rubber_band)
class ConnectTool(QgsMapToolEmitPoint): """ Map tool to conect points """ line_complete = pyqtSignal(QgsPoint, QgsPoint) start_point = None end_point = None rubberband = None def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, canvas) def canvasMoveEvent(self, event): if self.start_point: point = self.toMapCoordinates(event.pos()) if self.rubberband: self.rubberband.reset() else: self.rubberband = QgsRubberBand(self.canvas, False) self.rubberband.setColor(QColor(Qt.red)) # set the geometry for the rubberband point = [self.start_point, point] self.rubberband.setToGeometry(QgsGeometry.fromPolyline(points), None) def canvasPressEvent(self, e): if self.end_point is None: self.start_point = self.toMapCoordinates(e.pos()) else: self.end_point = self.toMapCoordinates(e.pos()) # kill the rubberband self.rubberband.reset() # line is done, emit a signal self.line_complete.emit(self.start_point, self.end_point) # reset the points self.start_point = None self.end_point = None
class lineTool(QgsMapTool): def __init__(self, iface, callback): QgsMapTool.__init__(self,iface.mapCanvas()) self.iface = iface self.canvas = iface.mapCanvas() self.cursor = QCursor(Qt.CrossCursor) self.callback = callback self.rubberBand = QgsRubberBand(self.canvas, False) self.points = [] self.rubberBand.setColor(Qt.red) self.rubberBand.setWidth(1.6) def canvasReleaseEvent(self,event): if event.button() == Qt.RightButton: self.points.append(QgsPoint( self.toMapCoordinates( event.pos()) ) ) if len(self.points) <= 1 :return self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None ) self.callback( self.rubberBand ) QgsMapTool.deactivate(self) else: self.points.append(QgsPoint( self.toMapCoordinates(event.pos()) ) ) if len(self.points) <= 1 : return self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None ) def canvasDoubleClickEvent(self,event): self.points.append(QgsPoint( self.toMapCoordinates( event.pos()) )) if len(self.points) <= 1 : return self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None ) self.callback( self.rubberBand ) QgsMapTool.deactivate(self) def activate(self): QgsMapTool.activate(self) self.canvas.setCursor(self.cursor) def isZoomTool(self): return False def setCursor(self,cursor): self.cursor = QCursor(cursor)
class GeometryDisplayer: def __init__(self, canvas): self.canvas = canvas # main rubber self.rubber1 = QgsRubberBand(self.canvas) self.rubber1.setWidth(2) self.rubber1.setStrokeColor(self.newGeometryColor()) self.rubber1.setFillColor(self.newGeometryColor()) # old geometry rubber self.rubber2 = QgsRubberBand(self.canvas) self.rubber2.setWidth(2) self.rubber2.setStrokeColor(self.oldGeometryColor()) self.rubber2.setFillColor(self.oldGeometryColor()) def reset(self): self.rubber1.reset() self.rubber2.reset() def oldGeometryColor(self): return QColor("#ff5733") def newGeometryColor(self): return QColor("#00f") def display(self, geom1, geom2=None): """ @param geom1 base geometry (old geometry for an update) @param geom2 new geometry for an update """ if geom2 is None: bbox = geom1.boundingBox() self.rubber1.setToGeometry(geom1, None) else: bbox = geom1.boundingBox() bbox.combineExtentWith(geom2.boundingBox()) self.rubber1.setToGeometry(geom2, None) self.rubber2.setToGeometry(geom1, None) bbox.scale(1.5) self.canvas.setExtent(bbox)
class nominatim_dlg(QDockWidget, Ui_search): def getHttp(self, uri, params): QgsApplication.setOverrideCursor(Qt.WaitCursor) try: rq = QUrl(uri) q = QUrlQuery() for (k, v) in params.items(): q.addQueryItem(k, v) rq.setQuery(q) req = QNetworkRequest(rq) try: reply = self.nominatim_networkAccessManager.blockingGet(req) resource = reply.content().data().decode('utf8') r = json.loads(resource) if (isinstance(r, list)): self.populateTable(r) else: self.populateTable([r]) except: self.tableResult.clearContents() finally: QgsApplication.restoreOverrideCursor() def searchJson(self, params, user, options, options2): contents = str(options).strip() items = contents.split(' ') for (k, v) in options2.items(): if k in ['viewbox']: params["bounded"] = "1" params[k] = v pairs = [] for item in items: pair = item.split('=', 1) if (pair != [''] and pair != [] and len(pair) > 1): pairs.append(pair) for (k, v) in pairs: if k in ['viewbox', 'countrycodes', 'limit', 'exclude_place_ids', 'addressdetails', 'exclude_place_ids', 'bounded', 'routewidth', 'osm_type', 'osm_id'] and not(k in options2.keys()): params[k] = v if k in ['viewbox']: params["bounded"] = "1" params["polygon_text"] = "1" params["format"] = "json" uri = 'https://nominatim.openstreetmap.org/search' self.getHttp(uri, params) def findNearbyJSON(self, params, user, options): uri = "https://nominatim.openstreetmap.org/reverse" params["format"] = "json" self.getHttp(uri, params) """ Gestion de l'évènement "leave", afin d'effacer l'objet sélectionné en sortie du dock """ def eventFilter(self, obj, event): typ = event.type() if typ == event.Leave: try: self.plugin.canvas.scene().removeItem(self.rubber) except: pass return False def __init__(self, parent, plugin): self.plugin = plugin QDockWidget.__init__(self, parent) self.setupUi(self) self.btnApply.setIcon(QIcon(":plugins/nominatim/arrow_green.png")) self.btnMask.setIcon(QIcon(":plugins/nominatim/add_mask.png")) self.btnLayer.setIcon(QIcon(":plugins/nominatim/add_layer.png")) self.tableResult.installEventFilter(self) # cf. eventFilter method self.tableResult.cellDoubleClicked.connect(self.onChoose) self.tableResult.cellEntered.connect(self.cellEntered) self.editSearch.returnPressed.connect(self.onReturnPressed) self.btnSearch.clicked.connect(self.onReturnPressed) self.btnApply.clicked.connect(self.onApply) self.btnHelp.clicked.connect(self.plugin.do_help) self.btnLocalize.clicked.connect(self.doLocalize) self.btnMask.clicked.connect(self.onMask) self.btnLayer.clicked.connect(self.onLayer) self.MultiPolygonLayerId = None self.LineLayerId = None self.PointLayerId = None try: self.cbExtent.setChecked(self.plugin.limitSearchToExtent) except: self.cbExtent.setChecked(self.plugin.limitSearchToExtent) self.currentExtent = self.plugin.canvas.extent() self.tableResult.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) try: self.editSearch.setText(self.plugin.lastSearch) except: pass try: if self.plugin.localiseOnStartup: self.doLocalize() except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass self.nominatim_networkAccessManager = QgsNetworkAccessManager.instance() def cellEntered(self, row, col): item = self.tableResult.item(row, 0) try: self.plugin.canvas.scene().removeItem(self.rubber) self.showItem(item) except: pass def onLayer(self): for r in self.tableResult.selectedRanges(): item = self.tableResult.item(r.topRow(), 0) self.doLayer(item) def onMask(self): for r in self.tableResult.selectedRanges(): item = self.tableResult.item(r.topRow(), 0) self.doMask(item) def populateRow(self, item, idx): id = item['place_id'] name = item['display_name'] try: className = QApplication.translate("nominatim", item['class'], None) except: className = "" try: typeName = QApplication.translate("nominatim", item['type'], None) except: typeName = "" try: wkt = item['geotext'] except: wkt = None try: osm_type = item['osm_type'] except: osm_type = None bbox = {} if osm_type == "node": lat = item['lat'] lng = item['lon'] poFD = ogr.FeatureDefn("Point") poFD.SetGeomType(ogr.wkbPoint) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) wkt = "POINT("+str(lng)+" "+str(lat)+")" ogrGeom = ogr.CreateGeometryFromWkt(wkt) else: try: bbox = item['boundingbox'] poFD = ogr.FeatureDefn("Rectangle") poFD.SetGeomType(ogr.wkbPolygon) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) if wkt is None: wkt = "POLYGON(("+str(bbox[2])+" "+str(bbox[0])+", "+str(bbox[2])+" " +\ str(bbox[1])+", "+str(bbox[3])+" "+str(bbox[1])+", "+str(bbox[3])+" " +\ str(bbox[0])+", "+str(bbox[2])+" "+str(bbox[0])+"))" ogrGeom = ogr.CreateGeometryFromWkt(wkt) except: lat = item['lat'] lng = item['lon'] poFD = ogr.FeatureDefn("Point") poFD.SetGeomType(ogr.wkbPoint) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) wkt = "POINT("+str(lng)+" "+str(lat)+")" ogrGeom = ogr.CreateGeometryFromWkt(wkt) mapCrsWKT = self.plugin.canvas.mapSettings().destinationCrs().toWkt() sourceSRS = osr.SpatialReference() sourceSRS.ImportFromEPSG(4326) targetSRS = osr.SpatialReference() targetSRS.ImportFromWkt(str(mapCrsWKT)) trsf = osr.CoordinateTransformation(sourceSRS, targetSRS) try: ogrGeom.Transform(trsf) except TypeError as e: QgsMessageLog.logMessage("Nominatim - transformation error. Check map projection.", "Extensions") ogrFeature.SetGeometry(ogrGeom) ogrFeature.SetFID(int(idx+1)) ogrFeature.SetField(str('id'), str(id)) ogrFeature.SetField(str('name'), name) item = QTableWidgetItem(name) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) item.setData(Qt.UserRole, ogrFeature) self.tableResult.setItem(idx, 0, item) itemLibelle = QTableWidgetItem(className) itemLibelle.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableResult.setItem(idx, 1, itemLibelle) itemType = QTableWidgetItem(typeName) itemType.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableResult.setItem(idx, 2, itemType) def populateTable(self, r): idx = 0 self.tableResult.clearContents() self.tableResult.setRowCount(len(r)) for item in r: self.populateRow(item, idx) idx = idx+1 def doLocalize(self): try: # center bbox = self.plugin.canvas.extent() sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem() targetCrs.createFromSrid(4326) xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) bbox = xform.transform(bbox) params = {"lon": str(bbox.center().x()), "lat": str(bbox.center().y()), "zoom": "10"} self.findNearbyJSON(params, self.plugin.gnUsername, self.plugin.gnOptions) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass def onReturnPressed(self): try: txt = self.editSearch.text().strip() self.plugin.lastSearch = self.editSearch.text() self.plugin.limitSearchToExtent = (self.cbExtent.isChecked()) options = self.plugin.gnOptions options2 = {} if self.plugin.limitSearchToExtent: sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem() targetCrs.createFromSrid(4326) xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) geom = xform.transform(self.plugin.canvas.extent()) options2 = {'viewbox': str(geom.xMinimum()) + ',' + str(geom.yMaximum()) + ',' + str(geom.xMaximum()) + ',' + str(geom.yMinimum())} params = {'q': txt, 'addressdetails': '0'} self.searchJson(params, self.plugin.gnUsername, options, options2) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass def onChoose(self, row, col): item = self.tableResult.item(row, 0) self.go(item) def onApply(self): for item in self.tableResult.selectedItems(): self.go(item) break def getBBox(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) if (ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint): mapextent = self.plugin.canvas.extent() ww = mapextent.width()/100 mapcrs = self.plugin.canvas.mapSettings().destinationCrs() x = geom.boundingBox().center().x() y = geom.boundingBox().center().y() ww = 50.0 if mapcrs.mapUnits() == QgsUnitTypes.DistanceFeet: ww = 150 if mapcrs.mapUnits() == QgsUnitTypes.DistanceDegrees: ww = 0.0005 bbox = QgsRectangle(x-10*ww, y-10*ww, x+10*ww, y+10*ww) return bbox else: bbox = geom.boundingBox() rubberRect = QgsRectangle(bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum()) return rubberRect def showItem(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) if (ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint): self.rubber = QgsRubberBand(self.plugin.canvas, QgsWkbTypes.PointGeometry) self.rubber.setColor(QColor(50, 50, 255, 100)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(2) self.rubber.setToGeometry(geom, None) else: # dont show if it is larger than the canvas if self.plugin.canvas.extent().contains(geom.boundingBox()): pass else: geom = geom.intersection(QgsGeometry.fromRect(self.plugin.canvas.extent())) self.rubber = QgsRubberBand(self.plugin.canvas, QgsWkbTypes.PolygonGeometry) self.rubber.setColor(QColor(50, 50, 255, 100)) self.rubber.setWidth(4) self.rubber.setToGeometry(geom, None) def go(self, item, zoom=True): try: self.plugin.canvas.scene().removeItem(self.rubber) except: pass if zoom: bbox = self.getBBox(item) self.plugin.canvas.setExtent(bbox) self.plugin.canvas.refresh() self.showItem(item) def doMask(self, item): mapcrs = self.plugin.canvas.mapSettings().destinationCrs() ogrFeature = item.data(Qt.UserRole) layerName = "OSM "+ogrFeature.GetFieldAsString('id') geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) if (geom.type() == QgsWkbTypes.PolygonGeometry): try: try: from mask import aeag_mask except: from mask_plugin import aeag_mask aeag_mask.do(mapcrs, {geom}, "Mask "+layerName) except: geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) toCrs = self.plugin.canvas.mapSettings().destinationCrs() l = max(geom.boundingBox().width(), geom.boundingBox().height()) x = geom.boundingBox().center().x() y = geom.boundingBox().center().y() rect = QgsRectangle(x-l, y-l, x+l, y+l) # geom.boundingBox() rect.scale(4) mask = QgsGeometry.fromRect(rect) mask = mask.difference(geom) maskLayer = QgsVectorLayer("MultiPolygon", "Mask "+layerName, "memory") maskLayer.setCrs(toCrs) QgsProject.instance().addMapLayer(maskLayer) pr = maskLayer.dataProvider() fields = QgsFields() fields.append(QgsField("id", QVariant.String)) fields.append(QgsField("name", QVariant.String)) fet = QgsFeature() fet.initAttributes(2) fet.setGeometry(mask) fet.setFields(fields) fet.setAttribute("id", (ogrFeature.GetFieldAsString('id'))) fet.setAttribute("name", (ogrFeature.GetFieldAsString('name'))) pr.addAttributes(fields.toList()) maskLayer.startEditing() pr.addFeatures([fet]) maskLayer.commitChanges() maskLayer.updateExtents() # transparence, epaisseur renderer = maskLayer.renderer() s = renderer.symbol() s.setOpacity(0.90) s.setColor(QColor(255, 255, 255)) if isinstance(s, QgsLineSymbol): s.setWidth(0) layerTree = QgsProject.instance().layerTreeRoot().findLayer(maskLayer) if layerTree: self.plugin.iface.layerTreeView().layerTreeModel()\ .refreshLayerLegend(layerTree) # Refresh legend self.go(item) def doLayer(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) fields = QgsFields() fields.append(QgsField("id", QVariant.String)) fields.append(QgsField("name", QVariant.String)) fet = QgsFeature() fet.initAttributes(2) fet.setFields(fields) fet.setGeometry(geom) fet.setAttribute("id", (ogrFeature.GetFieldAsString('id'))) fet.setAttribute("name", (ogrFeature.GetFieldAsString('name'))) vl = None if not self.plugin.singleLayer: if geom.type() == QgsWkbTypes.PolygonGeometry: layerName = "OSMPlaceSearch Polygon" layerId = self.MultiPolygonLayerId if geom.type() == QgsWkbTypes.LineGeometry: layerName = "OSMPlaceSearch Line" layerId = self.LineLayerId if geom.type() == QgsWkbTypes.PointGeometry: layerName = "OSMPlaceSearch Point" layerId = self.PointLayerId vl = QgsProject.instance().mapLayer(layerId) if vl is not None: pr = vl.dataProvider() else: if geom.type() == QgsWkbTypes.PolygonGeometry: vl = QgsVectorLayer("MultiPolygon", layerName, "memory") self.MultiPolygonLayerId = vl.id() if geom.type() == QgsWkbTypes.LineGeometry: vl = QgsVectorLayer("MultiLineString", layerName, "memory") self.LineLayerId = vl.id() if geom.type() == QgsWkbTypes.PointGeometry: vl = QgsVectorLayer("Point", layerName, "memory") self.PointLayerId = vl.id() if vl is not None: pr = vl.dataProvider() # ajout de champs pr.addAttributes(fields.toList()) QgsProject.instance().addMapLayer(vl) else: layerName = "OSM "+ogrFeature.GetFieldAsString('id') # creer une nouvelle couche si n'existe pas encore if geom.type() == QgsWkbTypes.PolygonGeometry: vl = QgsVectorLayer("MultiPolygon", layerName, "memory") if geom.type() == QgsWkbTypes.LineGeometry: vl = QgsVectorLayer("MultiLineString", layerName, "memory") if geom.type() == QgsWkbTypes.PointGeometry: vl = QgsVectorLayer("Point", layerName, "memory") if vl is not None: pr = vl.dataProvider() # ajout de champs pr.addAttributes(fields.toList()) QgsProject.instance().addMapLayer(vl) if vl is not None: vl.setProviderEncoding('UTF-8') vl.startEditing() pr.addFeatures([fet]) vl.commitChanges() # mise a jour etendue de la couche vl.updateExtents() layerTree = QgsProject.instance().layerTreeRoot().findLayer(vl) if layerTree: self.plugin.iface.layerTreeView()\ .layerTreeModel().refreshLayerLegend(layerTree) # Refresh legend self.go(item, False)
class MoveTool(QgsMapToolAdvancedDigitizing): """ Map tool class to move or copy an object """ def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/move_icon.png' self.text = QCoreApplication.translate("VDLTools", "Move/Copy a feature") self.setCursor(Qt.ArrowCursor) self.__isEditing = False self.__findVertex = False self.__onMove = False self.__layer = None self.__confDlg = None self.__lastFeatureId = None self.__selectedFeature = None self.__rubberBand = None self.__rubberSnap = None self.__newFeature = None self.__selectedVertex = None def activate(self): """ When the action is selected """ QgsMapToolAdvancedDigitizing.activate(self) if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) def deactivate(self): """ When the action is deselected """ self.__cancel() QgsMapToolAdvancedDigitizing.deactivate(self) def toolName(self): """ To get the tool name :return: tool name """ return QCoreApplication.translate("VDLTools", "Move/Copy") def startEditing(self): """ To set the action as enable, as the layer is editable """ self.action().setEnabled(True) Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer.editingStopped.connect(self.stopEditing) def stopEditing(self): """ To set the action as disable, as the layer is not editable """ self.action().setEnabled(False) Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def __cancel(self): """ To cancel used variables """ if self.__rubberBand is not None: self.canvas().scene().removeItem(self.__rubberBand) self.__rubberBand.reset() self.__rubberBand = None if self.__rubberSnap is not None: self.canvas().scene().removeItem(self.__rubberSnap) self.__rubberSnap.reset() self.__rubberSnap = None self.__isEditing = False self.__findVertex = False self.__onMove = False self.__lastFeatureId = None self.__selectedFeature = None self.__confDlg = None self.__newFeature = None self.__selectedVertex = None self.__layer.removeSelection() if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) def __removeLayer(self): """ To remove the current working layer """ if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = None def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None and layer.type() == QgsMapLayer.VectorLayer: if layer == self.__layer: return if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = layer if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) if self.__layer.isEditable(): self.action().setEnabled(True) self.__layer.editingStopped.connect(self.stopEditing) else: self.action().setEnabled(False) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() return self.action().setEnabled(False) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() self.__removeLayer() def __pointPreview(self, point): """ To create a point geometry preview (rubberBand) :param point: new position as mapPoint """ point_v2 = GeometryV2.asPointV2(self.__selectedFeature.geometry(), self.__iface) self.__newFeature = QgsPointV2(point.x(), point.y()) self.__newFeature.addZValue(point_v2.z()) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Point) self.__rubberBand.setToGeometry(QgsGeometry(self.__newFeature.clone()), None) def __linePreview(self, point): """ To create a line geometry preview (rubberBand) :param point: new position as mapPoint """ line_v2, curved = GeometryV2.asLineV2(self.__selectedFeature.geometry(), self.__iface) vertex = QgsPointV2() line_v2.pointAt(self.__selectedVertex, vertex) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Line) dx = vertex.x() - point.x() dy = vertex.y() - point.y() if isinstance(curved, (list, tuple)): self.__newFeature = QgsCompoundCurveV2() for pos in range(line_v2.nCurves()): curve_v2 = self.__newCurve(curved[pos], line_v2.curveAt(pos), dx, dy) self.__newFeature.addCurve(curve_v2) if pos == 0: self.__rubberBand.setToGeometry(QgsGeometry(curve_v2.curveToLine()), None) else: self.__rubberBand.addGeometry(QgsGeometry(curve_v2.curveToLine()), None) else: self.__newFeature = self.__newCurve(curved, line_v2, dx, dy) self.__rubberBand.setToGeometry(QgsGeometry(self.__newFeature.curveToLine()), None) @staticmethod def __newCurve(curved, line_v2, dx, dy): """ To create a new moved line :param curved: if the line is curved :param line_v2: the original line :param dx: x translation :param dy: y translation :return: the new line """ if curved: newCurve = QgsCircularStringV2() else: newCurve = QgsLineStringV2() points = [] for pos in range(line_v2.numPoints()): x = line_v2.pointN(pos).x() - dx y = line_v2.pointN(pos).y() - dy pt = QgsPointV2(x, y) pt.addZValue(line_v2.pointN(pos).z()) points.append(pt) newCurve.setPoints(points) return newCurve def __polygonPreview(self, point): """ To create a polygon geometry preview (rubberBand) :param point: new position as mapPoint """ polygon_v2, curved = GeometryV2.asPolygonV2(self.__selectedFeature.geometry(), self.__iface) vertex = polygon_v2.vertexAt(GeometryV2.polygonVertexId(polygon_v2, self.__selectedVertex)) dx = vertex.x() - point.x() dy = vertex.y() - point.y() self.__newFeature = QgsCurvePolygonV2() self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Line) line_v2 = self.__newCurve(curved[0], polygon_v2.exteriorRing(), dx, dy) self.__newFeature.setExteriorRing(line_v2) self.__rubberBand.setToGeometry(QgsGeometry(line_v2.curveToLine()), None) for num in range(polygon_v2.numInteriorRings()): line_v2 = self.__newCurve(curved[num+1], polygon_v2.interiorRing(num), dx, dy) self.__newFeature.addInteriorRing(line_v2) self.__rubberBand.addGeometry(QgsGeometry(line_v2.curveToLine()), None) def __onConfirmCancel(self): """ When the Cancel button in Move Confirm Dialog is pushed """ self.__confDlg.reject() def __onConfirmMove(self): """ When the Move button in Move Confirm Dialog is pushed """ geometry = QgsGeometry(self.__newFeature) if not geometry.isGeosValid(): self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL, duration=0) self.__layer.changeGeometry(self.__selectedFeature.id(), geometry) self.__confDlg.accept() self.__cancel() def __onConfirmCopy(self): """ When the Copy button in Move Confirm Dialog is pushed """ geometry = QgsGeometry(self.__newFeature) if not geometry.isGeosValid(): self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL, duration=0) feature = QgsFeature(self.__layer.pendingFields()) feature.setGeometry(geometry) primaryKey = QgsDataSourceURI(self.__layer.source()).keyColumn() for field in self.__selectedFeature.fields(): if field.name() != primaryKey: feature.setAttribute(field.name(), self.__selectedFeature.attribute(field.name())) if len(self.__selectedFeature.fields()) > 0 and self.__layer.editFormConfig().suppress() != \ QgsEditFormConfig.SuppressOn: self.__iface.openFeatureForm(self.__layer, feature) else: self.__layer.addFeature(feature) self.__confDlg.accept() self.__cancel() def keyReleaseEvent(self, event): """ When keyboard is pressed :param event: keyboard event """ if event.key() == Qt.Key_Escape: self.__cancel() def cadCanvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if type(event) == QMoveEvent: map_point = self.toMapCoordinates(event.pos()) else: map_point = event.mapPoint() if not self.__isEditing and not self.__findVertex and not self.__onMove: laySettings = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.All, 10, QgsTolerance.Pixels) f_l = Finder.findClosestFeatureAt(map_point, self.canvas(), [laySettings]) if f_l is not None and self.__lastFeatureId != f_l[0].id(): self.__lastFeatureId = f_l[0].id() self.__layer.setSelectedFeatures([f_l[0].id()]) if f_l is None: self.__layer.removeSelection() self.__lastFeatureId = None elif self.__findVertex: if self.__rubberBand is not None: self.__rubberBand.reset() closest = self.__selectedFeature.geometry().closestVertex(map_point) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__rubberBand.setToGeometry(QgsGeometry().fromPoint(closest[0]), None) elif self.__onMove: if self.__rubberBand is not None: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(map_point) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(map_point) else: self.__pointPreview(map_point) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setWidth(2) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(8) if self.__rubberSnap is not None: self.__rubberSnap.reset() else: self.__rubberSnap = QgsRubberBand(self.canvas(), QGis.Point) self.__rubberSnap.setColor(color) self.__rubberSnap.setWidth(2) self.__rubberSnap.setIconSize(20) match = Finder.snap(map_point, self.canvas()) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasVertex(): if match.layer(): self.__rubberSnap.setIcon(4) else: self.__rubberSnap.setIcon(1) if match.hasEdge(): intersection = Finder.snapCurvedIntersections(point, self.canvas(), self) if intersection is not None: self.__rubberSnap.setIcon(1) point = intersection else: self.__rubberSnap.setIcon(3) self.__rubberSnap.setToGeometry(QgsGeometry().fromPoint(point), None) def cadCanvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ if not self.__isEditing and not self.__findVertex and not self.__onMove: found_features = self.__layer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) return self.__selectedFeature = found_features[0] if self.__layer.geometryType() != QGis.Point: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Select vertex for moving (ESC to undo)"), level=QgsMessageBar.INFO, duration=3) self.__findVertex = True self.setMode(self.CaptureLine) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Point) else: self.setMode(self.CaptureNone) self.__onMove = True elif self.__findVertex: self.__findVertex = False self.setMode(self.CaptureNone) closest = self.__selectedFeature.geometry().closestVertex(event.mapPoint()) self.__selectedVertex = closest[1] self.__onMove = True elif self.__onMove: self.__onMove = False mapPoint = event.mapPoint() match = Finder.snap(event.mapPoint(), self.canvas()) if match.hasVertex() or match.hasEdge(): mapPoint = match.point() if match.hasEdge(): intersection = Finder.snapCurvedIntersections(mapPoint, self.canvas(), self) if intersection is not None: mapPoint = intersection self.__isEditing = True if self.__rubberBand is not None: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(mapPoint) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(mapPoint) else: self.__pointPreview(mapPoint) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setWidth(2) self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__confDlg = MoveConfirmDialog() self.__confDlg.rejected.connect(self.__cancel) self.__confDlg.moveButton().clicked.connect(self.__onConfirmMove) self.__confDlg.copyButton().clicked.connect(self.__onConfirmCopy) self.__confDlg.cancelButton().clicked.connect(self.__onConfirmCancel) self.__confDlg.show()
class QgepMapToolConnectNetworkElements(QgsMapTool): """ This map tool connects wastewater networkelements. It works on two lists of layers: source layers with fields with a foreign key to a networkelement target layers which depict networkelements (reaches and network nodes) The tool will snap to source layers first and once one is chosen to a target layer. It will then ask which field(s) should be connected and perform the update on the database """ def __init__(self, iface, action): QgsMapTool.__init__(self, iface.mapCanvas()) self.iface = iface self.action = action self.rbline = QgsRubberBand(self.iface.mapCanvas(), QGis.Line) self.rbline.setColor(QColor('#f4530e')) self.rbline.setWidth(3) self.rbmarkers = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.rbmarkers.setColor(QColor('#f4530e')) self.rbmarkers.setIconSize(6) self.source_snapper = QgepAreaSnapper(self.iface.mapCanvas()) self.target_snapper = QgepAreaSnapper(self.iface.mapCanvas()) self.source_feature = QgsFeature() self.rb_source_feature = QgsRubberBand(self.iface.mapCanvas()) self.rb_source_feature.setColor(QColor('#f49e79')) self.rb_source_feature.setWidth(3) self.target_feature = QgsFeature() self.rb_target_feature = QgsRubberBand(self.iface.mapCanvas()) self.rb_target_feature.setColor(QColor('#f49e79')) self.rb_target_feature.setWidth(3) def activate(self): """ Called by QGIS whenever the tool is activated. """ source_snap_layers = list() target_snap_layers = list() # A dict of layers and the fields that are foreign keys # pointing to wastewater networkelements self.network_element_sources = { QgepLayerManager.layer('vw_qgep_reach'): [ ('rp_to_fk_wastewater_networkelement', QCoreApplication.translate('QgepMapToolConnectNetworkElements', 'Reach Point To')), ('rp_from_fk_wastewater_networkelement', QCoreApplication.translate('QgepMapToolConnectNetworkElements', 'Reach Point From')) ], QgepLayerManager.layer('od_catchment_area'): [ ('fk_wastewater_networkelement_rw_current', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Rainwater current')), ('fk_wastewater_networkelement_rw_planned', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Rainwater planned')), ('fk_wastewater_networkelement_ww_current', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Wastewater current')), ('fk_wastewater_networkelement_ww_planned', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Wastewater planned')) ] } # A list of layers that can be used as wastewater networkelement # targets self.network_element_targets = [ QgepLayerManager.layer('vw_wastewater_node'), QgepLayerManager.layer('vw_qgep_reach') ] for layer in self.network_element_sources.keys(): if layer: snap_layer = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.All, 16, QgsTolerance.Pixels) source_snap_layers.append(snap_layer) for layer in self.network_element_targets: if layer: snap_layer = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.All, 16, QgsTolerance.Pixels) target_snap_layers.append(snap_layer) self.source_snapper.setLayers(source_snap_layers) self.source_snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) self.target_snapper.setLayers(target_snap_layers) self.target_snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) self.reset() self.action.setChecked(True) self.iface.mapCanvas().setCursor(QCursor(Qt.CrossCursor)) def canvasMoveEvent(self, event): """ When the mouse moves, update the rubberbands. """ pt = event.originalMapPoint() snap_match = self.snapper.snapToMap(pt) if snap_match.isValid(): if snap_match.type() != QgsPointLocator.Area: pt = snap_match.point() self.matchpoint = pt if self.source_match: if self.target_feature.id() != snap_match.featureId(): self.target_feature = self.get_feature_for_match( snap_match) self.rb_target_feature.setToGeometry( self.target_feature.geometry(), snap_match.layer()) self.rb_target_feature.show() self.rbmarkers.movePoint(pt) else: if self.source_feature.id() != snap_match.featureId(): self.source_feature = self.get_feature_for_match( snap_match) self.rb_source_feature.setToGeometry( self.source_feature.geometry(), snap_match.layer()) self.rb_source_feature.show() self.rbmarkers.movePoint(pt, 0) self.rbmarkers.show() else: self.rbmarkers.hide() if self.source_match: self.rb_target_feature.hide() else: self.rb_source_feature.hide() self.rbline.movePoint(pt) self.snapresult = snap_match def canvasReleaseEvent(self, event): """ On a click update the rubberbands and the snapping results if it's a left click. Reset if it's a right click. """ if event.button() == Qt.LeftButton: if self.snapresult.isValid(): if self.source_match: self.connect_features(self.source_match, self.snapresult) else: self.rbline.show() self.rbline.addPoint(self.matchpoint) self.source_match = self.snapresult self.snapper = self.target_snapper else: self.reset() def deactivate(self): """ Called by QGIS whenever this tool is deactivated. """ self.reset() self.action.setChecked(False) def reset(self): """ Resets the tool to a pristine state """ self.source_match = None self.rbline.hide() self.rbline.reset() self.rbmarkers.hide() self.rbmarkers.reset(QGis.Point) self.rbmarkers.addPoint(QgsPoint()) self.snapresult = None self.source_match = None self.snapper = self.source_snapper self.source_feature = QgsFeature() self.target_feature = QgsFeature() self.rb_source_feature.reset() self.rb_target_feature.reset() def get_feature_for_match(self, match): """ Get the feature for a snapping result @param match: The QgsPointLocator.SnapMatch object @return: A feature """ return next(match.layer().getFeatures(QgsFeatureRequest().setFilterFid(match.featureId()))) def connect_features(self, source, target): """ Connects the source feature with the target feature. @param source: A QgsPointLocator.Match object. Its foreign key will be updated. A dialog will be opened which asks the user for which foreign key(s) he wants to update. @param target: A QgsPointLocator.Match object. This feature will be used as link target. Its obj_id attribute will be used as primary key. """ dlg = QDialog(self.iface.mainWindow()) dlg.setWindowTitle(self.tr('Select properties to connect')) dlg.setLayout(QFormLayout()) properties = list() for prop in self.network_element_sources[source.layer()]: cbx = QCheckBox(prop[1]) cbx.setObjectName(prop[0]) properties.append(cbx) dlg.layout().addWidget(cbx) btn_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) dlg.layout().addWidget(btn_box) btn_box.accepted.connect(dlg.accept) btn_box.rejected.connect(dlg.reject) source_feature = self.get_feature_for_match(source) target_feature = self.get_feature_for_match(target) if dlg.exec_(): for cbx in properties: if cbx.isChecked(): source_feature[cbx.objectName()] = target_feature['obj_id'] if source.layer().updateFeature(source_feature): self.iface.messageBar().pushMessage('QGEP', self.tr('Connected {} to {}').format( source_feature[ 'identifier'], target_feature['identifier']), QgsMessageBar.INFO, 5) else: self.iface.messageBar().pushMessage('QGEP', self.tr( 'Error connecting features'), QgsMessageBar.WARNING, 5) self.reset()
class MainWindow(mainwindow_widget, mainwindow_base): """ Main application window """ def __init__(self, settings): super(MainWindow, self).__init__() self.setupUi(self) self.settings = settings roam.featureform.settings = settings.settings self.canvaslayers = [] self.layerbuttons = [] self.project = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.bar = roam.messagebaritems.MessageBar(self) self.actionMap.setVisible(False) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.triggered.connect(self.updatePage) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) #TODO Extract GPS out into a service and remove UI stuff self.actionGPS = GPSAction(":/icons/gps", self.canvas, self.settings, self) self.projecttoolbar.addAction(self.actionGPS) self.projectwidget = ProjectsWidget(self) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.project_page.layout().addWidget(self.projectwidget) self.syncwidget = SyncWidget() self.syncpage.layout().addWidget(self.syncwidget) self.settingswidget = SettingsWidget(settings, self) self.settings_page.layout().addWidget(self.settingswidget) self.actionSettings.toggled.connect(self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) self.dataentrywidget.openimage.connect(self.openimage) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel("User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.stackedWidget.currentChanged.connect(self.updateUIState) self.panels = [] self.connectButtons() self.band = QgsRubberBand(self.canvas) self.band.setIconSize(20) self.band.setWidth(10) self.band.setColor(QColor(186, 93, 212, 76)) self.canvas_page.layout().insertWidget(0, self.projecttoolbar) self.dataentrymodel = QStandardItemModel(self) self.dataentrycombo = QComboBox(self.projecttoolbar) self.dataentrycombo.setIconSize(QSize(48,48)) self.dataentrycombo.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.dataentrycombo.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.dataentrycombo.setModel(self.dataentrymodel) self.dataentrycomboaction = self.projecttoolbar.insertWidget(self.topspaceraction, self.dataentrycombo) self.dataentrycombo.showPopup = self.selectdataentry self.biglist = BigList(self.canvas) self.biglist.setlabel("Select data entry form") self.biglist.setmodel(self.dataentrymodel) self.biglist.itemselected.connect(self.dataentrychanged) self.biglist.hide() self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.requestopenform.connect(self.openForm) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.resultscleared.connect(self.clearselection) self.infodock.openurl.connect(self.viewurl) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) self.projecttoolbar.toolButtonStyleChanged.connect(self.updatecombo) def selectdataentry(self, ): if self.dataentrycombo.count() == 0: return self.biglist.show() def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] except KeyError: # It's not a image so lets just pass it of as a normal # URL QDesktopServices.openUrl(url) return pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def updatecombo(self, *args): self.dataentrycombo.setMinimumHeight(0) def settingsupdated(self, settings): settings.save() self.show() self.actionGPS.updateGPSPort() # eww! roam.featureform.settings = settings.settings def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format(extent.center().toString())) def highlightselection(self, results): for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 150)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def clearselection(self): # Clear the main selection rubber band self.band.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() def highlightfeature(self, layer, feature, features): self.clearselection() self.highlightselection({layer: features}) self.band.setToGeometry(feature.geometry(), layer) def showmap(self): self.actionMap.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def dataentrychanged(self, index): wasactive = self.clearCapatureTools() if not index.isValid(): return modelindex = index # modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) self.dataentrycombo.setCurrentIndex(index.row()) self.createCaptureButtons(form, wasactive) def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError('Seems something has gone wrong. Press for more details', info) def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24,24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = TouchMapTool(self.canvas) self.moveTool = MoveTool(self.canvas, []) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionMove, self.moveTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(self.showInfoResults) # The edit toolbutton is currently not being used but leaving it for feature. self.moveTool.layersupdated.connect(self.actionMove.setEnabled) self.moveTool.layersupdated.connect(self.actionEdit_Tools.setEnabled) self.actionGPSFeature.triggered.connect(self.addFeatureAtGPS) self.actionGPSFeature.setEnabled(self.actionGPS.isConnected) self.actionGPS.gpsfixed.connect(self.actionGPSFeature.setEnabled) self.actionHome.triggered.connect(self.homeview) self.actionQuit.triggered.connect(self.exit) def showToolError(self, label, message): self.bar.pushMessage(label, message, QgsMessageBar.WARNING) def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def createCaptureButtons(self, form, wasselected): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) if action.isdefault: action.setChecked(wasselected) if hasattr(tool, 'geometryComplete'): add = partial(self.addNewFeature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showToolError, form.label)) self.projecttoolbar.insertAction(self.topspaceraction, self.actionGPSFeature) self.actionGPSFeature.setVisible(not tool.isEditTool()) def createFormButtons(self, forms): """ Create buttons for each form that is defined """ self.dataentrymodel.clear() self.clearCapatureTools() def captureFeature(form): item = QStandardItem(QIcon(form.icon), form.icontext) item.setData(form, Qt.UserRole + 1) item.setSizeHint(QSize(item.sizeHint().width(), self.projecttoolbar.height())) self.dataentrymodel.appendRow(item) capabilitityhandlers = {"capture": captureFeature} failedforms = [] for form in forms: valid, reasons = form.valid if not valid: roam.utils.log("Form is invalid for data entry because {}".format(reasons)) failedforms.append((form, reasons)) continue for capability in form.capabilities: try: capabilitityhandlers[capability](form) except KeyError: # Just ignore capabilities we don't support yet. continue if failedforms: for form, reasons in failedforms: html = "<h3>{}</h3><br>{}".format(form.label, "<br>".join(reasons)) self.bar.pushMessage("Form errors", "Looks like some forms couldn't be loaded", level=QgsMessageBar.WARNING, extrainfo=html) visible = self.dataentrymodel.rowCount() > 0 self.dataentrycomboaction.setVisible(visible) self.dataentrycombo.setMinimumHeight(self.projecttoolbar.height()) index = self.dataentrymodel.index(0, 0) self.dataentrychanged(index) def addFeatureAtGPS(self): """ Add a record at the current GPS location. """ index = self.dataentrycombo.currentIndex() modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) point = self.actionGPS.position point = QgsGeometry.fromPoint(point) self.addNewFeature(form=form, geometry=point) def clearToolRubberBand(self): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def showhelp(self, url): help = HelpPage(self.stackedWidget) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuredeleted(self): self.dataentryfinished() self.bar.pushMessage("Deleted", "Feature Deleted", QgsMessageBar.INFO, 1) self.canvas.refresh() def featureSaved(self): self.dataentryfinished() self.canvas.refresh() def failSave(self, messages): self.bar.pushError("Error when saving changes.", messages) def cleartempobjects(self): self.band.reset() self.clearToolRubberBand() def formrejected(self, message, level): self.dataentryfinished() if message: self.bar.pushMessage("Form Message", message, level, duration=2) self.cleartempobjects() def openForm(self, form, feature): """ Open the form that is assigned to the layer """ self.band.setToGeometry(feature.geometry(), form.QGISLayer) self.showdataentry() self.dataentrywidget.openform(feature=feature, form=form, project=self.project) def addNewFeature(self, form, geometry): """ Add a new new feature to the given layer """ layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name() == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value self.openForm(form, feature) def exit(self): """ Exit the application. """ QApplication.exit(0) def showInfoResults(self, results): self.infodock.clearResults() forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.infodock.setResults(results, forms) self.infodock.show() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = self.settings.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) def updateUIState(self, page): """ Update the UI state to reflect the currently selected page in the stacked widget """ pass @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) self.canvas.updateScale() self.projectOpened() self.canvas.freeze(False) self.canvas.refresh() self.showmap() @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) self.createFormButtons(forms=self.project.forms) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) # TODO Abstract this out if not self.project.selectlayers: selectionlayers = QgsMapLayerRegistry.instance().mapLayers().values() else: selectionlayers = [] for layername in self.project.selectlayers: try: layer = QgsMapLayerRegistry.instance().mapLayersByName(layername)[0] except IndexError: roam.utils.warning("Can't find QGIS layer for select layer {}".format(layername)) continue selectionlayers.append(layer) self.infoTool.selectionlayers = selectionlayers self.actionPan.trigger() #noinspection PyArgumentList @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.closeProject() self.canvas.refresh() self.canvas.repaint() self.infodock.clearResults() # No idea why we have to set this each time. Maybe QGIS deletes it for # some reason. self.badLayerHandler = BadLayerHandler(callback=self.missingLayers) QgsProject.instance().setBadLayerHandler(self.badLayerHandler) self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format(project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def closeProject(self): """ Close the current open project """ self.canvas.freeze() QgsMapLayerRegistry.instance().removeAllMapLayers() self.canvas.clear() self.canvas.freeze(False) for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons for action in self.layerbuttons: self.editgroup.removeAction(action) self.dataentrymodel.clear() self.panels = [] self.project = None self.dataentrywidget.clear() self.hidedataentry() self.infodock.close()
class ProfiletoolMapTool(QgsMapTool): # Signals sig_clearMap = pyqtSignal() sig_createProfile = pyqtSignal() sig_changeCoord = pyqtSignal(QgsPointXY, str) def __init__(self, canvas, drawLineButton, showProfileButton): #buttonShowProf QgsMapTool.__init__(self, canvas) self.canvas = canvas self.cursor = QCursor(Qt.CrossCursor) # Red line self.rubberband = QgsRubberBand(self.canvas) self.rubberband.setWidth(3) self.rubberband.setColor(QColor(231, 28, 35)) # Buttons from main dialog self.drawLineButton = drawLineButton self.buttonShowProf = showProfileButton # Coordinates of drawn line points self.pointsToDraw = [] # Temporary save double clicks self.dblclktemp = None # Drawn line geometry self.drawnLine = None # Point markers on each end of the line self.markers = [] # Backup the last active Tool before the pofile tool became active self.savedTool = self.canvas.mapTool() def drawLine(self): # Emit signal that clears map and deletes profile self.sig_clearMap.emit() self.reset() self.canvas.setMapTool(self) # runs function self.activate() def activate(self): self.canvas.setCursor(self.cursor) def deactivate(self): self.canvas.setCursor(QCursor(Qt.OpenHandCursor)) self.pointsToDraw = [] # Stop pressing down button self.drawLineButton.setChecked(False) def reset(self): self.removeStueMarker() self.canvas.setMapTool(self.savedTool) self.rubberband.reset() self.pointsToDraw = [] self.dblclktemp = None self.drawnLine = None def canvasMoveEvent(self, event): if len(self.pointsToDraw) > 0: self.rubberband.reset() line = [self.pointsToDraw[0], event.mapPoint()] self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(line), None) def canvasReleaseEvent(self, event): mapPos = event.mapPoint() if mapPos == self.dblclktemp: self.dblclktemp = None return else: # Mark point with marker symbol self.drawStueMarker(mapPos) # Klick ist first point of line if len(self.pointsToDraw) == 0: self.rubberband.reset() self.pointsToDraw.append(mapPos) return # Klick is second point of line elif len(self.pointsToDraw) == 1: self.pointsToDraw.append(mapPos) self.removeStueMarker() self.dblclktemp = mapPos self.drawnLine = self.createDigiFeature(self.pointsToDraw) self.sig_changeCoord.emit(self.pointsToDraw[0], 'A') self.sig_changeCoord.emit(self.pointsToDraw[1], 'E') self.canvas.setMapTool(self.savedTool) # self.deactivate() def setCursor(self, cursor): self.cursor = cursor def updateLine(self, points): self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(points), None) self.drawnLine = self.createDigiFeature(points) self.drawStueMarker(points[0]) self.drawStueMarker(points[1]) def drawStueMarker(self, point): marker = QgsStueMarker(self.canvas) marker.setCenter(point) self.markers.append(marker) self.canvas.refresh() def removeStueMarker(self, position=-1): if position >= 0: marker = self.markers[position] self.canvas.scene().removeItem(marker) self.markers.pop(position) else: for marker in self.markers: self.canvas.scene().removeItem(marker) self.markers = [] self.canvas.refresh() @staticmethod def createDigiFeature(pnts): line = QgsGeometry.fromPolylineXY(pnts) qgFeat = QgsFeature() qgFeat.setGeometry(line) return qgFeat
class osmSearchDialog(QDockWidget , Ui_osmSearch ): def __init__(self,iface): self.iface = iface QDockWidget.__init__(self) self.setupUi(self) self.iface.addDockWidget(Qt.BottomDockWidgetArea,self) self.canvas = self.iface.mapCanvas() self.rb = QgsRubberBand(self.canvas, QGis.Point) self.rb.setColor(QColor( 255, 0, 0, 150 )) self.searchCacheLimit = 1000 self.wgs84 = QgsCoordinateReferenceSystem() self.wgs84.createFromSrid(4326) self.proj = self.canvas.mapRenderer().destinationCrs() self.transform = QgsCoordinateTransform(self.wgs84, self.proj) self.bSearch.clicked.connect(self.startSearch) self.eOutput.currentItemChanged.connect(self.itemChanged) self.eOutput.clickedOutsideOfItems.connect(self.itemChanged) self.eText.cleared.connect(self.clearEdit) self.canvas.mapRenderer().destinationSrsChanged.connect(self.crsChanged) self.iface.newProjectCreated.connect(self.clearEdit) self.iface.projectRead.connect(self.clearEdit) self.cbCenter.stateChanged.connect(self.autocenter) db = cacheDB() self.autocompleteList = db.getAutocompleteList() db.closeConnection() self.completer = QCompleter(self.autocompleteList) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.eText.setCompleter(self.completer) def startSearch(self): text = self.eText.text().encode('utf-8') if text == "": self.clearEdit() #url = 'http://open.mapquestapi.com/nominatim/v1/search.php' url = 'http://nominatim.openstreetmap.org/search' params = urllib.urlencode({'q': text,'format': 'json','polygon_text':'1'}) response = json.load(urllib2.urlopen(url+'?'+params)) self.loadData(response) def loadData(self, data): self.rb.reset(QGis.Point) self.eOutput.clear() items = [] for d in data: try: geometry = d['geotext'] except KeyError: geometry = 'POINT(%s %s)' % (d['lon'], d['lat']) item = QTreeWidgetItem([d['display_name'], d['type']]) item.setData(0, Qt.UserRole, geometry) if geometry.lower().startswith('point'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconPointLayer.svg')) elif geometry.lower().startswith('linestring'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconLineLayer.svg')) elif geometry.lower().startswith('polygon'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconPolygonLayer.svg')) items.append(item) if items: self.eOutput.insertTopLevelItems(0, items) self.addSearchTerm(unicode(self.eText.text().lower())) else: self.iface.messageBar().pushMessage('Nothing was found!', QgsMessageBar.CRITICAL, 2) def itemChanged(self, current=None, previous=None): if current: wkt = str(current.data(0,Qt.UserRole)) geom = QgsGeometry.fromWkt(wkt) if self.proj.srsid() != 4326: try: geom.transform(self.transform) except: self.iface.messageBar().pushMessage('CRS transformation error!', QgsMessageBar.CRITICAL, 2) self.rb.reset(QGis.Point) return self.rb.setToGeometry(geom, None) if self.cbCenter.isChecked(): self.moveCanvas(geom.centroid().asPoint(), self.canvas.extent()) else: self.rb.reset(QGis.Point) self.eOutput.setCurrentItem(None) def crsChanged(self): self.proj = self.canvas.mapRenderer().destinationCrs() self.transform = QgsCoordinateTransform(self.wgs84, self.proj) def clearEdit(self): self.eOutput.clear() self.eText.clear() if hasattr(self, 'rb'): self.rb.reset(QGis.Point) def setCompleter(self): self.completer.model().setStringList(self.autocompleteList) def addSearchTerm(self, text): if not text in self.autocompleteList: self.autocompleteList.append(text) self.setCompleter() while len(self.autocompleteList) > self.searchCacheLimit: self.autocompleteList.pop(0) def autocenter(self, state): if state and self.rb.size(): self.moveCanvas(self.rb.asGeometry().centroid().asPoint(), self.canvas.extent()) def moveCanvas(self, newCenter, oldExtent): newExtent = QgsRectangle(oldExtent) newExtent.scale(1, newCenter) self.canvas.setExtent(newExtent) self.canvas.refresh()
class DiviPluginHistoryDialog(QDialog, FORM_CLASS): def __init__(self, plugin, parent=None): """Constructor.""" super(DiviPluginHistoryDialog, 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.plugin = plugin #self.iface = plugin.iface self.setupUi(self) self.initGui() def initGui(self): #Models self.tblChanges.setModel( ChangeModel() ) proxyChanges = HistoryProxyModel() proxyChanges.setSourceModel( HistoryModel() ) self.tblHistory.setModel( proxyChanges ) #Signals self.plugin.tvIdentificationResult.model().sourceModel().on_history.connect( self.historyChanged ) self.tblHistory.selectionModel().currentChanged.connect( self.currentHistoryChanged ) #Widgets settings = QSettings() self.mapCanvas = QgsMapCanvas(self.vSplitter) self.mapCanvas.setDestinationCrs( QgsCoordinateReferenceSystem('EPSG:4326') ) zoomFactor = settings.value( "/qgis/zoom_factor", 2.0, type=float ) action = settings.value( "/qgis/wheel_action", 0, type=int) self.mapCanvas.setWheelFactor( zoomFactor ) self.mapCanvas.enableAntiAliasing( settings.value( "/qgis/enable_anti_aliasing", False, type=bool )) #self.mapCanvas.useImageToRender( settings.value( "/qgis/use_qimage_to_render", False, type=bool )) self.toolPan = QgsMapToolPan( self.mapCanvas ) self.mapCanvas.setMapTool( self.toolPan ) #Canvas items self.new_geometry = QgsRubberBand(self.mapCanvas) self.new_geometry.setWidth(2) self.new_geometry.setIcon( QgsRubberBand.ICON_CIRCLE ) g = QColor(0, 128, 0, 100) self.new_geometry.setColor( g ) self.old_geometry = QgsRubberBand(self.mapCanvas) self.old_geometry.setWidth(2) self.old_geometry.setIcon( QgsRubberBand.ICON_CIRCLE ) r = QColor(255, 0, 0, 100) self.old_geometry.setColor( r ) def show(self, data=[]): model = self.tblHistory.model().sourceModel() model.addItems(data) if data: self.tblHistory.selectionModel().setCurrentIndex( model.index(0,0), QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows ) super(DiviPluginHistoryDialog, self).show() def historyChanged(self): """ Reaload data if window is visible """ if self.isVisible(): self.plugin.showHistoryDialog() def currentHistoryChanged(self, current, previous): self.new_geometry.reset() self.old_geometry.reset() self.tblChanges.model().removeRows() if not current.isValid(): return item = current.data(Qt.UserRole) if item is None: data = {} else: data = current.data(Qt.UserRole).getDetails() with SetLocale_CtxDec(): extent = None if data.get('new_geometry'): wkt = CreateGeometryFromJson( json.dumps(data['new_geometry']) ).ExportToWkt() geom = QgsGeometry.fromWkt( wkt ) l = QgsVectorLayer('Point?crs=epsg:4326', 'asd', 'memory') self.new_geometry.setToGeometry( geom, l ) extent = QgsRectangle(geom.boundingBox()) if data.get('old_geometry'): wkt = CreateGeometryFromJson( json.dumps(data['old_geometry']) ).ExportToWkt() geom = QgsGeometry.fromWkt( wkt ) l = QgsVectorLayer('Point?crs=epsg:4326', 'asd', 'memory') self.old_geometry.setToGeometry( geom, l ) if extent is None: extent = QgsRectangle(geom.boundingBox()) else: extent.combineExtentWith( geom.boundingBox() ) if extent is not None: extent.grow(0.01) self.mapCanvas.setExtent( extent ) self.mapCanvas.refresh() if data.get('what_attributes', []): self.tblChanges.model().insertRows( 0, data.get('what_attributes', []) )
class DockEditorDialog(QtGui.QDockWidget, Ui_DockEditor): def __init__(self, iface, mapCanvas): self.iface = iface QtGui.QDockWidget.__init__(self) # 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.setAttribute(Qt.WA_DeleteOnClose) self.iface.addDockWidget(Qt.RightDockWidgetArea, self) self.mapCanvas = mapCanvas # rubber bands self.featureRubber = QgsRubberBand(self.mapCanvas, False) self.updateFeatureRubber() # Gui defaults self.kwaliteitsklasseCombo.setVisible(False) self.onderzochtJaarSpinBox.setVisible(False) self.hersteldJaarSpinBox.setVisible(False) self.kwaliteitsklasseLabel.setVisible(False) self.monitoringObjTekst.setVisible(False) # GUI signals connection self.actionButtonBox.button(QtGui.QDialogButtonBox.Save).clicked.connect(self.applySave) self.actionButtonBox.button(QtGui.QDialogButtonBox.Abort).clicked.connect(self.applyCancel) self.deleteButton.clicked.connect(self.applyDelete) self.newPandButton.clicked.connect(self.applyNewPand) self.idButton.clicked.connect(self.zoomToFeature) self.adresLinkButton.clicked.connect(self.showVerblijfsObj) self.verseonLinkButton.clicked.connect(self.getVerseonInfo) self.lkiLinkButton.clicked.connect(self.showLkiInfo) # force Dutch for QDialogButtonBox self.actionButtonBox.button(QtGui.QDialogButtonBox.Save).setText("Opslaan") self.actionButtonBox.button(QtGui.QDialogButtonBox.Abort).setText("Annuleer"); # enable save button when value changes self.bezitCombo.currentIndexChanged.connect(self.actionButtonBoxEnable) self.kwaliteitsklasseCombo.currentIndexChanged.connect(self.actionButtonBoxEnable) self.onderzochtCheckBox.stateChanged.connect(self.actionButtonBoxEnable) self.onderzochtJaarSpinBox.valueChanged.connect(self.actionButtonBoxEnable) self.hersteldCheckBox.stateChanged.connect(self.actionButtonBoxEnable) self.hersteldJaarSpinBox.valueChanged.connect(self.actionButtonBoxEnable) self.projectCombo.editTextChanged.connect(self.actionButtonBoxEnable) self.richtlijnCombo.editTextChanged.connect(self.actionButtonBoxEnable) self.handhavingCheckBox.stateChanged.connect(self.actionButtonBoxEnable) self.typefundCombo.editTextChanged.connect(self.actionButtonBoxEnable) self.paallengteSpinBox.valueChanged.connect(self.actionButtonBoxEnable) self.houtsoortCombo.editTextChanged.connect(self.actionButtonBoxEnable) self.dekkingSpinBox.valueChanged.connect(self.actionButtonBoxEnable) self.droogstandCheckBox.stateChanged.connect(self.actionButtonBoxEnable) self.opmerkingText.textChanged.connect(self.actionButtonBoxEnable) self.setVisible(False) def showEvent(self, e): self.newGroupBox.hide() self.editGroupBox.hide() if (getVectorLayerByName(editLayerName) == None): self.errorFrame.show() else: self.errorFrame.hide() self.editLayer = getVectorLayerByName(editLayerName) self.adresLayer = getVectorLayerByName(adresLayerName) self.geomLayer = getVectorLayerByName(geomLayerName) self.editFeature = None self.updateCombos() def closeEvent(self, e): e.ignore() self.featureRubber.reset() self.hide() def zoomToFeature(self): box = self.selectedFeature.geometry().buffer(20, 4).boundingBox() self.iface.mapCanvas().setExtent(box) self.iface.mapCanvas().refresh() def updateCombos(self): if (self.editLayer): FieldCombo(self.bezitCombo, self.editLayer, initField="bezit") FieldCombo(self.kwaliteitsklasseCombo, self.editLayer, initField="kwaliteitsklasse") FieldCombo(self.projectCombo, self.editLayer, initField="project") FieldCombo(self.richtlijnCombo, self.editLayer, initField="richtlijn") FieldCombo(self.typefundCombo, self.editLayer, initField="funderingtype") FieldCombo(self.houtsoortCombo, self.editLayer, initField="houtsoort") def actionButtonBoxEnable(self): self.actionButtonBox.setDisabled(False) def featureSelected(self, layer, feature): self.layer = layer self.selectedFeature = feature initialGeometry = QgsGeometry(feature.geometry()) self.featureRubber.reset() self.featureRubber.setToGeometry(initialGeometry, layer) self.updateGui(feature) def updateGui(self, feature): # The important part: get the feature iterator with an expression request = QgsFeatureRequest().setFilterExpression ( u'"pand_id" = \'' + unicode(feature['gebouwnummer']) + '\'' ) request.setFlags( QgsFeatureRequest.NoGeometry ) features = self.geomLayer.getFeatures( request ) atr = None fields = self.geomLayer.pendingFields() field_names = [field.name() for field in fields] for elem in features: self.editFeature = elem atr = dict(zip(field_names, elem.attributes())) if atr is not None: atr = {i:j for i,j in atr.items() if j } self.newGroupBox.hide() self.editGroupBox.show() self.verwijderWidget.show() self.showValues(feature, atr) self.actionButtonBox.setDisabled(True) else: self.newGroupBox.show() self.editGroupBox.hide() self.verwijderWidget.hide() self.editFeature = None self.statusNieuwLabel.setText(unicode(feature['status'])) self.pandidLabel.setText(unicode(feature['gebouwnummer'])) def showValues(self, feature, atr): self.deleteCheckBox.setChecked(False) self.idText.setText(unicode(atr.get("pand_id", ""))) if (feature['vboj_count'] == 1): self.adresLinkButton.setText(BagadresString().request(unicode(feature['gebouwnummer']))) else: self.adresLinkButton.setText("Pand bevat " + unicode(feature['vboj_count']) + " adres(sen)") self.setComboTekst(self.bezitCombo, atr.get("bezit", "")) if (atr.get("onderzocht", "")=="t"): self.onderzochtCheckBox.setChecked(True) self.onderzochtJaarSpinBox.setValue(atr.get("onderzocht_jaar", "")) else: self.onderzochtCheckBox.setChecked(False) self.setComboTekst(self.kwaliteitsklasseCombo, atr.get("kwaliteitsklasse", "")) if (atr.get("hersteld", "")=="t"): self.hersteldCheckBox.setChecked(True) self.hersteldJaarSpinBox.setValue(atr.get("hersteld_jaar", "")) else: self.hersteldCheckBox.setChecked(False) self.setComboTekst(self.projectCombo, atr.get("project", "")) self.setComboTekst(self.richtlijnCombo, atr.get("richtlijn", "")) self.handhavingCheckBox.setChecked(toBoolean(atr.get("fumon_monitoring", "f"))) self.monitoringObjTekst.setText(atr.get("fumon_objectcode", "")) self.setComboTekst(self.typefundCombo, atr.get("funderingtype", "")) self.paallengteSpinBox.setValue(atr.get("paallengte", 0)) self.setComboTekst(self.houtsoortCombo, atr.get("houtsoort", "")) self.dekkingSpinBox.setValue(atr.get("dekking", 0)) self.droogstandCheckBox.setChecked(toBoolean(atr.get("droogstand", "f"))) self.opmerkingText.setPlainText(atr.get("opmerking", "")) # set texts in UI featureStatus = unicode(feature['status']) featureBj = unicode(feature['bouwjaar']) self.statusText.setText(featureStatus) self.bouwjaarText.setText(featureBj) def showVerblijfsObj(self): feature = self.selectedFeature gebouwnummer = unicode(feature['gebouwnummer']) InfoBagDialog(gebouwnummer, self.iface) def getVerseonInfo(self): feature = self.selectedFeature gebouwnummer = unicode(feature['gebouwnummer']) InfoVerseonDialog(gebouwnummer, self.iface) def showLkiInfo(self): feature = self.selectedFeature wkt = feature.geometry().pointOnSurface().exportToWkt() PerceelinfoDialog(wkt, self.iface) def setComboTekst(self, combo, value): idx = combo.findText(value) combo.setCurrentIndex(idx) def updateFeatureRubber(self): self.featureRubber.setColor(featureRubberColor) self.featureRubber.setWidth(featureRubberSize) self.featureRubber.setBrushStyle(Qt.NoBrush) self.mapCanvas.refresh() def applySave(self): if not self.editLayer.isEditable(): self.editLayer.startEditing() layer = self.editLayer layer.beginEditCommand("Funderingsgegevens") try: if (self.editFeature == None): idx = layer.pendingFields().indexFromName("id") nextId = layer.maximumValue(idx) feat = QgsFeature() feat.setFields(layer.pendingFields(), True) feat.setAttribute(layer.fieldNameIndex( "pand_id" ), self.pandidLabel.text()) feat.setAttribute(layer.fieldNameIndex( "id" ), nextId + 1) layer.addFeature(feat, False) self.editFeature = feat fid = self.editFeature.id() layer.changeAttributeValue(fid, layer.fieldNameIndex( "pand_id" ), self.idText.text()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "bezit" ), self.bezitCombo.currentText()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "onderzocht" ), self.onderzochtCheckBox.isChecked()) if (self.onderzochtCheckBox.isChecked()): layer.changeAttributeValue(fid, layer.fieldNameIndex( "onderzocht_jaar" ), self.onderzochtJaarSpinBox.value()) else: layer.changeAttributeValue(fid, layer.fieldNameIndex( "onderzocht_jaar" ), None) layer.changeAttributeValue(fid, layer.fieldNameIndex( "kwaliteitsklasse" ), self.kwaliteitsklasseCombo.currentText()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "hersteld" ), self.hersteldCheckBox.isChecked()) if (self.hersteldCheckBox.isChecked()): layer.changeAttributeValue(fid, layer.fieldNameIndex( "hersteld_jaar" ), self.hersteldJaarSpinBox.value()) else: layer.changeAttributeValue(fid, layer.fieldNameIndex( "hersteld_jaar" ), None) layer.changeAttributeValue(fid, layer.fieldNameIndex( "project" ), self.projectCombo.currentText()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "richtlijn" ), self.richtlijnCombo.currentText()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "funderingtype" ), self.typefundCombo.currentText()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "paallengte" ), self.paallengteSpinBox.value()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "houtsoort" ), self.houtsoortCombo.currentText()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "dekking" ), self.dekkingSpinBox.value()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "droogstand" ), self.droogstandCheckBox.isChecked()) layer.changeAttributeValue(fid, layer.fieldNameIndex( "opmerking" ), self.opmerkingText.toPlainText()) except Exception, e: raise e layer.destroyEditCommand() self.iface.messageBar().pushMessage("Funderingsherstel", "Er is wat misgegaan tijdens het opslaan van dit BAG object!", level=QgsMessageBar.CRITICAL) else:
class addPolygon(QgsMapTool): cut = pyqtSignal() deact = pyqtSignal() def __init__(self, iface, action, geometryClass): self.canvas = iface.mapCanvas() self.iface = iface self.action = action self.geometryClass = geometryClass obj_color = QColor(254, 0, 0) obj_color_alpha = QColor(254, 0, 0) obj_color_alpha.setAlpha(60) vert_color = QColor(0, 0, 255) QgsMapTool.__init__(self, self.canvas) self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.GeometryType(3)) self.rubberBand.setWidth(1) self.rubberBand.setStrokeColor(obj_color) self.rubberBand.setFillColor(obj_color_alpha) self.rubberBand_click = QgsRubberBand(self.canvas, QgsWkbTypes.GeometryType(3)) self.rubberBand_click.setWidth(0) self.rubberBand_click.setFillColor(obj_color_alpha) # snap marker self.snap_mark = QgsVertexMarker(self.canvas) self.snap_mark.setColor(vert_color) self.snap_mark.setPenWidth(2) self.snap_mark.setIconType(QgsVertexMarker.ICON_BOX) self.snap_mark.setIconSize(10) self.points = [] def activate(self): self.action.setChecked(True) self.setCursor(Qt.CrossCursor) def canvasMoveEvent(self, e): self.snap_mark.hide() self.snapPoint = False self.snapPoint = self.checkSnapToPoint(e.pos()) if self.snapPoint[0]: self.snap_mark.setCenter(self.snapPoint[1]) self.snap_mark.show() if len(self.points) > 0: self.rubberBand.reset(QgsWkbTypes.GeometryType(3)) point = self.toMapCoordinates(self.canvas.mouseLastXY()) temp_points = self.points[:] temp_points.append(point) polygon = QgsGeometry.fromPolygonXY([temp_points]) self.rubberBand.setToGeometry(polygon, None) self.rubberBand.show() def canvasPressEvent(self, e): # Left mouse button if e.button() == Qt.LeftButton: if self.snapPoint[0]: point = self.snapPoint[1] else: point = self.toMapCoordinates(self.canvas.mouseLastXY()) self.points.append(point) polygon = QgsGeometry.fromPolygonXY([self.points]) self.rubberBand_click.reset(QgsWkbTypes.GeometryType(3)) self.rubberBand_click.setToGeometry(polygon, None) self.rubberBand_click.show() # Right mouse button if e.button() == Qt.RightButton: geometry = QgsGeometry.fromPolygonXY([self.points]) self.geometryClass.geometry = geometry self.cut.emit() self.reset() def checkSnapToPoint(self, point): snapped = False snap_point = self.toMapCoordinates(point) snapper = self.canvas.snappingUtils() snapMatch = snapper.snapToMap(point) if snapMatch.hasVertex(): snap_point = snapMatch.point() snapped = True return snapped, snap_point def deactivate(self): self.action.setChecked(False) self.reset() self.deact.emit() def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.reset() def reset(self): self.rubberBand_click.reset(QgsWkbTypes.GeometryType(3)) self.rubberBand.reset(QgsWkbTypes.GeometryType(3)) self.snap_mark.hide() self.points = []
class ItemBrowserDock(QDockWidget, Ui_itembrowser): dockRemoved = pyqtSignal(str) def __init__(self, iface, layer, currentFeature): self.iface = iface self.layer = layer self.renderer = self.iface.mapCanvas().mapRenderer() self.settings = MySettings() QDockWidget.__init__(self) self.setupUi(self) self.setWindowTitle("ItemBrowser: %s" % layer.name()) if layer.hasGeometryType() is False: self.panCheck.setChecked(False) self.panCheck.setEnabled(False) self.scaleCheck.setChecked(False) self.scaleCheck.setEnabled(False) self.previousButton.setArrowType(Qt.LeftArrow) self.nextButton.setArrowType(Qt.RightArrow) icon = QIcon(":/plugins/itembrowser/icons/openform.svg") self.editFormButton.setIcon(icon) # actions icon = QIcon(":/plugins/itembrowser/icons/action.svg") self.actionButton.setIcon(icon) self.attrAction = layer.actions() actions = [self.attrAction[i] for i in range(self.attrAction.size())] preferredAction = layer.customProperty("ItemBrowserPreferedAction", "") if preferredAction not in actions: dfltAction = self.attrAction.defaultAction() if dfltAction > len(actions): preferredAction = self.attrAction[dfltAction].name() preferredActionFound = False for i, action in enumerate(actions): qAction = QAction(QIcon(":/plugins/itembrowser/icons/action.svg"), action.name(), self) qAction.triggered.connect(lambda: self.doAction(i)) self.actionButton.addAction(qAction) if action.name() == preferredAction: self.actionButton.setDefaultAction(qAction) preferredActionFound = True if len(actions) == 0: self.actionButton.setEnabled(False) elif not preferredActionFound: self.actionButton.setDefaultAction(self.actionButton.actions()[0]) self.rubber = QgsRubberBand(self.iface.mapCanvas()) self.selectionChanged() if currentFeature == self.listCombo.currentIndex(): self.on_listCombo_currentIndexChanged(currentFeature) else: self.listCombo.setCurrentIndex(currentFeature) self.layer.layerDeleted.connect(self.close) self.layer.selectionChanged.connect(self.selectionChanged) def closeEvent(self, e): self.rubber.reset() try: self.layer.layerDeleted.disconnect(self.close) except TypeError: pass try: self.layer.selectionChanged.disconnect(self.selectionChanged) except TypeError: pass if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("itemBrowserSelection", repr([])) self.dockRemoved.emit(self.layer.id()) def selectionChanged(self): self.cleanBrowserFields() self.rubber.reset() nItems = self.layer.selectedFeatureCount() if nItems < 2: self.close() self.layer.emit(SIGNAL("browserNoItem()")) return self.browseFrame.setEnabled(True) subset = self.layer.selectedFeaturesIds() if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("itemBrowserSelection", repr(subset)) f = QgsFeature() title = QgsExpression(self.layer.displayExpression()) title.prepare(self.layer.pendingFields()) iterator = self.layer.getFeatures(QgsFeatureRequest().setFilterFids(subset)) while iterator.nextFeature(f): result = title.evaluate(f) if title.hasEvalError(): self.listCombo.addItem("%u" % f.id(), f.id()) else: self.listCombo.addItem("%s" % result, f.id()) def cleanBrowserFields(self): self.currentPosLabel.setText('0/0') self.listCombo.clear() def panScaleToItem(self, feature): if self.panCheck.isChecked() is False: return featBobo = feature.geometry().boundingBox() # if scaling and bobo has width and height (i.e. not a point) if self.scaleCheck.isChecked() and featBobo.width() != 0 and featBobo.height() != 0: featBobo.scale(self.settings.value("scale")) ul = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMaximum())) ur = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMaximum())) ll = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMinimum())) lr = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMinimum())) x = (ul.x(), ur.x(), ll.x(), lr.x()) y = (ul.y(), ur.y(), ll.y(), lr.y()) x0 = min(x) y0 = min(y) x1 = max(x) y1 = max(y) else: panTo = self.renderer.layerToMapCoordinates(self.layer, featBobo.center()) mapBobo = self.iface.mapCanvas().extent() xshift = panTo.x() - mapBobo.center().x() yshift = panTo.y() - mapBobo.center().y() x0 = mapBobo.xMinimum() + xshift y0 = mapBobo.yMinimum() + yshift x1 = mapBobo.xMaximum() + xshift y1 = mapBobo.yMaximum() + yshift self.iface.mapCanvas().setExtent(QgsRectangle(x0, y0, x1, y1)) self.iface.mapCanvas().refresh() def getCurrentItem(self): i = self.listCombo.currentIndex() if i == -1: return None f = QgsFeature() if self.layer.getFeatures(QgsFeatureRequest().setFilterFid(self.listCombo.itemData(i))).nextFeature(f): return f else: raise NameError("feature not found") def setCurrentItem(self, featureId): idx = self.listCombo.findText("%u" % featureId) self.listCombo.setCurrentIndex(idx) def doAction(self, i): f = self.getCurrentItem() self.actionButton.setDefaultAction(self.actionButton.actions()[i]) self.layer.setCustomProperty("ItemBrowserPreferedAction", self.attrAction[i].name()) self.attrAction.doActionFeature(i, f) @pyqtSlot(name="on_previousButton_clicked") def previousFeaature(self): i = self.listCombo.currentIndex() n = max(0, i-1) self.listCombo.setCurrentIndex(n) self.saveCurrentFeature(n) @pyqtSlot(name="on_nextButton_clicked") def nextFeature(self): i = self.listCombo.currentIndex() c = self.listCombo.count() n = min(i+1, c-1) self.listCombo.setCurrentIndex(n) self.saveCurrentFeature(n) @pyqtSlot(int, name="on_listCombo_activated") def saveCurrentFeature(self, i): if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("itemBrowserCurrentItem", i) @pyqtSlot(int, name="on_listCombo_currentIndexChanged") def on_listCombo_currentIndexChanged(self, i): feature = self.getCurrentItem() if feature is None: return self.rubber.reset() if self.listCombo.count() > 1: width = self.settings.value("rubberWidth") color = self.settings.value("rubberColor") self.rubber.setColor(color) self.rubber.setWidth(width) self.rubber.setToGeometry(feature.geometry(), self.layer) # scale to feature self.panScaleToItem(feature) # Update browser self.currentPosLabel.setText("%u/%u" % (i+1, self.listCombo.count())) # emit signal self.layer.emit(SIGNAL("browserCurrentItem(long)"), feature.id()) @pyqtSlot(int, name="on_panCheck_stateChanged") def on_panCheck_stateChanged(self, i): if self.panCheck.isChecked(): self.scaleCheck.setEnabled(True) feature = self.getCurrentItem() if feature is None: return self.panScaleToItem(feature) else: self.scaleCheck.setEnabled(False) @pyqtSlot(int, name="on_scaleCheck_stateChanged") def on_scaleCheck_stateChanged(self, i): if self.scaleCheck.isChecked(): feature = self.getCurrentItem() if feature is None: return self.panScaleToItem(feature) @pyqtSlot(name="on_editFormButton_clicked") def openFeatureForm(self): self.iface.openFeatureForm(self.layer, self.getCurrentItem())
class QMap(): def __init__(self, iface): self.iface = iface self.actions = [] self.panels= [] self.navtoolbar = self.iface.mapNavToolToolBar() self.mainwindow = self.iface.mainWindow() self.iface.projectRead.connect(self.projectOpened) self.iface.initializationCompleted.connect(self.setupUI) self.actionGroup = QActionGroup(self.mainwindow) self.actionGroup.setExclusive(True) self.menuGroup = QActionGroup(self.mainwindow) self.menuGroup.setExclusive(True) self.movetool = MoveTool(self.iface.mapCanvas(), []) self.infotool = InfoTool(self.iface.mapCanvas()) self.infotool.infoResults.connect(self.showInfoResults) self.report = PopDownReport(self.iface.messageBar()) self.dialogprovider = DialogProvider(iface.mapCanvas(), iface) self.dialogprovider.accepted.connect(self.clearToolRubberBand) self.dialogprovider.rejected.connect(self.clearToolRubberBand) self.edittool = EditTool(self.iface.mapCanvas(),[]) self.edittool.finished.connect(self.openForm) self.edittool.featuresfound.connect(self.showFeatureSelection) self.infodock = InfoDock(self.iface.mainWindow()) self.iface.addDockWidget(Qt.RightDockWidgetArea, self.infodock) self.infodock.hide() self.band = QgsRubberBand(self.iface.mapCanvas()) self.band.setIconSize(20) self.band.setWidth(10) self.band.setColor(QColor(186, 93, 212, 76)) def showFeatureSelection(self, features): listUi = ListFeaturesForm(self.mainwindow) listUi.loadFeatureList(features) listUi.openFeatureForm.connect(self.openForm) listUi.exec_() def showInfoResults(self, results): self.infodock.clearResults() self.infodock.setResults(results) self.infodock.show() self.infodock.repaint() @property def _mapLayers(self): return QgsMapLayerRegistry.instance().mapLayers() def clearToolRubberBand(self): tool = self.iface.mapCanvas().mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def missingLayers(self, layers): def showError(): html = ["<h1>Missing Layers</h1>", "<ul>"] for layer in layers: html.append("<li>{}</li>".format(layer)) html.append("</ul>") self.errorreport.updateHTML("".join(html)) message = "Seems like {} didn't load correctly".format(utils._pluralstring('layer', len(layers))) utils.warning("Missing layers") map(utils.warning, layers) self.widget = self.iface.messageBar().createMessage("Missing Layers", message, QIcon(":/icons/sad")) button = QPushButton(self.widget) button.setCheckable(True) button.setChecked(self.errorreport.isVisible()) button.setText("Show missing layers") button.toggled.connect(showError) button.toggled.connect(functools.partial(self.errorreport.setVisible)) self.widget.destroyed.connect(self.hideReports) self.widget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.widget, QgsMessageBar.WARNING) def excepthook(self, ex_type, value, tb): """ Custom exception hook so that we can handle errors in a nicer way """ where = ''.join(traceback.format_tb(tb)) msg = '{}'.format(value) utils.critical(msg) def showError(): html = """ <html> <body bgcolor="#FFEDED"> <p><b>{}</b></p> <p align="left"><small>{}</small></p> </body> </html> """.format(msg, where) self.errorreport.updateHTML(html) self.widget = self.iface.messageBar().createMessage("oops", "Looks like an error occurred", QIcon(":/icons/sad")) button = QPushButton(self.widget) button.setCheckable(True) button.setChecked(self.errorreport.isVisible()) button.setText("Show error") button.toggled.connect(showError) button.toggled.connect(functools.partial(self.errorreport.setVisible)) self.widget.destroyed.connect(self.hideReports) self.widget.layout().addWidget(button) self.messageBar.pushWidget(self.widget, QgsMessageBar.CRITICAL) def hideReports(self): self.errorreport.setVisible(False) self.report.setVisible(False) def setupUI(self): """ Set up the main QGIS interface items. Called after QGIS has loaded the plugin. """ self.updateAppSize() utils.settings_notify.settings_changed.connect(self.updateAppSize) self.navtoolbar.setMovable(False) self.navtoolbar.setAllowedAreas(Qt.TopToolBarArea) self.mainwindow.insertToolBar(self.toolbar, self.navtoolbar) self.openProjectAction.trigger() def updateAppSize(self): fullscreen = utils.settings.get("fullscreen", False) if fullscreen: self.mainwindow.showFullScreen() else: self.mainwindow.showMaximized() def setMapTool(self, tool): """ Set the current mapview canvas tool tool -- The QgsMapTool to set """ self.iface.mapCanvas().setMapTool(tool) def createToolBars(self): """ Create all the needed toolbars """ self.menutoolbar = QToolBar("Menu", self.mainwindow) self.menutoolbar.setMovable(False) self.menutoolbar.setAllowedAreas(Qt.LeftToolBarArea) self.mainwindow.addToolBar(Qt.LeftToolBarArea, self.menutoolbar) self.toolbar = QToolBar("QMap", self.mainwindow) self.mainwindow.addToolBar(Qt.TopToolBarArea, self.toolbar) self.toolbar.setMovable(False) self.editingtoolbar = FloatingToolBar("Editing", self.toolbar) self.extraaddtoolbar = FloatingToolBar("Extra Add Tools", self.toolbar) self.syncactionstoolbar = FloatingToolBar("Syncing", self.toolbar) self.syncactionstoolbar.setOrientation(Qt.Vertical) def createActions(self): """ Create all the actions """ self.homeAction = (QAction(QIcon(":/icons/zoomfull"), "Default View", self.mainwindow)) self.gpsAction = (GPSAction(QIcon(":/icons/gps"), self.iface.mapCanvas(), self.mainwindow)) self.openProjectAction = (QAction(QIcon(":/icons/open"), "Projects", self.mainwindow)) self.openProjectAction.setCheckable(True) self.configAction = (QAction(QIcon(":/icons/config"), "Settings", self.mainwindow)) self.configAction.setCheckable(True) self.toggleRasterAction = (QAction(QIcon(":/icons/photo"), "Aerial Photos", self.mainwindow)) self.syncAction = QAction(QIcon(":/icons/sync"), "Sync", self.mainwindow) self.syncAction.setVisible(False) self.editattributesaction = QAction(QIcon(":/icons/edit"), "Edit Attributes", self.mainwindow) self.editattributesaction.setCheckable(True) self.editattributesaction.toggled.connect(functools.partial(self.setMapTool, self.edittool)) self.moveaction = QAction(QIcon(":/icons/move"), "Move Feature", self.mainwindow) self.moveaction.setCheckable(True) self.editingmodeaction = QAction(QIcon(":/icons/edittools"), "Edit Tools", self.mainwindow) self.editingmodeaction.setCheckable(True) self.infoaction = QAction(QIcon(":/icons/info"), "Info", self.mainwindow) self.infoaction.setCheckable(True) self.addatgpsaction = QAction(QIcon(":/icons/gpsadd"), "Add at GPS", self.mainwindow) self.edittool.layersupdated.connect(self.editattributesaction.setVisible) self.movetool.layersupdated.connect(self.moveaction.setVisible) self.movetool.layersupdated.connect(self.editingmodeaction.setVisible) def initGui(self): """ Create all the icons and setup the tool bars. Called by QGIS when loading. This is called before setupUI. """ QApplication.setWindowIcon(QIcon(":/branding/logo")) self.mainwindow.findChildren(QMenuBar)[0].setVisible(False) self.mainwindow.setContextMenuPolicy(Qt.PreventContextMenu) self.mainwindow.setWindowTitle("IntraMaps Roam: Mobile Data Collection") # Disable QGIS logging window popups. We do our own logging QgsMessageLog.instance().messageReceived.disconnect() s = """ QToolButton { padding: 6px; color: #4f4f4f; } QToolButton:hover { padding: 6px; background-color: rgb(211, 228, 255); } QToolBar { background: white; } QCheckBox::indicator { width: 40px; height: 40px; } QLabel { color: #4f4f4f; } QDialog { background-color: rgb(255, 255, 255); } QPushButton { border: 1px solid #e1e1e1; padding: 6px; color: #4f4f4f; } QPushButton:hover { border: 1px solid #e1e1e1; padding: 6px; background-color: rgb(211, 228, 255); } QCheckBox { color: #4f4f4f; } QComboBox::drop-down { width: 30px; } QComboBox { border: 1px solid #d3d3d3; } QStackedWidget { background-color: rgb(255, 255, 255); } """ self.mainwindow.setStyleSheet(s) mainwidget = self.mainwindow.centralWidget() mainwidget.setLayout(QGridLayout()) mainwidget.layout().setContentsMargins(0,0,0,0) newlayout = QGridLayout() newlayout.setContentsMargins(0,0,0,0) newlayout.addWidget(self.iface.mapCanvas(), 0,0,2,1) newlayout.addWidget(self.iface.messageBar(), 0,0,1,1) wid = QWidget() wid.setLayout(newlayout) self.stack = QStackedWidget(self.mainwindow) self.messageBar = QgsMessageBar(wid) self.messageBar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed ) self.errorreport = PopDownReport(self.messageBar) mainwidget.layout().addWidget(self.stack, 0,0,2,1) mainwidget.layout().addWidget(self.messageBar, 0,0,1,1) self.helppage = HelpPage() helppath = os.path.join(os.path.dirname(__file__) , 'help',"help.html") self.helppage.setHelpPage(helppath) self.settingswidget = SettingsWidget(self.stack) self.projectwidget = ProjectsWidget() self.projectwidget.requestOpenProject.connect(self.loadProject) self.stack.addWidget(wid) self.stack.addWidget(self.projectwidget) self.stack.addWidget(self.helppage) self.stack.addWidget(self.settingswidget) sys.excepthook = self.excepthook def createSpacer(width=30): widget = QWidget() widget.setMinimumWidth(width) return widget self.createToolBars() self.createActions() spacewidget = createSpacer(60) gpsspacewidget = createSpacer() gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.moveaction.toggled.connect(functools.partial(self.setMapTool, self.movetool)) self.infoaction.toggled.connect(functools.partial(self.setMapTool, self.infotool)) showediting = (functools.partial(self.editingtoolbar.showToolbar, self.editingmodeaction, self.moveaction)) self.editingmodeaction.toggled.connect(showediting) self.addatgpsaction.triggered.connect(self.addAtGPS) self.addatgpsaction.setEnabled(self.gpsAction.isConnected) self.gpsAction.gpsfixed.connect(self.addatgpsaction.setEnabled) self.editingtoolbar.addToActionGroup(self.moveaction) self.actionGroup.addAction(self.editingmodeaction) self.actionGroup.addAction(self.editattributesaction) self.actionGroup.addAction(self.infoaction) self.homeAction.triggered.connect(self.zoomToDefaultView) self.openProjectAction.triggered.connect(self.showOpenProjectDialog) self.openProjectAction.triggered.connect(functools.partial(self.stack.setCurrentIndex, 1)) self.configAction.triggered.connect(functools.partial(self.stack.setCurrentIndex, 3)) self.configAction.triggered.connect(self.settingswidget.populateControls) self.configAction.triggered.connect(self.settingswidget.readSettings) self.toggleRasterAction.triggered.connect(self.toggleRasterLayers) self.navtoolbar.insertAction(self.iface.actionZoomIn(), self.iface.actionTouch()) self.navtoolbar.insertAction(self.iface.actionTouch(), self.homeAction) self.navtoolbar.insertAction(self.iface.actionTouch(), self.iface.actionZoomFullExtent()) self.navtoolbar.insertAction(self.homeAction, self.iface.actionZoomFullExtent()) self.navtoolbar.addAction(self.toggleRasterAction) self.navtoolbar.insertWidget(self.iface.actionZoomFullExtent(), spacewidget) self.toolbar.addAction(self.infoaction) self.toolbar.addAction(self.editingmodeaction) self.toolbar.addAction(self.editattributesaction) self.toolbar.addAction(self.syncAction) self.toolbar.addAction(self.gpsAction) self.toolbar.insertWidget(self.syncAction, gpsspacewidget) self.toolbar.insertSeparator(self.gpsAction) self.extraaddtoolbar.addAction(self.addatgpsaction) self.editingtoolbar.addAction(self.moveaction) self.mapview = QAction(QIcon(":/icons/map"), "Map", self.menutoolbar) self.mapview.setCheckable(True) self.mapview.triggered.connect(functools.partial(self.stack.setCurrentIndex, 0)) self.help = QAction(QIcon(":/icons/help"), "Help", self.menutoolbar) self.help.setCheckable(True) self.help.triggered.connect(functools.partial(self.stack.setCurrentIndex, 2)) self.help.setVisible(False) self.projectlabel = QLabel("Project: <br> None") self.projectlabel.setAlignment(Qt.AlignCenter) self.projectlabel.setStyleSheet(""" QLabel { color: #8c8c8c; font: 10px "Calibri" ; }""") self.userlabel = QLabel("User: <br> {user}".format(user=getpass.getuser())) self.userlabel.setAlignment(Qt.AlignCenter) self.userlabel.setStyleSheet(""" QLabel { color: #8c8c8c; font: 10px "Calibri" ; }""") self.quit = QAction(QIcon(":/icons/quit"), "Quit", self.menutoolbar) self.quit.triggered.connect(self.iface.actionExit().trigger) self.menuGroup.addAction(self.mapview) self.menuGroup.addAction(self.openProjectAction) self.menuGroup.addAction(self.help) self.menuGroup.addAction(self.configAction) self.menutoolbar.addAction(self.mapview) self.menutoolbar.addAction(self.openProjectAction) self.menutoolbar.addAction(self.help) self.menutoolbar.addAction(self.configAction) self.menutoolbar.addAction(self.quit) quitspacewidget = createSpacer() quitspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) labelaction = self.menutoolbar.insertWidget(self.configAction, self.userlabel) self.menutoolbar.insertWidget(labelaction, quitspacewidget) self.menutoolbar.insertWidget(labelaction, self.projectlabel) self.setupIcons() self.stack.currentChanged.connect(self.updateUIState) def updateUIState(self, page): """ Update the UI state to reflect the currently selected page in the stacked widget """ def setToolbarsActive(enabled): toolbars = self.mainwindow.findChildren(QToolBar) for toolbar in toolbars: if toolbar == self.menutoolbar: continue toolbar.setEnabled(enabled) def setPanelsVisible(visible): for panel in self.panels: panel.setVisible(visible) ismapview = page == 0 setToolbarsActive(ismapview) setPanelsVisible(ismapview) self.infodock.hide() def addAtGPS(self): """ Add a record at the current GPS location. """ action = self.actionGroup.checkedAction() if not action: return layer = action.data() if not layer: return point = self.gpsAction.position self.addNewFeature(layer=layer, geometry=point) def zoomToDefaultView(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.iface.mapCanvas().setExtent(self.defaultextent) self.iface.mapCanvas().refresh() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ legend = self.iface.legendInterface() #Freeze the canvas to save on UI refresh self.iface.mapCanvas().freeze() for layer in self._mapLayers.values(): if layer.type() == QgsMapLayer.RasterLayer: isvisible = legend.isLayerVisible(layer) legend.setLayerVisible(layer, not isvisible) self.iface.mapCanvas().freeze(False) self.iface.mapCanvas().refresh() def setupIcons(self): """ Update toolbars to have text and icons, change normal QGIS icons to new style """ toolbars = self.mainwindow.findChildren(QToolBar) for toolbar in toolbars: toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) toolbar.setIconSize(QSize(32, 32)) self.iface.actionTouch().setIconText("Pan") self.iface.actionTouch().setIcon(QIcon(":/icons/pan")) self.iface.actionZoomIn().setIcon(QIcon(":/icons/in")) self.iface.actionZoomOut().setIcon(QIcon(":/icons/out")) self.iface.actionPan().setIcon(QIcon(":/icons/pan")) self.iface.actionZoomFullExtent().setIcon(QIcon(":/icons/home")) self.iface.actionZoomFullExtent().setIconText("Home View") self.actionGroup.addAction(self.iface.actionZoomIn()) self.actionGroup.addAction(self.iface.actionZoomOut()) self.actionGroup.addAction(self.iface.actionTouch()) def projectOpened(self): """ Called when a new project is opened in QGIS. """ for panel in self.panels: self.mainwindow.removeDockWidget(panel) del panel projectpath = QgsProject.instance().fileName() project = QMapProject(os.path.dirname(projectpath), self.iface) self.projectlabel.setText("Project: <br> {}".format(project.name)) self.createFormButtons(projectlayers = project.getConfiguredLayers()) # Enable the raster layers button only if the project contains a raster layer. hasrasters = any(layer.type() for layer in self._mapLayers.values()) self.toggleRasterAction.setEnabled(hasrasters) self.defaultextent = self.iface.mapCanvas().extent() self.connectSyncProviders(project) # Show panels self.panels = list(project.getPanels()) for panel in self.panels: self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea , panel) self.iface.messageBar().popWidget() def captureLayer(self, layer): text = layer.icontext tool = layer.getMaptool(self.iface.mapCanvas()) # Hack until I fix it later if isinstance(tool, PointTool): add = functools.partial(self.addNewFeature, qgslayer) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(functools.partial(self.showToolError, text)) action = QAction(QIcon(layer.icon), text, self.mainwindow) action.setData(layer) action.setCheckable(True) action.toggled.connect(functools.partial(self.setMapTool, tool)) self.toolbar.insertAction(self.editingmodeaction, action) if not tool.isEditTool(): # Connect the GPS tools strip to the action pressed event. showgpstools = (functools.partial(self.extraaddtoolbar.showToolbar, action, None)) action.toggled.connect(showgpstools) self.actionGroup.addAction(action) self.actions.append(action) def editLayer(self, layer): self.edittool.addLayer(layer.QGISLayer) self.edittool.searchRadius = 10 def moveLayer(self, layer): self.movetool.addLayer(layer.QGISLayer) def createFormButtons(self, projectlayers): """ Create buttons for each form that is definded """ # Remove all the old buttons for action in self.actions: self.actionGroup.removeAction(action) self.toolbar.removeAction(action) self.edittool.layers = [] self.movetool.layers = [] capabilitityhandlers = { "capture" : self.captureLayer, "edit" : self.editLayer, "move" : self.moveLayer} for layer in projectlayers: try: qgslayer = QgsMapLayerRegistry.instance().mapLayersByName(layer.name)[0] if qgslayer.type() == QgsMapLayer.RasterLayer: utils.log("We can't support raster layers for data entry") continue layer.QGISLayer = qgslayer except IndexError: utils.log("Layer {} not found in project".format(layer.name)) continue for capability in layer.capabilities: try: capabilitityhandlers[capability](layer) except NoMapToolConfigured: utils.log("No map tool configured") continue except ErrorInMapTool as error: self.iface.messageBar().pushMessage("Error configuring map tool", error.message, level=QgsMessageBar.WARNING) continue def showToolError(self, label, message): self.iface.messageBar().pushMessage(label, message, QgsMessageBar.WARNING) def openForm(self, layer, feature): if not layer.isEditable(): layer.startEditing() self.band.setToGeometry(feature.geometry(), layer) self.dialogprovider.openDialog(feature=feature, layer=layer) self.band.reset() def addNewFeature(self, layer, geometry): fields = layer.pendingFields() feature = QgsFeature() feature.setGeometry( geometry ) feature.initAttributes(fields.count()) feature.setFields(fields) for indx in xrange(fields.count()): feature[indx] = layer.dataProvider().defaultValue(indx) self.openForm(layer, feature) def showOpenProjectDialog(self): """ Show the project selection dialog. """ self.stack.setCurrentIndex(1) self.infodock.hide() path = os.path.join(os.path.dirname(__file__), '..' , 'projects/') projects = getProjects(path, self.iface) self.projectwidget.loadProjectList(projects) def loadProject(self, project): """ Load a project into QGIS. """ utils.log(project) utils.log(project.name) utils.log(project.projectfile) utils.log(project.vaild) (passed, message) = project.onProjectLoad() if not passed: QMessageBox.warning(self.mainwindow, "Project Load Rejected", "Project couldn't be loaded because {}".format(message)) return self.mapview.trigger() self.iface.newProject(False) self.iface.mapCanvas().freeze() self.infodock.clearResults() # No idea why we have to set this each time. Maybe QGIS deletes it for # some reason. self.badLayerHandler = BadLayerHandler(callback=self.missingLayers) QgsProject.instance().setBadLayerHandler( self.badLayerHandler ) self.iface.messageBar().pushMessage("Project Loading","", QgsMessageBar.INFO) QApplication.processEvents() fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) self.iface.mapCanvas().updateScale() self.iface.mapCanvas().freeze(False) self.iface.mapCanvas().refresh() self.mainwindow.setWindowTitle("IntraMaps Roam: Mobile Data Collection") self.iface.projectRead.emit() def unload(self): del self.toolbar def connectSyncProviders(self, project): self.syncactionstoolbar.clear() syncactions = list(project.syncprovders()) # Don't show the sync button if there is no sync providers if not syncactions: self.syncAction.setVisible(False) return self.syncAction.setVisible(True) for provider in syncactions: action = QAction(QIcon(":/icons/sync"), "Sync {}".format(provider.name), self.mainwindow) action.triggered.connect(functools.partial(self.syncProvider, provider)) self.syncactionstoolbar.addAction(action) try: self.syncAction.toggled.disconnect() except TypeError: pass try: self.syncAction.triggered.disconnect() except TypeError: pass if len(syncactions) == 1: # If one provider is set then we just connect the main button. self.syncAction.setCheckable(False) self.syncAction.setText("Sync") self.syncAction.triggered.connect(functools.partial(self.syncProvider, syncactions[0])) else: # the sync button because a sync menu self.syncAction.setCheckable(True) self.syncAction.setText("Sync Menu") showsyncoptions = (functools.partial(self.syncactionstoolbar.showToolbar, self.syncAction, None)) self.syncAction.toggled.connect(showsyncoptions) def syncstarted(self): # Remove the old widget if it's still there. # I don't really like this. Seems hacky. try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass except AttributeError: pass self.iface.messageBar().findChildren(QToolButton)[0].setVisible(False) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync in progress", QIcon(":/icons/syncing")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setText("Status") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) pro = QProgressBar() pro.setMaximum(0) pro.setMinimum(0) self.syncwidget.layout().addWidget(pro) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget, QgsMessageBar.INFO) def synccomplete(self): try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass stylesheet = ("QgsMessageBar { background-color: rgba(239, 255, 233); border: 0px solid #b9cfe4; } " "QLabel,QTextEdit { color: #057f35; } ") closebutton = self.iface.messageBar().findChildren(QToolButton)[0] closebutton.setVisible(True) closebutton.clicked.connect(functools.partial(self.report.setVisible, False)) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync Complete", QIcon(":/icons/syncdone")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setChecked(self.report.isVisible()) button.setText("Sync Report") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) pro = QProgressBar() pro.setMaximum(100) pro.setValue(100) self.syncwidget.layout().addWidget(pro) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget) self.iface.messageBar().setStyleSheet(stylesheet) self.iface.mapCanvas().refresh() def syncerror(self): try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass closebutton = self.iface.messageBar().findChildren(QToolButton)[0] closebutton.setVisible(True) closebutton.clicked.connect(functools.partial(self.report.setVisible, False)) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync Error", QIcon(":/icons/syncfail")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setChecked(self.report.isVisible()) button.setText("Sync Report") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget, QgsMessageBar.CRITICAL) self.iface.mapCanvas().refresh() def syncProvider(self, provider): self.syncAction.toggle() provider.syncStarted.connect(functools.partial(self.syncAction.setEnabled, False)) provider.syncStarted.connect(self.syncstarted) provider.syncComplete.connect(self.synccomplete) provider.syncComplete.connect(functools.partial(self.syncAction.setEnabled, True)) provider.syncComplete.connect(functools.partial(self.report.updateHTML)) provider.syncMessage.connect(self.report.updateHTML) provider.syncError.connect(self.report.updateHTML) provider.syncError.connect(self.syncerror) provider.syncError.connect(functools.partial(self.syncAction.setEnabled, True)) provider.startSync()
class MetaSearchDialog(QDialog, BASE_CLASS): """main dialogue""" def __init__(self, iface): """init window""" QDialog.__init__(self) self.setupUi(self) self.iface = iface self.map = iface.mapCanvas() self.settings = QSettings() self.catalog = None self.catalog_url = None self.context = StaticContext() version = self.context.metadata.get('general', 'version') self.setWindowTitle('MetaSearch %s' % version) self.rubber_band = QgsRubberBand(self.map, True) # True = a polygon self.rubber_band.setColor(QColor(255, 0, 0, 75)) self.rubber_band.setWidth(5) # form inputs self.startfrom = 0 self.maxrecords = 10 self.timeout = 10 self.constraints = [] # Servers tab self.cmbConnectionsServices.activated.connect(self.save_connection) self.cmbConnectionsSearch.activated.connect(self.save_connection) self.btnServerInfo.clicked.connect(self.connection_info) self.btnAddDefault.clicked.connect(self.add_default_connections) self.btnCapabilities.clicked.connect(self.show_xml) self.tabWidget.currentChanged.connect(self.populate_connection_list) # server management buttons self.btnNew.clicked.connect(self.add_connection) self.btnEdit.clicked.connect(self.edit_connection) self.btnDelete.clicked.connect(self.delete_connection) self.btnLoad.clicked.connect(self.load_connections) self.btnSave.clicked.connect(save_connections) # Search tab self.treeRecords.itemSelectionChanged.connect(self.record_clicked) self.treeRecords.itemDoubleClicked.connect(self.show_metadata) self.btnSearch.clicked.connect(self.search) self.leKeywords.returnPressed.connect(self.search) # prevent dialog from closing upon pressing enter self.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False) # launch help from button self.buttonBox.helpRequested.connect(self.help) self.btnCanvasBbox.setAutoDefault(False) self.btnCanvasBbox.clicked.connect(self.set_bbox_from_map) self.btnGlobalBbox.clicked.connect(self.set_bbox_global) # navigation buttons self.btnFirst.clicked.connect(self.navigate) self.btnPrev.clicked.connect(self.navigate) self.btnNext.clicked.connect(self.navigate) self.btnLast.clicked.connect(self.navigate) self.btnAddToWms.clicked.connect(self.add_to_ows) self.btnAddToWfs.clicked.connect(self.add_to_ows) self.btnAddToWcs.clicked.connect(self.add_to_ows) self.btnShowXml.clicked.connect(self.show_xml) # settings self.radioTitleAsk.clicked.connect(self.set_ows_save_title_ask) self.radioTitleNoAsk.clicked.connect(self.set_ows_save_title_no_ask) self.radioTempName.clicked.connect(self.set_ows_save_temp_name) self.manageGui() def manageGui(self): """open window""" self.tabWidget.setCurrentIndex(0) self.populate_connection_list() self.btnCapabilities.setEnabled(False) self.spnRecords.setValue( self.settings.value('/MetaSearch/returnRecords', 10, int)) key = '/MetaSearch/%s' % self.cmbConnectionsSearch.currentText() self.catalog_url = self.settings.value('%s/url' % key) self.set_bbox_global() self.reset_buttons() # get preferred connection save strategy from settings and set it save_strat = self.settings.value('/MetaSearch/ows_save_strategy', 'title_ask') if save_strat == 'temp_name': self.radioTempName.setChecked(True) elif save_strat == 'title_no_ask': self.radioTitleNoAsk.setChecked(True) else: self.radioTitleAsk.setChecked(True) # install proxy handler if specified in QGIS settings self.install_proxy() # Servers tab def populate_connection_list(self): """populate select box with connections""" self.settings.beginGroup('/MetaSearch/') self.cmbConnectionsServices.clear() self.cmbConnectionsServices.addItems(self.settings.childGroups()) self.cmbConnectionsSearch.clear() self.cmbConnectionsSearch.addItems(self.settings.childGroups()) self.settings.endGroup() self.set_connection_list_position() if self.cmbConnectionsServices.count() == 0: # no connections - disable various buttons state_disabled = False self.btnSave.setEnabled(state_disabled) # and start with connection tab open self.tabWidget.setCurrentIndex(1) # tell the user to add services msg = self.tr('No services/connections defined. To get ' 'started with MetaSearch, create a new ' 'connection by clicking \'New\' or click ' '\'Add default services\'.') self.textMetadata.setHtml('<p><h3>%s</h3></p>' % msg) else: # connections - enable various buttons state_disabled = True self.btnServerInfo.setEnabled(state_disabled) self.btnEdit.setEnabled(state_disabled) self.btnDelete.setEnabled(state_disabled) def set_connection_list_position(self): """set the current index to the selected connection""" to_select = self.settings.value('/MetaSearch/selected') conn_count = self.cmbConnectionsServices.count() if conn_count == 0: self.btnDelete.setEnabled(False) self.btnServerInfo.setEnabled(False) self.btnEdit.setEnabled(False) # does to_select exist in cmbConnectionsServices? exists = False for i in range(conn_count): if self.cmbConnectionsServices.itemText(i) == to_select: self.cmbConnectionsServices.setCurrentIndex(i) self.cmbConnectionsSearch.setCurrentIndex(i) exists = True break # If we couldn't find the stored item, but there are some, default # to the last item (this makes some sense when deleting items as it # allows the user to repeatidly click on delete to remove a whole # lot of items) if not exists and conn_count > 0: # If to_select is null, then the selected connection wasn't found # by QSettings, which probably means that this is the first time # the user has used CSWClient, so default to the first in the list # of connetions. Otherwise default to the last. if not to_select: current_index = 0 else: current_index = conn_count - 1 self.cmbConnectionsServices.setCurrentIndex(current_index) self.cmbConnectionsSearch.setCurrentIndex(current_index) def save_connection(self): """save connection""" caller = self.sender().objectName() if caller == 'cmbConnectionsServices': # servers tab current_text = self.cmbConnectionsServices.currentText() elif caller == 'cmbConnectionsSearch': # search tab current_text = self.cmbConnectionsSearch.currentText() self.settings.setValue('/MetaSearch/selected', current_text) key = '/MetaSearch/%s' % current_text if caller == 'cmbConnectionsSearch': # bind to service in search tab self.catalog_url = self.settings.value('%s/url' % key) if caller == 'cmbConnectionsServices': # clear server metadata self.textMetadata.clear() self.btnCapabilities.setEnabled(False) def connection_info(self): """show connection info""" current_text = self.cmbConnectionsServices.currentText() key = '/MetaSearch/%s' % current_text self.catalog_url = self.settings.value('%s/url' % key) # connect to the server if not self._get_csw(): return QApplication.restoreOverrideCursor() if self.catalog: # display service metadata self.btnCapabilities.setEnabled(True) metadata = render_template('en', self.context, self.catalog, 'service_metadata.html') style = QgsApplication.reportStyleSheet() self.textMetadata.clear() self.textMetadata.document().setDefaultStyleSheet(style) self.textMetadata.setHtml(metadata) def add_connection(self): """add new service""" conn_new = NewConnectionDialog() conn_new.setWindowTitle(self.tr('New Catalogue service')) if conn_new.exec_() == QDialog.Accepted: # add to service list self.populate_connection_list() self.textMetadata.clear() def edit_connection(self): """modify existing connection""" current_text = self.cmbConnectionsServices.currentText() url = self.settings.value('/MetaSearch/%s/url' % current_text) conn_edit = NewConnectionDialog(current_text) conn_edit.setWindowTitle(self.tr('Edit Catalogue service')) conn_edit.leName.setText(current_text) conn_edit.leURL.setText(url) if conn_edit.exec_() == QDialog.Accepted: # update service list self.populate_connection_list() def delete_connection(self): """delete connection""" current_text = self.cmbConnectionsServices.currentText() key = '/MetaSearch/%s' % current_text msg = self.tr('Remove service %s?') % current_text result = QMessageBox.information(self, self.tr('Confirm delete'), msg, QMessageBox.Ok | QMessageBox.Cancel) if result == QMessageBox.Ok: # remove service from list self.settings.remove(key) index_to_delete = self.cmbConnectionsServices.currentIndex() self.cmbConnectionsServices.removeItem(index_to_delete) self.cmbConnectionsSearch.removeItem(index_to_delete) self.set_connection_list_position() def load_connections(self): """load services from list""" ManageConnectionsDialog(1).exec_() self.populate_connection_list() def add_default_connections(self): """add default connections""" filename = os.path.join(self.context.ppath, 'resources', 'connections-default.xml') doc = get_connections_from_file(self, filename) if doc is None: return self.settings.beginGroup('/MetaSearch/') keys = self.settings.childGroups() self.settings.endGroup() for server in doc.findall('csw'): name = server.attrib.get('name') # check for duplicates if name in keys: msg = self.tr('%s exists. Overwrite?') % name res = QMessageBox.warning(self, self.tr('Loading connections'), msg, QMessageBox.Yes | QMessageBox.No) if res != QMessageBox.Yes: continue # no dups detected or overwrite is allowed key = '/MetaSearch/%s' % name self.settings.setValue('%s/url' % key, server.attrib.get('url')) self.populate_connection_list() # Settings tab def set_ows_save_title_ask(self): """save ows save strategy as save ows title, ask if duplicate""" self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_ask') def set_ows_save_title_no_ask(self): """save ows save strategy as save ows title, do NOT ask if duplicate""" self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_no_ask') def set_ows_save_temp_name(self): """save ows save strategy as save with a temporary name""" self.settings.setValue('/MetaSearch/ows_save_strategy', 'temp_name') # Search tab def set_bbox_from_map(self): """set bounding box from map extent""" crs = self.map.mapRenderer().destinationCrs() crsid = int(crs.authid().split(':')[1]) extent = self.map.extent() if crsid != 4326: # reproject to EPSG:4326 src = QgsCoordinateReferenceSystem(crsid) dest = QgsCoordinateReferenceSystem(4326) xform = QgsCoordinateTransform(src, dest) minxy = xform.transform(QgsPoint(extent.xMinimum(), extent.yMinimum())) maxxy = xform.transform(QgsPoint(extent.xMaximum(), extent.yMaximum())) minx, miny = minxy maxx, maxy = maxxy else: # 4326 minx = extent.xMinimum() miny = extent.yMinimum() maxx = extent.xMaximum() maxy = extent.yMaximum() self.leNorth.setText(unicode(maxy)[0:9]) self.leSouth.setText(unicode(miny)[0:9]) self.leWest.setText(unicode(minx)[0:9]) self.leEast.setText(unicode(maxx)[0:9]) def set_bbox_global(self): """set global bounding box""" self.leNorth.setText('90') self.leSouth.setText('-90') self.leWest.setText('-180') self.leEast.setText('180') def search(self): """execute search""" self.catalog = None self.constraints = [] # clear all fields and disable buttons self.lblResults.clear() self.treeRecords.clear() self.reset_buttons() # save some settings self.settings.setValue('/MetaSearch/returnRecords', self.spnRecords.cleanText()) # set current catalogue current_text = self.cmbConnectionsSearch.currentText() key = '/MetaSearch/%s' % current_text self.catalog_url = self.settings.value('%s/url' % key) # start position and number of records to return self.startfrom = 0 self.maxrecords = self.spnRecords.value() # set timeout self.timeout = self.spnTimeout.value() # bbox minx = self.leWest.text() miny = self.leSouth.text() maxx = self.leEast.text() maxy = self.leNorth.text() bbox = [minx, miny, maxx, maxy] # only apply spatial filter if bbox is not global # even for a global bbox, if a spatial filter is applied, then # the CSW server will skip records without a bbox if bbox != ['-180', '-90', '180', '90']: self.constraints.append(BBox(bbox)) # keywords if self.leKeywords.text(): # TODO: handle multiple word searches keywords = self.leKeywords.text() self.constraints.append(PropertyIsLike('csw:AnyText', keywords)) if len(self.constraints) > 1: # exclusive search (a && b) self.constraints = [self.constraints] # build request if not self._get_csw(): return # TODO: allow users to select resources types # to find ('service', 'dataset', etc.) try: self.catalog.getrecords2(constraints=self.constraints, maxrecords=self.maxrecords, esn='full') except ExceptionReport as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('Search error'), self.tr('Search error: %s') % err) return except Exception as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('Connection error'), self.tr('Connection error: %s') % err) return if self.catalog.results['matches'] == 0: QApplication.restoreOverrideCursor() self.lblResults.setText(self.tr('0 results')) return QApplication.restoreOverrideCursor() self.display_results() def display_results(self): """display search results""" self.treeRecords.clear() position = self.catalog.results['returned'] + self.startfrom msg = self.tr('Showing %d - %d of %n result(s)', 'number of results', self.catalog.results['matches']) % (self.startfrom + 1, position) self.lblResults.setText(msg) for rec in self.catalog.records: item = QTreeWidgetItem(self.treeRecords) if self.catalog.records[rec].type: item.setText(0, normalize_text(self.catalog.records[rec].type)) else: item.setText(0, 'unknown') if self.catalog.records[rec].title: item.setText(1, normalize_text(self.catalog.records[rec].title)) if self.catalog.records[rec].identifier: set_item_data(item, 'identifier', self.catalog.records[rec].identifier) self.btnShowXml.setEnabled(True) if self.catalog.results["matches"] < self.maxrecords: disabled = False else: disabled = True self.btnFirst.setEnabled(disabled) self.btnPrev.setEnabled(disabled) self.btnNext.setEnabled(disabled) self.btnLast.setEnabled(disabled) def record_clicked(self): """record clicked signal""" # disable only service buttons self.reset_buttons(True, False, False) if not self.treeRecords.selectedItems(): return item = self.treeRecords.currentItem() if not item: return identifier = get_item_data(item, 'identifier') try: record = self.catalog.records[identifier] except KeyError as err: QMessageBox.warning(self, self.tr('Record parsing error'), 'Unable to locate record identifier') return # if the record has a bbox, show a footprint on the map if record.bbox is not None: points = bbox_to_polygon(record.bbox) if points is not None: src = QgsCoordinateReferenceSystem(4326) dst = self.map.mapSettings().destinationCrs() geom = QgsGeometry.fromPolygon(points) if src.postgisSrid() != dst.postgisSrid(): ctr = QgsCoordinateTransform(src, dst) try: geom.transform(ctr) except Exception as err: QMessageBox.warning( self, self.tr('Coordinate Transformation Error'), unicode(err)) self.rubber_band.setToGeometry(geom, None) # figure out if the data is interactive and can be operated on self.find_services(record, item) def find_services(self, record, item): """scan record for WMS/WMTS|WFS|WCS endpoints""" links = record.uris + record.references services = {} for link in links: if 'scheme' in link: link_type = link['scheme'] elif 'protocol' in link: link_type = link['protocol'] else: link_type = None if link_type is not None: link_type = link_type.upper() wmswmst_link_types = map(str.upper, link_types.WMSWMST_LINK_TYPES) wfs_link_types = map(str.upper, link_types.WFS_LINK_TYPES) wcs_link_types = map(str.upper, link_types.WCS_LINK_TYPES) # if the link type exists, and it is one of the acceptable # interactive link types, then set if all([link_type is not None, link_type in wmswmst_link_types + wfs_link_types + wcs_link_types]): if link_type in wmswmst_link_types: services['wms'] = link['url'] self.btnAddToWms.setEnabled(True) if link_type in wfs_link_types: services['wfs'] = link['url'] self.btnAddToWfs.setEnabled(True) if link_type in wcs_link_types: services['wcs'] = link['url'] self.btnAddToWcs.setEnabled(True) set_item_data(item, 'link', json.dumps(services)) def navigate(self): """manage navigation / paging""" caller = self.sender().objectName() if caller == 'btnFirst': self.startfrom = 0 elif caller == 'btnLast': self.startfrom = self.catalog.results['matches'] - self.maxrecords elif caller == 'btnNext': self.startfrom += self.maxrecords if self.startfrom >= self.catalog.results["matches"]: msg = self.tr('End of results. Go to start?') res = QMessageBox.information(self, self.tr('Navigation'), msg, (QMessageBox.Ok | QMessageBox.Cancel)) if res == QMessageBox.Ok: self.startfrom = 0 else: return elif caller == "btnPrev": self.startfrom -= self.maxrecords if self.startfrom <= 0: msg = self.tr('Start of results. Go to end?') res = QMessageBox.information(self, self.tr('Navigation'), msg, (QMessageBox.Ok | QMessageBox.Cancel)) if res == QMessageBox.Ok: self.startfrom = (self.catalog.results['matches'] - self.maxrecords) else: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: self.catalog.getrecords2(constraints=self.constraints, maxrecords=self.maxrecords, startposition=self.startfrom, esn='full') except ExceptionReport as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('Search error'), self.tr('Search error: %s') % err) return except Exception as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('Connection error'), self.tr('Connection error: %s') % err) return QApplication.restoreOverrideCursor() self.display_results() def add_to_ows(self): """add to OWS provider connection list""" conn_name_matches = [] item = self.treeRecords.currentItem() if not item: return item_data = json.loads(get_item_data(item, 'link')) caller = self.sender().objectName() # stype = human name,/Qgis/connections-%s,providername if caller == 'btnAddToWms': stype = ['OGC:WMS/OGC:WMTS', 'wms', 'wms'] data_url = item_data['wms'] elif caller == 'btnAddToWfs': stype = ['OGC:WFS', 'wfs', 'WFS'] data_url = item_data['wfs'] elif caller == 'btnAddToWcs': stype = ['OGC:WCS', 'wcs', 'wcs'] data_url = item_data['wcs'] QApplication.restoreOverrideCursor() sname = '%s from MetaSearch' % stype[1] # store connection # check if there is a connection with same name self.settings.beginGroup('/Qgis/connections-%s' % stype[1]) keys = self.settings.childGroups() self.settings.endGroup() for key in keys: if key.startswith(sname): conn_name_matches.append(key) if conn_name_matches: sname = conn_name_matches[-1] # check for duplicates if sname in keys: # duplicate found if self.radioTitleAsk.isChecked(): # ask to overwrite msg = self.tr('Connection %s exists. Overwrite?') % sname res = QMessageBox.warning(self, self.tr('Saving server'), msg, QMessageBox.Yes | QMessageBox.No) if res != QMessageBox.Yes: # assign new name with serial sname = serialize_string(sname) elif self.radioTitleNoAsk.isChecked(): # don't ask to overwrite pass elif self.radioTempName.isChecked(): # use temp name sname = serialize_string(sname) # no dups detected or overwrite is allowed self.settings.beginGroup('/Qgis/connections-%s' % stype[1]) self.settings.setValue('/%s/url' % sname, data_url) self.settings.endGroup() # open provider window ows_provider = QgsProviderRegistry.instance().selectWidget(stype[2], self) service_type = stype[0] # connect dialog signals to iface slots if service_type == 'OGC:WMS/OGC:WMTS': ows_provider.addRasterLayer.connect(self.iface.addRasterLayer) conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections') connect = 'on_btnConnect_clicked' elif service_type == 'OGC:WFS': ows_provider.addWfsLayer.connect(self.iface.mainWindow().addWfsLayer) conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections') connect = 'connectToServer' elif service_type == 'OGC:WCS': ows_provider.addRasterLayer.connect(self.iface.addRasterLayer) conn_cmb = ows_provider.findChild(QWidget, 'mConnectionsComboBox') connect = 'on_mConnectButton_clicked' ows_provider.setModal(False) ows_provider.show() # open provider dialogue against added OWS index = conn_cmb.findText(sname) if index > -1: conn_cmb.setCurrentIndex(index) # only for wfs if service_type == 'OGC:WFS': ows_provider.on_cmbConnections_activated(index) getattr(ows_provider, connect)() def show_metadata(self): """show record metadata""" if not self.treeRecords.selectedItems(): return item = self.treeRecords.currentItem() if not item: return identifier = get_item_data(item, 'identifier') try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) cat = CatalogueServiceWeb(self.catalog_url, timeout=self.timeout) cat.getrecordbyid( [self.catalog.records[identifier].identifier]) except ExceptionReport as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('GetRecords error'), self.tr('Error getting response: %s') % err) return except KeyError as err: QMessageBox.warning(self, self.tr('Record parsing error'), 'Unable to locate record identifier') QApplication.restoreOverrideCursor() return QApplication.restoreOverrideCursor() record = cat.records[identifier] record.xml_url = cat.request crd = RecordDialog() metadata = render_template('en', self.context, record, 'record_metadata_dc.html') style = QgsApplication.reportStyleSheet() crd.textMetadata.document().setDefaultStyleSheet(style) crd.textMetadata.setHtml(metadata) crd.exec_() def show_xml(self): """show XML request / response""" crd = XMLDialog() request_html = highlight_xml(self.context, self.catalog.request) response_html = highlight_xml(self.context, self.catalog.response) style = QgsApplication.reportStyleSheet() crd.txtbrXMLRequest.clear() crd.txtbrXMLResponse.clear() crd.txtbrXMLRequest.document().setDefaultStyleSheet(style) crd.txtbrXMLResponse.document().setDefaultStyleSheet(style) crd.txtbrXMLRequest.setHtml(request_html) crd.txtbrXMLResponse.setHtml(response_html) crd.exec_() def reset_buttons(self, services=True, xml=True, navigation=True): """Convenience function to disable WMS/WMTS|WFS|WCS buttons""" if services: self.btnAddToWms.setEnabled(False) self.btnAddToWfs.setEnabled(False) self.btnAddToWcs.setEnabled(False) if xml: self.btnShowXml.setEnabled(False) if navigation: self.btnFirst.setEnabled(False) self.btnPrev.setEnabled(False) self.btnNext.setEnabled(False) self.btnLast.setEnabled(False) def help(self): """launch help""" open_url(get_help_url()) def reject(self): """back out of dialogue""" QDialog.reject(self) self.rubber_band.reset() def _get_csw(self): """convenience function to init owslib.csw.CatalogueServiceWeb""" # connect to the server try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.catalog = CatalogueServiceWeb(self.catalog_url, timeout=self.timeout) return True except ExceptionReport as err: msg = self.tr('Error connecting to service: %s') % err except ValueError as err: msg = self.tr('Value Error: %s') % err except Exception as err: msg = self.tr('Unknown Error: %s') % err QMessageBox.warning(self, self.tr('CSW Connection error'), msg) QApplication.restoreOverrideCursor() return False def install_proxy(self): """set proxy if one is set in QGIS network settings""" # initially support HTTP for now if self.settings.value('/proxy/proxyEnabled') == 'true': if self.settings.value('/proxy/proxyType') == 'HttpProxy': ptype = 'http' else: return user = self.settings.value('/proxy/proxyUser') password = self.settings.value('/proxy/proxyPassword') host = self.settings.value('/proxy/proxyHost') port = self.settings.value('/proxy/proxyPort') proxy_up = '' proxy_port = '' if all([user != '', password != '']): proxy_up = '%s:%s@' % (user, password) if port != '': proxy_port = ':%s' % port conn = '%s://%s%s%s' % (ptype, proxy_up, host, proxy_port) install_opener(build_opener(ProxyHandler({ptype: conn})))
class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) self.firstshow = True self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) if hasattr(self.canvas, 'setParallelRenderingEnabled'): self.canvas.setParallelRenderingEnabled(True) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) gpsspacewidget= QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.marker = GPSMarker(self.canvas) self.marker.hide() self.currentfeatureband = QgsRubberBand(self.canvas) self.currentfeatureband.setIconSize(20) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 76)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(0, 0, 212, 76)) self.gpsband.setWidth(5) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.featureformloaded.connect(self.feature_form_loaded) self.connectButtons() def init_qgisproject(self, doc): parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0]; #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0]; #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0]; #color = QColor(red, green, blue); #self.canvas.setCanvasColor(color) self.canvas.updateScale() return self.canvas.mapRenderer().destinationCrs() def showEvent(self, *args, **kwargs): if self.firstshow: self.canvas.refresh() self.canvas.repaint() self.firstshow = False def feature_form_loaded(self, form, feature, project, editmode): self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): self.clear_selection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 200)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def highlight_active_selection(self, layer, feature, features): self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def clear_selection(self): # Clear the main selection rubber band self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() break self.editfeaturestack.append((form, feature)) self.load_form(form) trigger_default_action() def clear_temp_objects(self): def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging def set_gps(self, gps, logging): self.gps = gps self.gpslogging = logging self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) def gps_update_canvas(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.zoom_to_location(position) self.marker.show() self.marker.setCenter(position) def gps_first_fix(self, postion, gpsinfo): zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): rect = QgsRectangle(position, position) self.canvas.setExtent(rect) self.canvas.refresh() def gps_disconnected(self): self.marker.hide() def select_data_entry(self): def showformerror(form): pass def actions(): for form in self.project.forms: action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format(form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form") formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): self.project = project self.actionPan.trigger() try: firstform = project.forms[0] self.load_form(firstform) self.dataentryselection.setVisible(True) except IndexError: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.freeze(False) self.canvas.refresh() def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24,24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def load_form(self, form): self.clearCapatureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) def create_capture_buttons(self, form): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showUIMessage, form.label)) def add_new_feature(self, form, geometry): """ Add a new new feature to the given layer """ # TODO Extract into function. # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name() == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value RoamEvents.open_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def cleanup(self): self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clearCapatureTools() self.canvas.freeze() self.canvas.clear() self.canvas.freeze(False) for action in self.layerbuttons: self.editgroup.removeAction(action)
class teamqgisDock(QDockWidget, Ui_teamqgis): dockRemoved = pyqtSignal(str) def __init__(self, iface, layer, currentFeature): self.iface = iface self.layer = layer self.proj = QgsProject.instance() self.renderer = self.iface.mapCanvas().mapRenderer() self.settings = MySettings() QDockWidget.__init__(self) self.setupUi(self) # Track attr warnings so they are not repeated for multiple items self.warned_attr_values = [] self.setWindowTitle("teamqgis: %s" % layer.name()) if layer.hasGeometryType() is False: self.panCheck.setChecked(False) self.panCheck.setEnabled(False) self.scaleCheck.setChecked(False) self.scaleCheck.setEnabled(False) self.previousButton.setArrowType(Qt.LeftArrow) self.nextButton.setArrowType(Qt.RightArrow) icon = QIcon(":/plugins/teamqgis/icons/openform.svg") self.editFormButton.setIcon(icon) # actions icon = QIcon(":/plugins/teamqgis/icons/action.svg") self.actionButton.setIcon(icon) self.attrAction = layer.actions() actions = [self.attrAction[i] for i in range(self.attrAction.size())] preferredAction = layer.customProperty("teamqgisPreferedAction", "") if preferredAction not in actions: dfltAction = self.attrAction.defaultAction() if dfltAction > len(actions): preferredAction = self.attrAction[dfltAction].name() preferredActionFound = False for i, action in enumerate(actions): qAction = QAction(QIcon(":/plugins/teamqgis/icons/action.svg"), action.name(), self) qAction.triggered.connect(lambda: self.doAction(i)) self.actionButton.addAction(qAction) if action.name() == preferredAction: self.actionButton.setDefaultAction(qAction) preferredActionFound = True if len(actions) == 0: self.actionButton.setEnabled(False) elif not preferredActionFound: self.actionButton.setDefaultAction(self.actionButton.actions()[0]) self.nameComboBoxes = [self.fieldOneNameComboBox, self.fieldTwoNameComboBox, self.fieldThreeNameComboBox] self.valueComboBoxes = [self.fieldOneValueComboBox, self.fieldTwoValueComboBox, self.fieldThreeValueComboBox] self.updateNameComboBoxes() # Restore saved nameComboBox current indices if they exist for nameComboBox in self.nameComboBoxes: fieldName = self.layer.customProperty("teamqgis" + nameComboBox.objectName()) if fieldName != None: nameComboBox.setCurrentIndex(nameComboBox.findText(fieldName)) self.rubber = QgsRubberBand(self.iface.mapCanvas()) self.selectionChanged() if currentFeature == self.listCombo.currentIndex(): self.on_listCombo_currentIndexChanged(currentFeature) else: self.listCombo.setCurrentIndex(currentFeature) self.layer.layerDeleted.connect(self.close) self.layer.selectionChanged.connect(self.selectionChanged) self.layer.layerModified.connect(self.layerChanged) self.layer.editingStopped.connect(self.editingStopped) self.layer.editingStarted.connect(self.editingStarted) QObject.connect(self.proj, SIGNAL("allowedClassesChanged()"), self.updateValueComboBoxes) def updateNameComboBoxes(self): fieldNameMap = self.layer.dataProvider().fieldNameMap() allFields = fieldNameMap.keys() if 'ID' in allFields: allFields.remove('ID') if 'FID' in allFields: allFields.remove('FID') for nameComboBox in self.nameComboBoxes: nameComboBox.clear() nameComboBox.addItems(allFields) def updateValueComboBoxes(self): feature = self.getCurrentItem() for (valueComboBox, nameComboBox) in zip(self.valueComboBoxes, self.nameComboBoxes): valueComboBox.clear() allowedClasses, hasAllowedClasses = self.proj.readListEntry("teamqgis", "allowedClasses") if hasAllowedClasses: valueComboBox.addItems(allowedClasses) attr_value = str(feature[nameComboBox.currentText()]) if (allowedClasses == None) or (attr_value not in allowedClasses) and (attr_value not in self.warned_attr_values): self.iface.messageBar().pushMessage("Class name not in allowed class list", 'Assign an allowed class or add "%s" to allowed class list'%attr_value, level=QgsMessageBar.WARNING, duration=3) self.warned_attr_values.append(attr_value) valueComboBox.addItem(attr_value) valueComboBox.setCurrentIndex(valueComboBox.findText(attr_value)) def setRubber(self, feature): self.rubber.setColor(self.settings.value("rubberColor")) self.rubber.setWidth(self.settings.value("rubberWidth")) ##self.rubber.setLineStyle(Qt.DotLine) self.rubber.setBrushStyle(Qt.NoBrush) self.rubber.setToGeometry(feature.geometry(), self.layer) def closeEvent(self, e): self.rubber.reset() self.layer.layerDeleted.disconnect(self.close) self.layer.selectionChanged.disconnect(self.selectionChanged) self.layer.layerModified.disconnect(self.layerChanged) self.layer.editingStopped.disconnect(self.editingStopped) self.layer.editingStarted.disconnect(self.editingStarted) if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("teamqgisSelection", repr([])) self.dockRemoved.emit(self.layer.id()) def selectionChanged(self): self.cleanBrowserFields() self.rubber.reset() nItems = self.layer.selectedFeatureCount() if nItems < 1: self.close() self.layer.emit(SIGNAL("browserNoItem()")) return self.browseFrame.setEnabled(True) self.subset = self.layer.selectedFeaturesIds() if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("teamqgisSelection", repr(self.subset)) for fid in self.subset: self.listCombo.addItem("%u" % fid) self.setRubber(self.getCurrentItem()) self.updateValueComboBoxes() def layerChanged(self): self.applyChangesButton.setEnabled(True) def editingStarted(self): for valueComboBox in self.valueComboBoxes: valueComboBox.setEnabled(True) self.translateRightButton.setEnabled(True) self.translateLeftButton.setEnabled(True) self.translateUpButton.setEnabled(True) self.translateDownButton.setEnabled(True) self.editFormButton.setDown(True) def editingStopped(self): self.applyChangesButton.setEnabled(False) for valueComboBox in self.valueComboBoxes: valueComboBox.setEnabled(False) self.translateRightButton.setEnabled(False) self.translateLeftButton.setEnabled(False) self.translateUpButton.setEnabled(False) self.translateDownButton.setEnabled(False) self.editFormButton.setDown(False) def cleanBrowserFields(self): self.currentPosLabel.setText('0/0') self.listCombo.clear() def panScaleToItem(self, feature): if self.panCheck.isChecked() is False: return featBobo = feature.geometry().boundingBox() # if scaling and bobo has width and height (i.e. not a point) if self.scaleCheck.isChecked() and featBobo.width() != 0 and featBobo.height() != 0: featBobo.scale(self.settings.value("scale")) ul = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMaximum())) ur = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMaximum())) ll = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMinimum())) lr = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMinimum())) x = (ul.x(), ur.x(), ll.x(), lr.x()) y = (ul.y(), ur.y(), ll.y(), lr.y()) x0 = min(x) y0 = min(y) x1 = max(x) y1 = max(y) else: panTo = self.renderer.layerToMapCoordinates(self.layer, featBobo.center()) mapBobo = self.iface.mapCanvas().extent() xshift = panTo.x() - mapBobo.center().x() yshift = panTo.y() - mapBobo.center().y() x0 = mapBobo.xMinimum() + xshift y0 = mapBobo.yMinimum() + yshift x1 = mapBobo.xMaximum() + xshift y1 = mapBobo.yMaximum() + yshift self.iface.mapCanvas().setExtent(QgsRectangle(x0, y0, x1, y1)) self.iface.mapCanvas().refresh() def getCurrentItem(self): i = self.listCombo.currentIndex() if i == -1: return None f = QgsFeature() if self.layer.getFeatures(QgsFeatureRequest().setFilterFid(self.subset[i])).nextFeature(f): return f else: raise NameError("feature not found") def doAction(self, i): f = self.getCurrentItem() self.actionButton.setDefaultAction(self.actionButton.actions()[i]) self.layer.setCustomProperty("teamqgisPreferedAction", self.attrAction[i].name()) self.attrAction.doActionFeature(i, f) def doTranslate(self, trans): # Based on the "doaffine" function in the qgsAffine plugin if (self.layer.geometryType() == 2): start=1 else: start=0 if (not self.layer.isEditable()): self.iface.messageBar().pushMessage("Layer not in edit mode", 'Select a vector layer and choose "Toggle Editing"', level=QgsMessageBar.WARNING) else: feature = self.getCurrentItem() result = feature.geometry() i = start vertex = result.vertexAt(i) fid = feature.id() while (vertex != QgsPoint(0, 0)): newx = vertex.x() + trans[0] * float(self.settings.value("xres")) newy = vertex.y() + trans[1] * float(self.settings.value("yres")) result.moveVertex(newx, newy, i) i += 1 vertex = result.vertexAt(i) self.layer.changeGeometry(fid, result) self.iface.mapCanvas().refresh() self.rubber.reset() self.setRubber(feature) def changeAttribute(self, i, fieldNameComboBox, fieldValueComboBox): fieldValueComboBox.setCurrentIndex(i) feature = self.getCurrentItem() attr_index = self.layer.dataProvider().fieldNameMap()[fieldNameComboBox.currentText()] self.layer.changeAttributeValue(feature.id(), attr_index, fieldValueComboBox.currentText()) self.iface.mapCanvas().refresh() self.updateValueComboBoxes() def nameComboBox_activated(self, i, nameComboBox): self.layer.setCustomProperty('teamqgis' + nameComboBox.objectName(), nameComboBox.currentText()) @pyqtSlot(name="on_previousButton_clicked") def previousFeature(self): i = self.listCombo.currentIndex() n = max(0, i-1) self.listCombo.setCurrentIndex(n) self.saveCurrentFeature(n) @pyqtSlot(name="on_nextButton_clicked") def nextFeature(self): self.warned_attr_values = [] # Reset attr warnings i = self.listCombo.currentIndex() c = self.listCombo.count() n = min(i+1, c-1) self.listCombo.setCurrentIndex(n) self.saveCurrentFeature(n) @pyqtSlot(int, name="on_listCombo_activated") def saveCurrentFeature(self, i): if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("teamqgisCurrentItem", i) @pyqtSlot(int, name="on_fieldOneNameComboBox_activated") def fieldOneNameComboBox_activated(self, i): self.nameComboBox_activated(i, self.fieldOneNameComboBox) @pyqtSlot(int, name="on_fieldTwoNameComboBox_activated") def fieldTwoNameComboBox_activated(self, i): self.nameComboBox_activated(i, self.fieldTwoNameComboBox) @pyqtSlot(int, name="on_fieldThreeNameComboBox_activated") def fieldThreeNameComboBox_activated(self, i): self.nameComboBox_activated(i, self.fieldThreeNameComboBox) @pyqtSlot(int, name="on_listCombo_currentIndexChanged") def on_listCombo_currentIndexChanged(self, i): feature = self.getCurrentItem() if feature is None: return self.rubber.reset() if self.listCombo.count() > 1: self.setRubber(feature) self.updateValueComboBoxes() # scale to feature self.panScaleToItem(feature) # Update browser self.currentPosLabel.setText("%u/%u" % (i+1, len(self.subset))) # emit signal self.layer.emit(SIGNAL("browserCurrentItem(long)"), feature.id()) @pyqtSlot(int, name="on_panCheck_stateChanged") def on_panCheck_stateChanged(self, i): if self.panCheck.isChecked(): self.scaleCheck.setEnabled(True) feature = self.getCurrentItem() if feature is None: return self.panScaleToItem(feature) else: self.scaleCheck.setEnabled(False) @pyqtSlot(int, name="on_scaleCheck_stateChanged") def on_scaleCheck_stateChanged(self, i): if self.scaleCheck.isChecked(): feature = self.getCurrentItem() if feature is None: return self.panScaleToItem(feature) @pyqtSlot(name="on_editFormButton_clicked") def openFeatureForm(self): if (self.layer.isEditable()): self.layer.commitChanges() else: self.layer.startEditing() @pyqtSlot(name="on_translateRightButton_clicked") def doTranslateRight(self): self.doTranslate((1, 0)) @pyqtSlot(name="on_translateLeftButton_clicked") def doTranslateLeft(self): self.doTranslate((-1, 0)) @pyqtSlot(name="on_translateUpButton_clicked") def doTranslateUp(self): self.doTranslate((0, 1)) @pyqtSlot(name="on_translateDownButton_clicked") def doTranslateDown(self): self.doTranslate((0, -1)) @pyqtSlot(name="on_applyChangesButton_clicked") def applyChanges(self): self.layer.commitChanges() self.layer.startEditing() self.layer.updateExtents() self.iface.mapCanvas().refresh() @pyqtSlot(int, name="on_fieldOneValueComboBox_activated") def on_fieldOneValueComboBox_activated(self, i): self.changeAttribute(i, self.fieldOneNameComboBox, self.fieldOneValueComboBox) @pyqtSlot(int, name="on_fieldTwoValueComboBox_activated") def on_fieldTwoValueComboBox_activated(self, i): self.changeAttribute(i, self.fieldTwoNameComboBox, self.fieldTwoValueComboBox) @pyqtSlot(int, name="on_fieldThreeValueComboBox_activated") def on_fieldThreeValueComboBox_activated(self, i): self.changeAttribute(i, self.fieldThreeNameComboBox, self.fieldThreeValueComboBox)
class AuditDialog(QDialog, Ui_audit, SettingDialog): rejectShowEvent = pyqtSignal() performSearchAtShowEvent = pyqtSignal() def __init__(self, iface, layerId=None, featureId=None): QDialog.__init__(self) self.setupUi(self) self.settings = MySettings() SettingDialog.__init__(self, self.settings, False, True) # column chooser, advanced search options #init variables self.layerId = layerId self.featureId = featureId self.layer = None self.rubber = QgsRubberBand(iface.mapCanvas()) self.mapCanvas = iface.mapCanvas() self.resuts = dict() # connect "pan and show geometry" check box to draw in rubber band self.panShowGeometry.clicked.connect(self.displayGeomDifference) # reject properly showEvent if checking fails self.rejectShowEvent.connect(self.reject, Qt.QueuedConnection) # start search directly at the end of showEvent if enough params self.performSearchAtShowEvent.connect(self.on_searchButton_clicked, Qt.QueuedConnection) # setup layer - field combo, with primary key selector as field self.layerComboManager = VectorLayerCombo(self.layerCombo, layerId, {"dataProvider": "postgres", "finishInit": False, "skipLayers": [lambda: self.settings.value("logLayer")]}) self.layerComboManager.finishInit() # log layer self.logLayer = LogLayer() self.logLayer.setProgressMax.connect(self.progressBar.setMaximum) self.logLayer.setProgressMin.connect(self.progressBar.setMinimum) self.logLayer.setProgressValue.connect(self.progressBar.setValue) # logged actions table self.loggedActionsLayout = QGridLayout(self.loggedActionsWidget) self.loggedActionsTable = LoggedActionsTable(self.loggedActionsWidget) self.loggedActionsLayout.addWidget(self.loggedActionsTable, 0, 0, 1, 1) self.loggedActionsTable.itemSelectionChanged.connect(self.displayDifference) # difference viewer self.differenceLayout = QGridLayout(self.differenceViewerWidget) self.differenceViewer = DifferenceViewer(self.differenceViewerWidget) self.differenceLayout.addWidget(self.differenceViewer, 0, 0, 1, 1) # set dates now = QDateTime.currentDateTime() self.searchBeforeDate.setDateTime(now) self.searchAfterDate.setDateTime(now.addDays(-7)) # finish ui self.buttonDisplayMode(False) self.restoreButton.setEnabled(False) if featureId is not None: self.featureEdit.setText("%s" % featureId) self.adjustSize() def closeEvent(self, e): self.rubber.reset() def showEvent(self, e): SettingDialog.showEvent(self, e) while not self.logLayer.isValid(): if not LoggedActionsTableChooserDialog().exec_(): self.rejectShowEvent.emit() return if self.layerId is not None: self.layerCombo.setEnabled(False) layer = self.layerComboManager.getLayer() if layer is None: self.rejectShowEvent.emit() return if self.featureId is not None: self.featureEdit.setEnabled(False) f = QgsFeature() featReq = QgsFeatureRequest().setFilterFid(self.featureId).setFlags(QgsFeatureRequest.NoGeometry) if layer.getFeatures(featReq).nextFeature(f) is False: self.rejectShowEvent.emit() return self.performSearchAtShowEvent.emit() else: layer = self.mapCanvas.currentLayer() self.layerComboManager.setLayer(layer) @pyqtSignature("on_layerCombo_currentIndexChanged(int)") def on_layerCombo_currentIndexChanged(self, i): self.layer = self.layerComboManager.getLayer() self.panShowGeometry.setEnabled(self.layer is not None and self.layer.hasGeometryType()) @pyqtSignature("on_stopButton_clicked()") def on_stopButton_clicked(self): self.logLayer.interrupt() @pyqtSignature("on_searchButton_clicked()") def on_searchButton_clicked(self): self.layer = self.layerComboManager.getLayer() pkeyName = primaryKey(self.layer) if self.layer is None or pkeyName is None: return self.loggedActionsTable.geomColumn = self.layer.hasGeometryType() featureId = int(self.featureEdit.text() or 0) searchBeforeDate = QDateTime() if self.searchBefore.isChecked(): searchBeforeDate = self.searchAfterDate.dateTime() searchAfterDate = QDateTime() if self.searchAfter.isChecked(): searchAfterDate = self.searchAfterDate.dateTime() self.buttonDisplayMode(True) self.results = self.logLayer.performSearch(self.layer, featureId, pkeyName, self.searchInserts.isChecked(), self.searchUpdates.isChecked(), self.searchDeletes.isChecked(), self.searchOnlyGeometry.isChecked(), searchAfterDate, searchBeforeDate) self.buttonDisplayMode(False) self.panShowGeometry.setEnabled(self.layer.hasGeometryType()) self.displayLoggedActions() def buttonDisplayMode(self, searchOn): self.searchButton.setVisible(not searchOn) self.stopButton.setVisible(searchOn) self.progressBar.setVisible(searchOn) def displayLoggedActions(self): self.differenceViewer.clearRows() self.loggedActionsTable.displayColumns() self.loggedActionsTable.displayRows(self.results) def displayDifference(self): self.differenceViewer.clearRows() self.restoreButton.setEnabled(False) item = self.loggedActionsTable.selectedItems() if len(item) == 0: return rowId = item[0].data(Qt.UserRole) logRow = self.results[rowId] if logRow.featureLayer.isEditable(): self.restoreButton.setEnabled(True) self.differenceViewer.display(logRow) self.displayGeomDifference() def displayGeomDifference(self): self.rubber.reset() item = self.loggedActionsTable.selectedItems() if len(item) == 0: return rowId = item[0].data(Qt.UserRole) logRow = self.results[rowId] if self.layer.hasGeometryType() and self.panShowGeometry.isChecked(): geom = logRow.geometry() self.rubber.setToGeometry(geom, self.layer) panTo = self.mapCanvas.mapRenderer().layerExtentToOutputExtent(self.layer, geom.boundingBox()) panTo.scale(1.5) self.mapCanvas.setExtent(panTo) self.mapCanvas.refresh() @pyqtSignature("on_columnChooserButton_clicked()") def on_columnChooserButton_clicked(self): ColumnChooserDialog().exec_() self.loggedActionsTable.displayColumns() self.loggedActionsTable.displayRows(self.results) @pyqtSignature("on_restoreButton_clicked()") def on_restoreButton_clicked(self): item = self.loggedActionsTable.selectedItems() if len(item) == 0: return rowId = item[0].data(Qt.UserRole) logRow = self.results[rowId] if not logRow.featureLayer.isEditable(): return logRow.restoreFeature() self.mapCanvas.refresh()
class DEMto3DDialog(QtGui.QDialog, Ui_DEMto3DDialogBase): # Layer to print layer = None ''' Region of interest properties ''' map_crs = None roi_x_max = 0 roi_x_min = 0 roi_y_max = 0 roi_y_min = 0 z_max = 0 z_min = 0 ''' Model dimensions ''' height = 0 width = 0 scale = 0 z_scale = 0 ''' Raster properties ''' cell_size = 0 cols = 0 rows = 0 raster_x_max = 0 raster_x_min = 0 raster_y_max = 0 raster_y_min = 0 def __init__(self, iface): """Constructor.""" QDialog.__init__(self) self.ui = Ui_DEMto3DDialogBase() self.ui.setupUi(self) self.iface = iface self.canvas = iface.mapCanvas() try: self.map_crs = self.canvas.mapSettings().destinationCrs() except: self.map_crs = self.canvas.mapRenderer().destinationCrs() # region Layer action # fill layer combobox with raster visible layers in mapCanvas self.viewLayers = self.canvas.layers() self.ui.LayerComboBox.clear() for layer in self.viewLayers: if layer.type() == 1: self.ui.LayerComboBox.addItem(layer.name()) self.layer = get_layer(self.ui.LayerComboBox.currentText()) self.get_raster_properties() QtCore.QObject.connect(self.ui.LayerComboBox, QtCore.SIGNAL(_fromUtf8("activated(QString)")), self.get_layer) # endregion # region Extension actions self.extent = None QtCore.QObject.connect(self.ui.FullExtToolButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.full_extent) QtCore.QObject.connect(self.ui.LayerExtToolButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.layer_extent) QtCore.QObject.connect(self.ui.CustomExtToolButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.custom_extent) QtCore.QObject.connect(self.ui.XMinLineEdit, QtCore.SIGNAL(_fromUtf8("returnPressed()")), self.upload_extent) QtCore.QObject.connect(self.ui.XMaxLineEdit, QtCore.SIGNAL(_fromUtf8("returnPressed()")), self.upload_extent) QtCore.QObject.connect(self.ui.YMaxLineEdit, QtCore.SIGNAL(_fromUtf8("returnPressed()")), self.upload_extent) QtCore.QObject.connect(self.ui.YMinLineEdit, QtCore.SIGNAL(_fromUtf8("returnPressed()")), self.upload_extent) # endregion # region Dimension actions QtCore.QObject.connect(self.ui.HeightLineEdit, QtCore.SIGNAL(_fromUtf8("textEdited(QString)")), self.upload_size_from_height) QtCore.QObject.connect(self.ui.WidthLineEdit, QtCore.SIGNAL(_fromUtf8("textEdited(QString)")), self.upload_size_from_width) QtCore.QObject.connect(self.ui.ScaleLineEdit, QtCore.SIGNAL(_fromUtf8("textEdited(QString)")), self.upload_size_from_scale) # endregion QtCore.QObject.connect(self.ui.ZScaleDoubleSpinBox, QtCore.SIGNAL(_fromUtf8("valueChanged(double)")), self.get_height_model) QtCore.QObject.connect(self.ui.BaseHeightLineEdit, QtCore.SIGNAL(_fromUtf8("textEdited(QString)")), self.get_height_model) # region Cancel, export, print buttons QtCore.QObject.connect(self.ui.CancelToolButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.reject) QtCore.QObject.connect(self.ui.STLToolButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.do_export) close = QtGui.QAction(self) self.connect(close, QtCore.SIGNAL('clicked()'), self.reject) # endregion def do_export(self): parameters = self.get_parameters() layer_name = self.ui.LayerComboBox.currentText() + '_model.stl' if parameters != 0: if parameters["spacing_mm"] < 0.5 and self.height > 100 and self.width > 100: reply = QMessageBox.question(self, self.tr('Export to STL'), self.tr('The construction of the STL file could takes several minutes. Do you want to continue?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: f = QFileDialog.getSaveFileNameAndFilter(self, self.tr('Export to STL'), layer_name, filter=".stl") stl_file = f[0] if stl_file: export_dlg = Export_dialog.Dialog(parameters, stl_file) if export_dlg.exec_(): QMessageBox.information(self, self.tr("Attention"), self.tr("STL model generated")) else: QMessageBox.information(self, self.tr("Attention"), self.tr("Process canceled")) else: f = QFileDialog.getSaveFileNameAndFilter(self, self.tr('Export to STL'), layer_name, filter=".stl") stl_file = f[0] if stl_file: export_dlg = Export_dialog.Dialog(parameters, stl_file) if export_dlg.exec_(): QMessageBox.information(self, self.tr("Attention"), self.tr("STL model generated")) else: QMessageBox.information(self, self.tr("Attention"), self.tr("Process canceled")) else: QMessageBox.warning(self, self.tr("Attention"), self.tr("Fill the data correctly")) def get_layer(self, layer_name): if self.layer.name() != layer_name: self.ini_dialog() layermap = QgsMapLayerRegistry.instance().mapLayers() for name, layer in layermap.iteritems(): if layer.name() == layer_name: if layer.isValid(): self.layer = layer self.get_raster_properties() else: self.layer = None def ini_dialog(self): self.ui.XMaxLineEdit.clear() self.ui.XMinLineEdit.clear() self.ui.YMaxLineEdit.clear() self.ui.YMinLineEdit.clear() if self.extent: self.canvas.scene().removeItem(self.extent) self.extent = None self.ini_dimensions() self.ui.ZMaxLabel.setText('0 m') self.ui.ZMinLabel.setText('0 m') def ini_dimensions(self): self.ui.HeightLineEdit.clear() self.height = 0 self.ui.WidthLineEdit.clear() self.width = 0 self.ui.ScaleLineEdit.clear() self.scale = 0 self.ui.RecomSpacinglabel.setText('0.2 mm') self.ui.BaseHeightLineEdit.clear() self.ui.HeightModelLabel.setText('0 mm') def get_raster_properties(self): self.cell_size = self.layer.rasterUnitsPerPixelX() self.rows = self.layer.height() self.cols = self.layer.width() rec = self.layer.extent() self.raster_x_max = rec.xMaximum() self.raster_x_min = rec.xMinimum() self.raster_y_max = rec.yMaximum() self.raster_y_min = rec.yMinimum() # region Extension functions def full_extent(self): rec = self.canvas.fullExtent() self.paint_extent(rec) self.get_z_max_z_min() self.ini_dimensions() def layer_extent(self): layers = self.iface.legendInterface().layers() select_layer_dialog = SelectLayer_dialog.Dialog(layers) if select_layer_dialog.exec_(): layer = select_layer_dialog.get_layer() if layer: rec = get_layer(layer).extent() source = self.layer.crs() target = self.map_crs if source != target: transform = QgsCoordinateTransform(source, target) rec = transform.transform(rec) self.paint_extent(rec) self.get_z_max_z_min() self.ini_dimensions() def custom_extent(self): self.iface.messageBar().pushMessage("Info", self.tr("Click and drag the mouse to draw print extent"), level=QgsMessageBar.INFO, duration=3) if self.extent: self.canvas.scene().removeItem(self.extent) self.extent = None ct = RectangleMapTool(self.canvas, self.get_custom_extent) self.canvas.setMapTool(ct) def get_custom_extent(self, rec): layer_extension = self.layer.extent() source = self.layer.crs() target = self.map_crs if source != target: transform = QgsCoordinateTransform(source, target) layer_extension = transform.transform(layer_extension) if rec.intersects(layer_extension): extension = rec.intersect(layer_extension) self.paint_extent(extension) self.iface.actionPan().trigger() self.get_z_max_z_min() self.ini_dimensions() else: QMessageBox.warning(self, self.tr("Attention"), self.tr("Print extent defined outside layer extent")) def upload_extent(self): try: self.roi_x_max = float(self.ui.XMaxLineEdit.text()) self.roi_x_min = float(self.ui.XMinLineEdit.text()) self.roi_y_max = float(self.ui.YMaxLineEdit.text()) self.roi_y_min = float(self.ui.YMinLineEdit.text()) rec = QgsRectangle(self.roi_x_min, self.roi_y_min, self.roi_x_max, self.roi_y_max) self.paint_extent(rec) self.get_z_max_z_min() self.ini_dimensions() except ValueError: QMessageBox.warning(self, self.tr("Attention"), self.tr("Value entered incorrect")) def paint_extent(self, rec): self.roi_x_max = rec.xMaximum() self.ui.XMaxLineEdit.setText(str(round(rec.xMaximum(), 3))) self.roi_y_min = rec.yMinimum() self.ui.YMinLineEdit.setText(str(round(rec.yMinimum(), 3))) self.roi_x_min = rec.xMinimum() self.ui.XMinLineEdit.setText(str(round(rec.xMinimum(), 3))) self.roi_y_max = rec.yMaximum() self.ui.YMaxLineEdit.setText(str(round(rec.yMaximum(), 3))) if self.extent: self.canvas.scene().removeItem(self.extent) self.extent = None self.extent = QgsRubberBand(self.canvas, True) points = [QgsPoint(self.roi_x_max, self.roi_y_min), QgsPoint(self.roi_x_max, self.roi_y_max), QgsPoint(self.roi_x_min, self.roi_y_max), QgsPoint(self.roi_x_min, self.roi_y_min), QgsPoint(self.roi_x_max, self.roi_y_min)] self.extent.setToGeometry(QgsGeometry.fromPolyline(points), None) self.extent.setColor(QColor(227, 26, 28, 255)) self.extent.setWidth(5) self.extent.setLineStyle(Qt.PenStyle(Qt.DashLine)) self.canvas.refresh() def get_z_max_z_min(self): QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) roi = QgsRectangle(self.roi_x_min, self.roi_y_min, self.roi_x_max, self.roi_y_max) source = self.map_crs target = self.layer.crs() transform = QgsCoordinateTransform(source, target) rec = transform.transform(roi) x_max = rec.xMaximum() x_min = rec.xMinimum() y_max = rec.yMaximum() y_min = rec.yMinimum() x_off = int(math.floor((x_min - self.raster_x_min) * self.cols / (self.raster_x_max - self.raster_x_min))) y_off = int(math.floor((self.raster_y_max - y_max) * self.rows / (self.raster_y_max - self.raster_y_min))) col_size = int(math.floor((x_max - x_min) / self.cell_size)) row_size = int(math.floor((y_max - y_min) / self.cell_size)) if x_off < 0: x_off = 0 if y_off < 0: y_off = 0 if x_off >= self.cols: x_off = self.cols - 1 if y_off >= self.rows: y_off = self.rows - 1 if x_off + col_size > self.cols: col_size = self.cols - x_off if row_size + row_size > self.rows: row_size = self.rows - y_off provider = self.layer.dataProvider() path = provider.dataSourceUri() path_layer = path.split('|') dem_dataset = gdal.Open(path_layer[0]) data = self.get_dem_z(dem_dataset, x_off, y_off, col_size, row_size) if data is not None: self.z_max = max(data) self.z_min = self.z_max no_data = dem_dataset.GetRasterBand(1).GetNoDataValue() if min(data) == no_data: for z_cell in data: if z_cell != no_data and z_cell < self.z_min: self.z_min = z_cell elif math.isnan(min(data)): self.z_max = 0 self.z_min = 0 for z_cell in data: if not math.isnan(z_cell): if self.z_min > z_cell: self.z_min = z_cell if self.z_max < z_cell: self.z_max = z_cell else: self.z_min = min(data) if self.z_min < 0: self.z_min = 0 self.z_max = round(self.z_max, 3) self.z_min = round(self.z_min, 3) self.ui.ZMaxLabel.setText(str(self.z_max) + ' m') self.ui.ZMinLabel.setText(str(self.z_min) + ' m') dem_dataset = None band = None QApplication.restoreOverrideCursor() # endregion # region Dimensions function def get_min_spacing(self): min_spacing = 0 if self.map_crs.mapUnits() == 0: # Meters if self.layer.crs().mapUnits() == 0: width_roi = self.roi_x_max - self.roi_x_min min_spacing = round(self.cell_size * self.width / width_roi, 2) elif self.layer.crs().mapUnits() == 2: width_roi = self.roi_x_max - self.roi_x_min cell_size_m = self.cell_size * math.pi / 180 * math.cos(self.roi_y_max * math.pi / 180) * 6371000 min_spacing = round(cell_size_m * self.width / width_roi, 2) # min_spacing = self.cell_size/self.scale elif self.map_crs.mapUnits() == 2: # Degree if self.layer.crs().mapUnits() == 0: width_roi = self.roi_x_max - self.roi_x_min cell_size_deg = self.cell_size / math.pi * 180 / math.cos(self.roi_y_max * math.pi / 180) / 6371000 min_spacing = round(cell_size_deg * self.width / width_roi, 2) elif self.layer.crs().mapUnits() == 2: width_roi = self.roi_x_max - self.roi_x_min min_spacing = round(self.cell_size * self.width / width_roi, 2) if min_spacing < 0.2: self.ui.RecomSpacinglabel.setText('0.2 mm') else: self.ui.RecomSpacinglabel.setText(str(min_spacing) + ' mm') def upload_size_from_height(self): try: width_roi = self.roi_x_max - self.roi_x_min height_roi = self.roi_y_max - self.roi_y_min self.height = float(self.ui.HeightLineEdit.text()) self.width = round(width_roi * self.height / height_roi, 2) self.ui.WidthLineEdit.setText(str(self.width)) if self.map_crs.mapUnits() == 0: # Meters scale1 = height_roi / self.height * 1000 scale2 = width_roi / self.width * 1000 self.scale = round((scale1 + scale2) / 2, 6) self.ui.ScaleLineEdit.setText(str(int(self.scale))) elif self.map_crs.mapUnits() == 2: # Degree dist = width_roi * math.pi / 180 * math.cos(self.roi_y_max * math.pi / 180) * 6371000 * 1000 self.scale = round(dist / self.width, 6) self.ui.ScaleLineEdit.setText(str(int(self.scale))) self.get_min_spacing() self.get_height_model() except ZeroDivisionError: QMessageBox.warning(self, self.tr("Attention"), self.tr("Define print extent")) self.ui.HeightLineEdit.clear() def upload_size_from_width(self): try: width_roi = self.roi_x_max - self.roi_x_min height_roi = self.roi_y_max - self.roi_y_min self.width = float(self.ui.WidthLineEdit.text()) self.height = round(height_roi * self.width / width_roi, 2) self.ui.HeightLineEdit.setText(str(self.height)) if self.map_crs.mapUnits() == 0: # Meters scale1 = height_roi / self.height * 1000 scale2 = width_roi / self.width * 1000 self.scale = round((scale1 + scale2) / 2, 6) self.ui.ScaleLineEdit.setText(str(int(self.scale))) elif self.map_crs.mapUnits() == 2: # Degree dist = width_roi * math.pi / 180 * math.cos(self.roi_y_max * math.pi / 180) * 6371000 * 1000 self.scale = round(dist / self.width, 6) self.ui.ScaleLineEdit.setText(str(int(self.scale))) self.get_min_spacing() self.get_height_model() except ZeroDivisionError: QMessageBox.warning(self, self.tr("Attention"), self.tr("Define size model")) self.ui.WidthLineEdit.clear() def upload_size_from_scale(self): try: width_roi = self.roi_x_max - self.roi_x_min height_roi = self.roi_y_max - self.roi_y_min self.scale = float(self.ui.ScaleLineEdit.text()) if self.map_crs.mapUnits() == 0: # Meters self.height = round(height_roi / self.scale * 1000, 2) self.ui.HeightLineEdit.setText(str(self.height)) self.width = round(width_roi / self.scale * 1000, 2) self.ui.WidthLineEdit.setText(str(self.width)) elif self.map_crs.mapUnits() == 2: # Degree dist = width_roi * math.pi / 180 * math.cos(self.roi_y_max * math.pi / 180) * 6371000 * 1000 self.width = round(dist / self.scale, 2) self.ui.WidthLineEdit.setText(str(self.width)) self.height = round(height_roi * self.width / width_roi, 2) self.ui.HeightLineEdit.setText(str(self.height)) self.get_min_spacing() self.get_height_model() except ZeroDivisionError: QMessageBox.warning(self, self.tr("Attention"), self.tr("Define print extent")) self.ui.ScaleLineEdit.clear() self.scale = 0 self.ui.WidthLineEdit.clear() # endregion def get_height_model(self): if self.ui.BaseHeightLineEdit.text() == '': return try: z_base = float(self.ui.BaseHeightLineEdit.text()) self.z_scale = self.ui.ZScaleDoubleSpinBox.value() h_model = round((self.z_max - z_base) / self.scale * 1000 * self.z_scale + 2, 1) if h_model == float("inf"): QMessageBox.warning(self, self.tr("Attention"), self.tr("Define size model")) self.ui.BaseHeightLineEdit.clear() return if z_base <= self.z_max: self.ui.HeightModelLabel.setText(str(h_model) + ' mm') else: QMessageBox.warning(self, self.tr("Attention"), self.tr("Height of the base must be lower than DEM highest point")) self.ui.BaseHeightLineEdit.clear() except ZeroDivisionError: QMessageBox.warning(self, self.tr("Attention"), self.tr("Define print extent")) self.ui.BaseHeightLineEdit.clear() def get_parameters(self): if self.map_crs.mapUnits() == 0: # Meters projected = True elif self.map_crs.mapUnits() == 2: # Degree projected = False provider = self.layer.dataProvider() path = provider.dataSourceUri() path_layer = path.split('|') self.z_scale = self.ui.ZScaleDoubleSpinBox.value() try: spacing_mm = float(self.ui.SpacingLineEdit.text()) z_base = float(self.ui.BaseHeightLineEdit.text()) except ValueError: return 0 if self.ui.RevereseZCheckBox.isChecked(): z_inv = True else: z_inv = False return {"layer": path_layer[0], "roi_x_max": self.roi_x_max, "roi_x_min": self.roi_x_min, "roi_y_max": self.roi_y_max, "roi_y_min": self.roi_y_min, "spacing_mm": spacing_mm, "height": self.height, "width": self.width, "z_scale": self.z_scale, "scale": self.scale, "z_inv": z_inv, "z_base": z_base, "projected": projected, "crs_layer": self.layer.crs(), "crs_map": self.map_crs} @staticmethod def get_dem_z(dem_dataset, x_off, y_off, col_size, row_size): band = dem_dataset.GetRasterBand(1) data_types = {'Byte': 'B', 'UInt16': 'H', 'Int16': 'h', 'UInt32': 'I', 'Int32': 'i', 'Float32': 'f', 'Float64': 'd'} data_type = band.DataType data = band.ReadRaster(x_off, y_off, col_size, row_size, col_size, row_size, data_type) data = struct.unpack(data_types[gdal.GetDataTypeName(band.DataType)] * col_size * row_size, data) return data
class MainWindow(ui_mainwindow.Ui_MainWindow, QMainWindow): """ Main application window """ def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.canvaslayers = [] self.layerbuttons = [] self.project = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionLegend.triggered.connect(self.updatelegend) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.actionSettings.toggled.connect(self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel("User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.gpslabel = createlabel("GPS: Not active") self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer2 = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.panels = [] self.connectButtons() self.currentfeatureband = QgsRubberBand(self.canvas) self.currentfeatureband.setIconSize(20) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 76)) self.canvas_page.layout().insertWidget(0, self.projecttoolbar) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.selectdataentry) self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.selectioncleared.connect(self.clearselection) RoamEvents.editgeometry.connect(self.addforedit) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.highlightselection) RoamEvents.selectionchanged.connect(self.showInfoResults) GPS.gpspostion.connect(self.updatecanvasfromgps) GPS.firstfix.connect(self.gpsfirstfix) GPS.gpsdisconnected.connect(self.gpsdisconnected) self.lastgpsposition = None self.marker = GPSMarker(self.canvas) self.marker.hide() self.legendpage.showmap.connect(self.showmap) self.editfeaturestack = [] self.currentselection = {} def showUIMessage(self, label, message, level=QgsMessageBar.INFO, time=0, extra=''): self.bar.pushMessage(label, message, level, duration=time, extrainfo=extra) def addforedit(self, form, feature): self.editfeaturestack.append((form, feature)) self.loadform(form) actions = self.getcaptureactions() for action in actions: if action.isdefault: action.trigger() break def updatelegend(self): self.legendpage.updatecanvas(self.canvas) def gpsfirstfix(self, postion, gpsinfo): zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) def updatecanvasfromgps(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.canvas.setExtent(rect) self.canvas.refresh() self.marker.show() self.marker.setCenter(position) self.gpslabel.setText("GPS: PDOP {} HDOP {} VDOP {}".format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) def gpsdisconnected(self): self.marker.hide() self.gpslabel.setText("GPS Not Active") def openkeyboard(self): if not roam.config.settings.get('keyboard', True): return if sys.platform == 'win32': try: programfiles = os.environ['ProgramW6432'] except KeyError: programfiles = os.environ['ProgramFiles'] cmd = r'{path}\Common Files\Microsoft Shared\ink\TabTip.exe'.format(path=programfiles) try: os.startfile(cmd) except WindowsError: roam.config.settings['keyboard'] = False roam.config.save() else: cmd = 'onboard' Popen(cmd) def selectdataentry(self): forms = self.project.forms formpicker = PickActionDialog(msg="Select data entry form") for form in forms: action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format(form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(self.showformerror, form)) else: action.triggered.connect(partial(self.loadform, form)) formpicker.addAction(action) formpicker.exec_() def showformerror(self, form): pass def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) except KeyError: pix = QPixmap() pix.load(key) if pix.isNull(): QDesktopServices.openUrl(url) return self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def settingsupdated(self, settings): self.show() self.actionGPS.updateGPSPort() def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format(extent.center().toString())) def on_geometryedit(self, form, feature): layer = form.QGISLayer self.reloadselection(layer, updated=[feature]) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def reloadselection(self, layer, deleted=[], updated=[]): """ Reload the selection after features have been updated or deleted. :param layer: :param deleted: :param updated: :return: """ selectedfeatures = self.currentselection[layer] # Update any features that have changed. for updatedfeature in updated: oldfeatures = [f for f in selectedfeatures if f.id() == updatedfeature.id()] for feature in oldfeatures: self.currentselection[layer].remove(feature) self.currentselection[layer].append(updatedfeature) # Delete any old ones for deletedid in deleted: oldfeatures = [f for f in selectedfeatures if f.id() == deletedid] for feature in oldfeatures: self.currentselection[layer].remove(feature) RoamEvents.selectionchanged.emit(self.currentselection) def highlightselection(self, results): self.clearselection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 200)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def clearselection(self): # Clear the main selection rubber band self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.editfeaturestack = [] def highlightfeature(self, layer, feature, features): self.clearselection() self.highlightselection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def showmap(self): self.actionMap.setVisible(True) self.actionLegend.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def dataentrychanged(self, index): self.clearCapatureTools() if not index.isValid(): return modelindex = index # modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) self.dataentryselection.setCurrentIndex(index.row()) self.createCaptureButtons(form) def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError(QApplication.translate('MainWindowPy','Seems something has gone wrong. Press for more details', None, QApplication.UnicodeUTF8), info) def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24,24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit) self.actionHome.triggered.connect(self.homeview) self.actionQuit.triggered.connect(self.exit) def getcaptureactions(self): for action in self.projecttoolbar.actions(): if action.property('dataentry'): yield action def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def createCaptureButtons(self, form): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.addNewFeature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showUIMessage, form.label)) def loadform(self, form): self.clearCapatureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.createCaptureButtons(form) def clearToolRubberBand(self): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def showhelp(self, url): help = HelpPage(self.stackedWidget) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuredeleted(self, layer, featureid): self.dataentryfinished() self.reloadselection(layer, deleted=[featureid]) self.canvas.refresh() def featureSaved(self): self.dataentryfinished() self.canvas.refresh() def failSave(self, messages): self.bar.pushError("Error when saving changes.", messages) def cleartempobjects(self): self.currentfeatureband.reset() self.clearToolRubberBand() def formrejected(self, message, level): self.dataentryfinished() if message: RoamEvents.raisemessage("Form Message", message, level, duration=2) self.cleartempobjects() def openForm(self, form, feature, editmode): """ Open the form that is assigned to the layer """ self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) self.showdataentry() self.dataentrywidget.openform(feature=feature, form=form, project=self.project, editmode=editmode) def editfeaturegeometry(self, form, feature, newgeometry): layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() RoamEvents.editgeometry_complete.emit(form, feature) def addNewFeature(self, form, geometry): """ Add a new new feature to the given layer """ layer = form.QGISLayer if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name() == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value self.openForm(form, feature, editmode=False) def exit(self): """ Exit the application. """ QApplication.exit(0) def showInfoResults(self, results): forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.currentselection = results self.infodock.setResults(results, forms) self.infodock.show() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = roam.config.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0]; #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0]; #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0]; #color = QColor(red, green, blue); #self.canvas.setCanvasColor(color) self.canvas.updateScale() self.projectOpened() self.canvas.freeze(False) self.canvas.refresh() GPS.crs = self.canvas.mapRenderer().destinationCrs() self.showmap() @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) try: firstform = self.project.forms[0] self.loadform(self.project.forms[0]) self.dataentryselection.setVisible(True) except IndexError: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) self.infoTool.selectionlayers = self.project.selectlayersmapping() layers = self.project.legendlayersmapping().values() self.legendpage.updateitems(layers) self.actionPan.trigger() #noinspection PyArgumentList @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.closeProject() self.canvas.refresh() self.canvas.repaint() RoamEvents.selectioncleared.emit() # No idea why we have to set this each time. Maybe QGIS deletes it for # some reason. self.badLayerHandler = BadLayerHandler(callback=self.missingLayers) QgsProject.instance().setBadLayerHandler(self.badLayerHandler) self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format(project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def closeProject(self): """ Close the current open project """ self.clearCapatureTools() self.canvas.freeze() QgsMapLayerRegistry.instance().removeAllMapLayers() self.canvas.clear() self.canvas.freeze(False) for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons for action in self.layerbuttons: self.editgroup.removeAction(action) self.panels = [] self.project = None self.dataentrywidget.clear() self.hidedataentry() self.infodock.close()
class VoGISProfilToolMainDialog(QDialog): def __init__(self, interface, settings): self.settings = settings self.iface = interface self.selectingVisibleRasters = False self.thread = None QDialog.__init__(self, interface.mainWindow()) # Set up the user interface from Designer. self.ui = Ui_VoGISProfilToolMain() self.ui.setupUi(self) if self.settings.onlyHektoMode is True: self.ui.IDC_widRaster.hide() self.adjustSize() validator = QIntValidator(-32768, 32768, self) self.ui.IDC_tbNoDataExport.setValidator(validator) self.ui.IDC_tbFromX.setText('-30000') self.ui.IDC_tbFromY.setText('240000') self.ui.IDC_tbToX.setText('-20000') self.ui.IDC_tbToY.setText('230000') self.__addRastersToGui() self.__addPolygonsToGui() for line_lyr in self.settings.mapData.lines.lines(): self.ui.IDC_cbLineLayers.addItem(line_lyr.name, line_lyr) if self.settings.mapData.lines.count() < 1: self.ui.IDC_rbDigi.setChecked(True) self.ui.IDC_rbShapeLine.setEnabled(False) #Einstellungen fuer Linie zeichen self.action = QAction(QIcon(":/plugins/vogisprofiltoolmain/icons/icon.png"), "VoGIS-Profiltool", self.iface.mainWindow()) self.action.setWhatsThis("VoGIS-Profiltool") self.canvas = self.iface.mapCanvas() self.tool = ProfiletoolMapTool(self.canvas, self.action) self.savedTool = self.canvas.mapTool() self.polygon = False self.rubberband = QgsRubberBand(self.canvas, self.polygon) if QGis.QGIS_VERSION_INT >= 10900: #self.rubberband.setBrushStyle() self.rubberband.setLineStyle(Qt.SolidLine) self.rubberband.setWidth(4.0) self.rubberband.setColor(QColor(0, 255, 0)) #http://www.qgis.org/api/classQgsRubberBand.html#a6f7cdabfcf69b65dfc6c164ce2d01fab self.pointsToDraw = [] self.dblclktemp = None self.drawnLine = None def accept(self): try: #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "ACCEPTED") #QgsMessageLog.logMessage('nodata: {0}'.format(self.settings.nodata_value), 'VoGis') self.settings.nodata_value = int(self.ui.IDC_tbNoDataExport.text()) QgsMessageLog.logMessage('maindlg: nodata: {0}'.format(self.settings.nodata_value), 'VoGis') if self.settings.onlyHektoMode is True and self.settings.mapData.rasters.count() > 0: self.settings.onlyHektoMode = False if self.settings.onlyHektoMode is False: if self.settings.mapData.rasters.count() < 1: #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", u"Keine Raster vorhanden. Zum Hektometrieren Dialog neu öffnen.") #return retVal = QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Keine Rasterebene vorhanden oder sichtbar! Nur hektometrieren?', None, QApplication.UnicodeUTF8), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if retVal == QMessageBox.No: return else: self.settings.onlyHektoMode = True self.settings.createHekto = True if self.__getSettingsFromGui() is False: return if self.settings.onlyHektoMode is False: if len(self.settings.mapData.rasters.selectedRasters()) < 1: #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "Kein Raster selektiert!") #msg = #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", msg) QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Kein Raster selektiert!', None, QApplication.UnicodeUTF8)) return QgsMessageLog.logMessage('modeLine!=line: {0}'.format(self.settings.modeLine != enumModeLine.line), 'VoGis') QgsMessageLog.logMessage('customLine is None: {0}'.format(self.settings.mapData.customLine is None), 'VoGis') if self.settings.modeLine != enumModeLine.line and self.settings.mapData.customLine is None: QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Keine Profillinie vorhanden!', None, QApplication.UnicodeUTF8)) return if len(self.settings.mapData.polygons.selected_polygons()) > 0 and len(self.settings.mapData.rasters.selectedRasters()) > 1: raster_names = list(raster.name for raster in self.settings.mapData.rasters.selectedRasters()) sel_raster, ok_clicked = QInputDialog.getItem( self.iface.mainWindow(), u'DHM?', u'Welches DHM soll zur Flächenverschneidung verwendet werden?', raster_names, 0, False ) if ok_clicked is False: return self.settings.intersection_dhm_idx = raster_names.index(sel_raster) #self.rubberband.reset(self.polygon) #QDialog.accept(self) QApplication.setOverrideCursor(Qt.WaitCursor) create_profile = CreateProfile(self.iface, self.settings) thread = QThread(self) create_profile.moveToThread(thread) create_profile.finished.connect(self.profiles_finished) create_profile.error.connect(self.profiles_error) create_profile.progress.connect(self.profiles_progress) thread.started.connect(create_profile.create) thread.start(QThread.LowestPriority) self.thread = thread self.create_profile = create_profile self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) except: QApplication.restoreOverrideCursor() ex = u'{0}'.format(traceback.format_exc()) msg = 'Unexpected ERROR:\n\n{0}'.format(ex[:2000]) QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", msg) def profiles_finished(self, profiles, intersections): QApplication.restoreOverrideCursor() self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True) #self.create_profile.deleteLater() self.thread.quit() self.thread.wait() #self.thread.deleteLater() #QGIS 2.0 http://gis.stackexchange.com/a/58754 http://gis.stackexchange.com/a/57090 self.iface.mainWindow().statusBar().showMessage('VoGIS-Profiltool, {0} Profile'.format(len(profiles))) QgsMessageLog.logMessage(u'Profile Count: {0}'.format(len(profiles)), 'VoGis') if len(profiles) < 1: QApplication.restoreOverrideCursor() QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Es konnten keine Profile erstellt werden.', None, QApplication.UnicodeUTF8)) return dlg = VoGISProfilToolPlotDialog(self.iface, self.settings, profiles, intersections) dlg.show() #result = self.dlg.exec_() dlg.exec_() def profiles_error(self, exception_string): QApplication.restoreOverrideCursor() QgsMessageLog.logMessage(u'Error during profile creation: {0}'.format(exception_string), 'VoGis') QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", exception_string) def profiles_progress(self, msg): self.iface.mainWindow().statusBar().showMessage(msg) self.ui.IDC_lblCreateStatus.setText(msg) #QgsMessageLog.logMessage(msg, 'VoGis') QApplication.processEvents() def reject(self): if not self.thread is None: if self.thread.isRunning(): self.create_profile.abort() return self.rubberband.reset(self.polygon) QDialog.reject(self) def selectVisibleRasters(self): self.refreshRasterList() self.selectingVisibleRasters = True extCanvas = self.iface.mapCanvas().extent() #alle raster in den einstellunge deselektieren for r in self.settings.mapData.rasters.rasters(): r.selected = False #alle raster in der ListView deselektieren for idx in xrange(self.ui.IDC_listRasters.count()): item = self.ui.IDC_listRasters.item(idx) item.setCheckState(Qt.Unchecked) #Raster im Extent selektieren for idx in xrange(self.ui.IDC_listRasters.count()): item = self.ui.IDC_listRasters.item(idx) if QGis.QGIS_VERSION_INT < 10900: raster = item.data(Qt.UserRole).toPyObject() else: raster = item.data(Qt.UserRole) for r in self.settings.mapData.rasters.rasters(): if extCanvas.intersects(r.grid.extent()): if r.id == raster.id: r.selected = True item.setCheckState(Qt.Checked) self.selectingVisibleRasters = False def lineLayerChanged(self, idx): if self.ui.IDC_rbShapeLine.isChecked() is False: self.ui.IDC_rbShapeLine.setChecked(True) if QGis.QGIS_VERSION_INT < 10900: lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()).toPyObject()) else: lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex())) lyr = lineLyr.line #QgsMessageLog.logMessage('{0}'.format(lyr.selectedFeatureCount()), 'VoGis') #QgsMessageLog.logMessage('{0}'.format(dir(lyr)), 'VoGis') if hasattr(lyr, 'selectedFeatureCount'): if(lyr.selectedFeatureCount() < 1): self.ui.IDC_chkOnlySelectedFeatures.setChecked(False) else: self.ui.IDC_chkOnlySelectedFeatures.setChecked(True) def valueChangedEquiDistance(self, val): if self.ui.IDC_rbEquiDistance.isChecked() is False: self.ui.IDC_rbEquiDistance.setChecked(True) def valueChangedVertexCount(self, val): if self.ui.IDC_rbVertexCount.isChecked() is False: self.ui.IDC_rbVertexCount.setChecked(True) def lvRasterItemChanged(self, item): if self.selectingVisibleRasters is True: return if item.checkState() == Qt.Checked: selected = True if item.checkState() == Qt.Unchecked: selected = False item_data = item.data(Qt.UserRole) if QGis.QGIS_VERSION_INT < 10900: raster_lyr = item_data.toPyObject() else: raster_lyr = item_data self.settings.mapData.rasters.getById(raster_lyr.id).selected = selected def lvPolygonItemChanged(self, item): if item.checkState() == Qt.Checked: selected = True if item.checkState() == Qt.Unchecked: selected = False item_data = item.data(Qt.UserRole) if QGis.QGIS_VERSION_INT < 10900: poly_lyr = item_data.toPyObject() else: poly_lyr = item_data self.settings.mapData.polygons.getById(poly_lyr.id).selected = selected def refreshRasterList(self): legend = self.iface.legendInterface() avail_lyrs = legend.layers() raster_coll = RasterCollection() for lyr in avail_lyrs: if legend.isLayerVisible(lyr): lyr_type = lyr.type() lyr_name = unicodedata.normalize('NFKD', unicode(lyr.name())).encode('ascii', 'ignore') if lyr_type == 1: if lyr.bandCount() < 2: new_raster = Raster(lyr.id(), lyr_name, lyr) raster_coll.addRaster(new_raster) self.settings.mapData.rasters = raster_coll self.__addRastersToGui() def __addRastersToGui(self): self.ui.IDC_listRasters.clear() check = Qt.Unchecked if self.settings.mapData.rasters.count() == 1: check = Qt.Checked self.settings.mapData.rasters.rasters()[0].selected = True for raster_lyr in self.settings.mapData.rasters.rasters(): item = QListWidgetItem(raster_lyr.name) item.setData(Qt.UserRole, raster_lyr) item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState(check) self.ui.IDC_listRasters.addItem(item) def __addPolygonsToGui(self): self.ui.IDC_listPolygons.clear() check = Qt.Unchecked for poly_lyr in self.settings.mapData.polygons.polygons(): item = QListWidgetItem(poly_lyr.name) item.setData(Qt.UserRole, poly_lyr) item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState(check) self.ui.IDC_listPolygons.addItem(item) def drawLine(self): if self.ui.IDC_rbDigi.isChecked() is False: self.ui.IDC_rbDigi.setChecked(True) self.dblckltemp = None self.rubberband.reset(self.polygon) self.__cleanDigi() self.__activateDigiTool() self.canvas.setMapTool(self.tool) def __createDigiFeature(self, pnts): u = Util(self.iface) f = u.createQgLineFeature(pnts) self.settings.mapData.customLine = f def __lineFinished(self, position): mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"]) newPoint = QgsPoint(mapPos.x(), mapPos.y()) self.pointsToDraw.append(newPoint) #launch analyses self.iface.mainWindow().statusBar().showMessage(str(self.pointsToDraw)) if len(self.pointsToDraw) < 2: self.__cleanDigi() self.pointsToDraw = [] self.dblclktemp = newPoint self.drawnLine = None QMessageBox.warning(self, "VoGIS-Profiltool", QApplication.translate('code', 'Profillinie digitalisieren abgebrochen!', None, QApplication.UnicodeUTF8)) self.drawnLine = self.__createDigiFeature(self.pointsToDraw) self.__cleanDigi() self.pointsToDraw = [] self.dblclktemp = newPoint def __cleanDigi(self): self.pointsToDraw = [] self.canvas.unsetMapTool(self.tool) self.canvas.setMapTool(self.savedTool) def __activateDigiTool(self): QObject.connect(self.tool, SIGNAL("moved"), self.__moved) QObject.connect(self.tool, SIGNAL("rightClicked"), self.__rightClicked) QObject.connect(self.tool, SIGNAL("leftClicked"), self.__leftClicked) QObject.connect(self.tool, SIGNAL("doubleClicked"), self.__doubleClicked) QObject.connect(self.tool, SIGNAL("deactivate"), self.__deactivateDigiTool) def __deactivateDigiTool(self): QObject.disconnect(self.tool, SIGNAL("moved"), self.__moved) QObject.disconnect(self.tool, SIGNAL("leftClicked"), self.__leftClicked) QObject.disconnect(self.tool, SIGNAL("rightClicked"), self.__rightClicked) QObject.disconnect(self.tool, SIGNAL("doubleClicked"), self.__doubleClicked) if QGis.QGIS_VERSION_INT < 10900: self.iface.mainWindow().statusBar().showMessage(QString("")) else: self.iface.mainWindow().statusBar().showMessage('') def __moved(self, position): if len(self.pointsToDraw) > 0: mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"]) self.rubberband.reset(self.polygon) newPnt = QgsPoint(mapPos.x(), mapPos.y()) if QGis.QGIS_VERSION_INT < 10900: for i in range(0, len(self.pointsToDraw)): self.rubberband.addPoint(self.pointsToDraw[i]) self.rubberband.addPoint(newPnt) else: pnts = self.pointsToDraw + [newPnt] self.rubberband.setToGeometry(QgsGeometry.fromPolyline(pnts),None) def __rightClicked(self, position): self.__lineFinished(position) def __leftClicked(self, position): mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"]) newPoint = QgsPoint(mapPos.x(), mapPos.y()) #if self.selectionmethod == 0: if newPoint == self.dblclktemp: self.dblclktemp = None return else: if len(self.pointsToDraw) == 0: self.rubberband.reset(self.polygon) self.pointsToDraw.append(newPoint) def __doubleClicked(self, position): pass #not in use right now def __lineCancel(self): pass def __getSettingsFromGui(self): self.settings.linesExplode = (self.ui.IDC_chkLinesExplode.checkState() == Qt.Checked) self.settings.linesMerge = (self.ui.IDC_chkLinesMerge.checkState() == Qt.Checked) self.settings.onlySelectedFeatures = (self.ui.IDC_chkOnlySelectedFeatures.checkState() == Qt.Checked) self.settings.equiDistance = self.ui.IDC_dblspinDistance.value() self.settings.vertexCnt = self.ui.IDC_dblspinVertexCnt.value() #self.settings.createHekto = (self.ui.IDC_chkCreateHekto.checkState() == Qt.Checked) self.settings.nodesAndVertices = (self.ui.IDC_chkNodesAndVertices.checkState() == Qt.Checked) if QGis.QGIS_VERSION_INT < 10900: self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData( self.ui.IDC_cbLineLayers.currentIndex() ).toPyObject() ) else: self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex())) if self.settings.onlySelectedFeatures is True and self.settings.mapData.selectedLineLyr.line.selectedFeatureCount() < 1: QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', u'Der gewählte Layer hat keine selektierten Elemente.', None, QApplication.UnicodeUTF8)) return False if self.ui.IDC_rbDigi.isChecked(): self.settings.modeLine = enumModeLine.customLine elif self.ui.IDC_rbShapeLine.isChecked(): self.settings.modeLine = enumModeLine.line else: #self.ui.IDC_rbStraigthLine self.settings.modeLine = enumModeLine.straightLine if self.ui.IDC_rbEquiDistance.isChecked(): self.settings.modeVertices = enumModeVertices.equiDistant else: self.settings.modeVertices = enumModeVertices.vertexCnt if self.ui.IDC_rbStraigthLine.isChecked(): ut = Util(self.iface) if ut.isFloat(self.ui.IDC_tbFromX.text(), QApplication.translate('code', 'Rechtswert von', None, QApplication.UnicodeUTF8)) is False: return False else: fromX = float(self.ui.IDC_tbFromX.text()) if ut.isFloat(self.ui.IDC_tbFromY.text(), QApplication.translate('code', 'Hochwert von', None, QApplication.UnicodeUTF8)) is False: return False else: fromY = float(self.ui.IDC_tbFromY.text()) if ut.isFloat(self.ui.IDC_tbToX.text(), QApplication.translate('code', 'Rechtswert nach', None, QApplication.UnicodeUTF8)) is False: return False else: toX = float(self.ui.IDC_tbToX.text()) if ut.isFloat(self.ui.IDC_tbToY.text(), QApplication.translate('code', 'Hochwert nach', None, QApplication.UnicodeUTF8)) is False: return False else: toY = float(self.ui.IDC_tbToY.text()) fromPnt = QgsPoint(fromX, fromY) toPnt = QgsPoint(toX, toY) self.settings.mapData.customLine = ut.createQgLineFeature([fromPnt, toPnt]) return True
class RubberBandResultRenderer(): def __init__(self): self.iface = iface self.srs_wgs84 = QgsCoordinateReferenceSystem(4326) self.transformation = QgsCoordinateTransform(self.srs_wgs84, self.srs_wgs84) self.rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.rb.setColor(QColor('magenta')) self.rb.setIconSize(12) self.features_rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.features_rb.setColor(QColor('green')) self.features_rb.setIconSize(12) self.features_rb.setWidth(3) def show_point(self, point, center=False): #check srs if self.need_transform(): point = self.transform_point(point) self.rb.addPoint(point) if center: self.center_to_point(point) def clear(self): self.rb.reset(QGis.Point) def need_transform(self): return self.iface.mapCanvas().mapRenderer().destinationCrs().postgisSrid() != 4326 def transform_point(self, point): dest_srs_id = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid() self.transformation.setDestCRSID(dest_srs_id) try: return self.transformation.transform(point) except: print 'Error on transform!' # DEBUG! need message??? return def transform_bbox(self, bbox): dest_srs_id = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid() self.transformation.setDestCRSID(dest_srs_id) try: return self.transformation.transformBoundingBox(bbox) except: print 'Error on transform!' # DEBUG! need message??? return def transform_geom(self, geom): dest_srs_id = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid() self.transformation.setDestCRSID(dest_srs_id) try: geom.transform(self.transformation) return geom except: print 'Error on transform!' # DEBUG! need message??? return def center_to_point(self, point): canvas = self.iface.mapCanvas() new_extent = QgsRectangle(canvas.extent()) new_extent.scale(1, point) canvas.setExtent(new_extent) canvas.refresh() def zoom_to_bbox(self, bbox): if self.need_transform(): bbox = self.transform_bbox(bbox) self.iface.mapCanvas().setExtent(bbox) self.iface.mapCanvas().refresh() def show_feature(self, geom): if self.need_transform(): geom = self.transform_geom(geom) self.features_rb.setToGeometry(geom, None) def clear_feature(self): self.features_rb.reset(QGis.Point)
class ItemWidgetBase(QFrame): checkedStateChanged = pyqtSignal() thumbnailChanged = pyqtSignal() def __init__(self, item): QFrame.__init__(self) self.item = item self.is_updating_checkbox = False self.setMouseTracking(True) self.setStyleSheet("ItemWidgetBase{border: 2px solid transparent;}") def _setup_ui(self, text, thumbnailurl): self.lockLabel = QLabel() iconSize = QSize(16, 16) self.lockLabel.setPixmap(LOCK_ICON.pixmap(iconSize)) self.checkBox = QCheckBox("") self.checkBox.clicked.connect(self.check_box_state_changed) self.nameLabel = QLabel(text) self.iconLabel = QLabel() self.labelZoomTo = QLabel() self.labelZoomTo.setPixmap(ZOOMTO_ICON.pixmap(QSize(18, 18))) self.labelZoomTo.setToolTip("Zoom to extent") self.labelZoomTo.mousePressEvent = self.zoom_to_extent self.labelAddPreview = QLabel() self.labelAddPreview.setPixmap(ADD_PREVIEW_ICON.pixmap(QSize(18, 18))) self.labelAddPreview.setToolTip("Add preview layer to map") self.labelAddPreview.mousePressEvent = self._add_preview_clicked layout = QHBoxLayout() layout.setMargin(0) layout.addWidget(self.checkBox) layout.addWidget(self.lockLabel) pixmap = QPixmap(PLACEHOLDER_THUMB, "SVG") self.thumbnail = None thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.iconLabel.setFixedSize(48, 48) layout.addWidget(self.iconLabel) if thumbnailurl is not None: download_thumbnail(thumbnailurl, self) layout.addWidget(self.nameLabel) layout.addStretch() layout.addWidget(self.labelZoomTo) layout.addWidget(self.labelAddPreview) layout.addSpacing(10) self.setLayout(layout) self.footprint = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.footprint.setStrokeColor(PLANET_COLOR) self.footprint.setWidth(2) def set_thumbnail(self, img): self.thumbnail = QPixmap(img) thumb = self.thumbnail.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.thumbnailChanged.emit() def is_selected(self): return self.checkBox.checkState() == Qt.Checked def _geom_bbox_in_project_crs(self): transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance(), ) return transform.transformBoundingBox(self.geom.boundingBox()) def _geom_in_project_crs(self): transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance(), ) geom = QgsGeometry(self.geom) geom.transform(transform) return geom def show_footprint(self): self.footprint.setToGeometry(self._geom_in_project_crs()) def hide_footprint(self): self.footprint.reset(QgsWkbTypes.PolygonGeometry) def enterEvent(self, event): self.setStyleSheet( "ItemWidgetBase{border: 2px solid rgb(0, 157, 165);}") self.show_footprint() def leaveEvent(self, event): self.setStyleSheet("ItemWidgetBase{border: 2px solid transparent;}") self.hide_footprint() def zoom_to_extent(self, evt): rect = QgsRectangle(self._geom_bbox_in_project_crs()) rect.scale(1.05) iface.mapCanvas().setExtent(rect) iface.mapCanvas().refresh() def _add_preview_clicked(self, evt): self.add_preview() @waitcursor def add_preview(self): send_analytics_for_preview(self.item.images()) create_preview_group(self.name(), self.item.images()) def check_box_state_changed(self): self.update_children_items() self.update_parent_item() self.checkedStateChanged.emit() def update_parent_item(self): parent = self.item.parent() if parent is not None: w = parent.treeWidget().itemWidget(parent, 0) w.update_checkbox() def update_children_items(self): total = self.item.childCount() if self.checkBox.isTristate(): self.checkBox.setTristate(False) self.checkBox.setChecked(False) for i in range(total): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) w.set_checked(self.checkBox.isChecked()) def update_checkbox(self): selected = 0 total = self.item.childCount() for i in range(total): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) if w.is_selected(): selected += 1 if selected == total: self.checkBox.setTristate(False) self.checkBox.setCheckState(Qt.Checked) elif selected == 0: self.checkBox.setTristate(False) self.checkBox.setCheckState(Qt.Unchecked) else: self.checkBox.setTristate(True) self.checkBox.setCheckState(Qt.PartiallyChecked) def set_checked(self, checked): self.checkBox.setChecked(checked) self.update_children_items() def update_thumbnail(self): thumbnails = self.scene_thumbnails() if thumbnails and None not in thumbnails: bboxes = [img[GEOMETRY] for img in self.item.images()] pixmap = createCompoundThumbnail(bboxes, thumbnails) thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.thumbnailChanged.emit() def scene_thumbnails(self): thumbnails = [] try: for i in range(self.item.childCount()): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) thumbnails.extend(w.scene_thumbnails()) except RuntimeError: # item might not exist anymore. In this case, we just return # an empty list pass return thumbnails
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.mapCanvas) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) self.clearButton = QPushButton(self) self.clearButton.setIcon(QIcon(":/plugins/quickfinder/icons/draft.svg")) self.clearButton.setText('') self.clearButton.setFlat(True) self.clearButton.setCursor(QCursor(Qt.ArrowCursor)) self.clearButton.setStyleSheet('border: 0px; padding: 0px;') self.clearButton.clicked.connect(self.clear) layout = QHBoxLayout(self) self.setLayout(layout) layout.addStretch() layout.addWidget(self.clearButton) layout.addSpacing(20) buttonSize = self.clearButton.sizeHint() # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth) padding = buttonSize.width() # + frameWidth + 1 self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def clearSelection(self): self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() def clear(self): self.clearSelection() self.resultModel.clearResults() self.lineEdit().setText('') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clearSelection() QComboBox.keyPressEvent(self, event) def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.clearSelection() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.findersToStart = [] for finder in self.finders.values(): if finder.activated(): self.findersToStart.append(finder) bbox = self.mapCanvas.fullExtent() while len(self.findersToStart) > 0: finder = self.findersToStart[0] self.findersToStart.remove(finder) self.resultModel.addResult(finder.name) finder.start(toFind, bbox=bbox) # For case there is no finder activated self.finished(None) def stop(self): self.findersToStart = [] for finder in self.finders.values(): if finder.isRunning(): finder.stop() self.finished(None) def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): if len(self.findersToStart) > 0: return for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.clearSelection() def transformGeom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform(QgsCoordinateTransform(src_crs, dest_crs)) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()