Skip to content
Snippets Groups Projects
mapvisualization.py 101 KiB
Newer Older
        self.sigSpatialExtentChanged.emit(extent)
    def setBackgroundColor(self, color:QColor):
        """
        Sets the MapCanvas background color
        :param color: QColor
        """
        assert isinstance(color, QColor)
        self.mColor = color
        for mapCanvas in self.mMapCanvases:
            assert isinstance(mapCanvas, MapCanvas)
            mapCanvas.setCanvasColor(color)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def backgroundColor(self)->QColor:
        """
        Returns the MapCanvas background color
        :return: QColor
        """
    def mapCanvases(self, mapView=None)->list:
        """
        Returns MapCanvases
        :param mapView: a MapView to return MapCanvases from only, defaults to None
        :return: [list-of-MapCanvas]
        """
        if isinstance(mapView, MapView):
            s = ""
        return self.mMapCanvases[:]
    def mapViews(self)->list:
        """
        Returns a list of all mapviews
        :return [list-of-MapViews]:
        """
        return self.MVC[:]

    def setCrs(self, crs):
        assert isinstance(crs, QgsCoordinateReferenceSystem)

        if self.mCRS != crs:
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            transform = QgsCoordinateTransform()
            transform.setSourceCrs(self.mCRS)
            transform.setDestinationCrs(crs)
            if transform.isValid() and not transform.isShortCircuited():
                self.mCRS = crs
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                    # print(('STV set CRS {} {}', str(mapCanvas), self.mCRS.description()))
                    mapCanvas.setDestinationCrs(QgsCoordinateReferenceSystem(crs))
                """
                from timeseriesviewer.utils import saveTransform
                if saveTransform(self.mSpatialExtent, self.mCRS, crs):
                    self.mCRS = crs
                    
                else:
                    pass
                """
                self.sigCRSChanged.emit(self.crs())
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def crs(self)->QgsCoordinateReferenceSystem:
        """
        Returns the QgsCoordinateReferenceSystem
        :return: QgsCoordinateReferenceSystem
        """
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def spatialExtent(self)->SpatialExtent:
        """
        Returns the SpatialExtent
        :return: SpatialExtent
        """
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def navigateToTSD(self, TSD:TimeSeriesDatum):
        """
        Changes the viewport of the scroll window to show the requested TimeSeriesDatum
        :param TSD: TimeSeriesDatum
        """
        assert isinstance(TSD, TimeSeriesDatum)
        #get widget related to TSD
        tsdv = self.DVC.tsdView(TSD)
        assert isinstance(self.scrollArea, QScrollArea)
        self.scrollArea.ensureWidgetVisible(tsdv.ui)

class DateViewCollection(QObject):

    sigResizeRequired = pyqtSignal()
    sigLoadingStarted = pyqtSignal(MapView, TimeSeriesDatum)
    sigLoadingFinished = pyqtSignal(MapView, TimeSeriesDatum)
    sigShowProfiles = pyqtSignal(SpatialPoint)
    sigSpatialExtentChanged = pyqtSignal(SpatialExtent)

    def __init__(self, STViz):
        assert isinstance(STViz, SpatialTemporalVisualization)
        super(DateViewCollection, self).__init__()
        self.mViews = list()
        self.STV = STViz
        self.ui = self.STV.targetLayout.parentWidget()
        self.scrollArea = self.ui.parentWidget().parentWidget()
        #potentially there are many more dates than views.
        #therefore we implement the addinng/removing of mapviews here
        #we reduce the number of layout refresh calls by
        #suspending signals, adding the new map view canvases, and sending sigResizeRequired

        self.STV.MVC.sigMapViewAdded.connect(self.addMapView)
        self.STV.MVC.sigMapViewRemoved.connect(self.removeMapView)
    def tsdFromMapCanvas(self, mapCanvas):
        assert isinstance(mapCanvas, MapCanvas)
        for view in self.mViews:
            assert isinstance(view, DatumView)
            if mapCanvas in view.mMapCanvases.values():
        r = [v for v in self.mViews if v.TSD == tsd]
        if len(r) == 1:
            return r[0]
        else:
            raise Exception('TSD not in list')

    def addMapView(self, mapView):
        assert isinstance(mapView, MapView)
        w = self.ui
        #w.setUpdatesEnabled(False)
        #for tsdv in self.mViews:
        #    tsdv.ui.setUpdatesEnabled(False)
        for tsdv in self.mViews:
        #for tsdv in self.mViews:
        #    tsdv.ui.setUpdatesEnabled(True)
        #mapView.sigSensorRendererChanged.connect(lambda *args : self.setRasterRenderer(mapView, *args))
benjamin.jakimow@geo.hu-berlin.de's avatar
benjamin.jakimow@geo.hu-berlin.de committed
        mapView.sigMapViewVisibility.connect(lambda: self.sigResizeRequired.emit())
        mapView.sigShowProfiles.connect(self.sigShowProfiles.emit)
        #w.setUpdatesEnabled(True)
        self.sigResizeRequired.emit()

    def removeMapView(self, mapView):
        assert isinstance(mapView, MapView)
        for tsdv in self.mViews:
    def highlightDate(self, tsd):
        """
        Highlights a time series data for a specific time our
        :param tsd:
        :return:
        """
        tsdView = self.tsdView(tsd)
        if isinstance(tsdView, DatumView):
            tsdView.setHighlight(True)

    def setFocusView(self, tsd):
        self.focusView = tsd

    def orderedViews(self):
        #returns the
        if self.focusView is not None:
            assert isinstance(self.focusView, DatumView)
            return sorted(self.mViews, key=lambda v: np.abs(v.TSD.date - self.focusView.TSD.date))
            return self.mViews
    def setSubsetSize(self, size):
        assert isinstance(size, QSize)
        self.subsetSize = size

        for tsdView in self.orderedViews():
            tsdView.blockSignals(True)

        for tsdView in self.orderedViews():
            tsdView.setSubsetSize(size)

        for tsdView in self.orderedViews():
            tsdView.blockSignals(False)


    def addDates(self, tsdList):
        """
        Create a new TSDView
        :param tsdList:
        :return:
        """
        for tsd in tsdList:
            assert isinstance(tsd, TimeSeriesDatum)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            DV = DatumView(tsd, self.STV, parent=self.ui)
            #tsdView.setSubsetSize(self.subsetSize)
            DV.sigLoadingStarted.connect(self.sigLoadingStarted.emit)
            DV.sigLoadingFinished.connect(self.sigLoadingFinished.emit)
            DV.sigVisibilityChanged.connect(lambda: self.STV.adjustScrollArea())
            for i, mapView in enumerate(self.STV.MVC):
                DV.insertMapView(mapView)
            bisect.insort(self.mViews, DV)
            i = self.mViews.index(DV)
            DV.ui.setParent(self.STV.targetLayout.parentWidget())
            self.STV.targetLayout.insertWidget(i, DV.ui)
            DV.ui.show()

        if len(tsdList) > 0:
            self.sigResizeRequired.emit()

    def removeDates(self, tsdList):
        toRemove = [v for v in self.mViews if v.TSD in tsdList]
        for DV in toRemove:
            self.mViews.remove(DV)
            for mapCanvas in DV.mMapCanvases.values():
                toRemove = mapCanvas.layers()
                mapCanvas.setLayers([])
                toRemove = [l for l in toRemove if isinstance(l, QgsRasterLayer)]
                if len(toRemove) > 0:
                    QgsProject.instance().removeMapLayers([l.id() for l in toRemove])
            DV.ui.parent().layout().removeWidget(DV.ui)
            DV.ui.hide()
            DV.ui.close()
            removedDates.append(DV.TSD)
            del DV

        if len(removedDates) > 0:
            self.sigResizeRequired.emit()

    def __len__(self):
        return len(self.mViews)
        return iter(self.mViews)
        return self.mViews[slice]
        self.removeDates(self.mViews[slice])
Benjamin Jakimow's avatar
Benjamin Jakimow committed

class MapViewListModel(QAbstractListModel):
    """
    A model to keep a list of map views.

    """
    sigMapViewsAdded = pyqtSignal(list)
    sigMapViewsRemoved = pyqtSignal(list)

    def __init__(self, parent=None):
        super(MapViewListModel, self).__init__(parent)
        self.mMapViewList = []


Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def addMapView(self, mapView):
        i = len(self.mMapViewList)
        self.insertMapView(i, mapView)

    def insertMapView(self, i, mapView):
        self.insertMapViews(i, [mapView])

    def insertMapViews(self, i, mapViews):
        assert isinstance(mapViews, list)
        assert i >= 0 and i <= len(self.mMapViewList)

        self.beginInsertRows(QModelIndex(), i, i + len(mapViews) - 1)

        for j in range(len(mapViews)):
            mapView = mapViews[j]
            assert isinstance(mapView, MapView)
            mapView.sigTitleChanged.connect(
                lambda : self.doRefresh([mapView])
            )
            self.mMapViewList.insert(i + j, mapView)
        self.endInsertRows()
        self.sigMapViewsAdded.emit(mapViews)


    def doRefresh(self, mapViews):
        for mapView in mapViews:
            idx = self.mapView2idx(mapView)
            self.dataChanged.emit(idx, idx)

    def removeMapView(self, mapView):
        self.removeMapViews([mapView])

    def removeMapViews(self, mapViews):
        assert isinstance(mapViews, list)
        for mv in mapViews:
            assert mv in self.mMapViewList
            idx = self.mapView2idx(mv)
            self.beginRemoveRows(idx.parent(), idx.row(), idx.row())
            self.mMapViewList.remove(mv)
            self.endRemoveRows()
        self.sigMapViewsRemoved.emit(mapViews)

    def rowCount(self, parent=None, *args, **kwargs):
        return len(self.mMapViewList)

    def columnCount(self, QModelIndex_parent=None, *args, **kwargs):
        return 1


    def idx2MapView(self, index):
        if isinstance(index, QModelIndex):
            if index.isValid():
                index = index.row()
            else:
                return None
        assert index >= 0 and index < len(self.mMapViewList)
        return self.mMapViewList[index]


    def mapView2idx(self, mapView):
        assert isinstance(mapView, MapView)
        row = self.mMapViewList.index(mapView)
        return self.createIndex(row, 0, mapView)

    def __len__(self):
        return len(self.mMapViewList)

    def __iter__(self):
        return iter(self.mMapViewList)

    def __getitem__(self, slice):
        return self.mMapViewList[slice]

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None

        if (index.row() >= len(self.mMapViewList)) or (index.row() < 0):
            return None

        mapView = self.idx2MapView(index)
        assert isinstance(mapView, MapView)

        value = None

        if role == Qt.DisplayRole:
            value = '{} {}'.format(index.row() +1 , mapView.title())
        #if role == Qt.DecorationRole:
            #value = classInfo.icon(QSize(20,20))
        if role == Qt.UserRole:
            value = mapView
        return value
class MapViewCollectionDock(QgsDockWidget, loadUI('mapviewdock.ui')):
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    sigMapViewAdded = pyqtSignal(MapView)
    sigMapViewRemoved = pyqtSignal(MapView)
    sigShowProfiles = pyqtSignal(SpatialPoint, MapCanvas, str)
    sigMapCanvasColorChanged = pyqtSignal(QColor)
    sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
    sigCrsChanged = pyqtSignal(QgsCoordinateReferenceSystem)
    sigMapSizeChanged = pyqtSignal(QSize)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def setTimeSeries(self, timeSeries):
        assert isinstance(timeSeries, TimeSeries)
        self.TS = timeSeries
        self.TS.sigSensorAdded.connect(self.addSensor)
        self.TS.sigSensorRemoved.connect(self.removeSensor)

    def __init__(self, parent=None):
        super(MapViewCollectionDock, self).__init__(parent)
        self.setupUi(self)

        self.mMapViews = MapViewListModel()
        self.baseTitle = self.windowTitle()

        self.btnAddMapView.setDefaultAction(self.actionAddMapView)
        self.btnRemoveMapView.setDefaultAction(self.actionRemoveMapView)
        self.btnRefresh.setDefaultAction(self.actionApplyStyles)
        self.btnHighlightMapView.setDefaultAction(self.actionHighlightMapView)

        self.btnCrs.crsChanged.connect(self.sigCrsChanged)
        self.btnMapCanvasColor.colorChanged.connect(self.sigMapCanvasColorChanged)
        self.btnApplySizeChanges.clicked.connect(lambda : self.sigMapSizeChanged.emit(QSize(self.spinBoxMapSizeX.value(),self.spinBoxMapSizeY.value())))

        self.actionAddMapView.triggered.connect(self.createMapView)
        self.actionRemoveMapView.triggered.connect(lambda : self.removeMapView(self.currentMapView()) if self.currentMapView() else None)
        self.actionHighlightMapView.triggered.connect(lambda : self.currentMapView().setHighlighted(True) if self.currentMapView() else None)
        self.actionApplyStyles.triggered.connect(self.refreshCurrentMapView)
        #self.actionApplyStyles.triggered.connect(self.dummySlot)

        self.mMapViews.sigMapViewsRemoved.connect(self.onMapViewsRemoved)
        self.mMapViews.sigMapViewsAdded.connect(self.onMapViewsAdded)
        self.mMapViews.sigMapViewsAdded.connect(self.updateButtons)
        self.mMapViews.sigMapViewsRemoved.connect(self.updateButtons)
        self.cbMapView.setModel(self.mMapViews)
        self.cbMapView.currentIndexChanged[int].connect(lambda i : None if i < 0 else self.setCurrentMapView(self.mMapViews.idx2MapView(i)) )


        self.spinBoxMapSizeX.valueChanged.connect(lambda: self.onMapSizeChanged('X'))
        self.spinBoxMapSizeY.valueChanged.connect(lambda: self.onMapSizeChanged('Y'))
        self.mLastMapSize = self.mapSize()
        #self.mapSize() #inits mLastMapSize
        self.TS = None

    def setCrs(self, crs):
        if isinstance(crs, QgsCoordinateReferenceSystem):
            old = self.btnCrs.crs()
            if old != crs:
                self.btnCrs.setCrs(crs)
                self.btnCrs.setLayerCrs(crs)


    def setMapSize(self, size):
        assert isinstance(size, QSize)
        ws = [self.spinBoxMapSizeX, self.spinBoxMapSizeY]
        oldSize = self.mapSize()
        b = oldSize != size
        for w in ws:
            w.blockSignals(True)

        self.spinBoxMapSizeX.setValue(size.width()),
        self.spinBoxMapSizeY.setValue(size.height())
        self.mLastMapSize = QSize(size)
        for w in ws:
            w.blockSignals(False)
        self.mLastMapSize = QSize(size)
        if b:
            self.sigMapSizeChanged.emit(size)

    def onMapSizeChanged(self, dim):
        newSize = self.mapSize()
        #1. set size of other dimension accordingly
        if dim is not None:
            if self.checkBoxKeepSubsetAspectRatio.isChecked():
                if dim == 'X':
                    vOld = self.mLastMapSize.width()
                    vNew = newSize.width()
                    targetSpinBox = self.spinBoxMapSizeY
                elif dim == 'Y':
                    vOld = self.mLastMapSize.height()
                    vNew = newSize.height()
                    targetSpinBox = self.spinBoxMapSizeX

                oldState = targetSpinBox.blockSignals(True)
                targetSpinBox.setValue(int(round(float(vNew) / vOld * targetSpinBox.value())))
                targetSpinBox.blockSignals(oldState)
                newSize = self.mapSize()
            if newSize != self.mLastMapSize:
                self.btnApplySizeChanges.setEnabled(True)
        else:
            self.sigMapSizeChanged.emit(self.mapSize())
            self.btnApplySizeChanges.setEnabled(False)
        self.setMapSize(newSize)

    def mapSize(self):
        return QSize(self.spinBoxMapSizeX.value(),
                     self.spinBoxMapSizeY.value())


    def refreshCurrentMapView(self, *args):
        mv = self.currentMapView()
        if isinstance(mv, MapView):
            mv.refreshMapView()
        else:
            s  =""
    def dummySlot(self):
        s  =""

    def onMapViewsRemoved(self, mapViews):

        for mapView in mapViews:
            idx = self.stackedWidget.indexOf(mapView.ui)
            if idx >= 0:
                self.stackedWidget.removeWidget(mapView.ui)
                mapView.ui.close()
            else:
                s = ""


        self.actionRemoveMapView.setEnabled(len(self.mMapViews) > 0)

    def onMapViewsAdded(self, mapViews):
        nextShown = None
        for mapView in mapViews:
            mapView.sigTitleChanged.connect(self.updateTitle)
            self.stackedWidget.addWidget(mapView.ui)
            if nextShown is None:
                nextShown = mapView

            contents = mapView.ui.scrollAreaWidgetContents
            size = contents.size()
            hint = contents.sizeHint()
            #mapView.ui.scrollArea.update()
            s = ""
            #setMinimumSize(mapView.ui.scrollAreaWidgetContents.sizeHint())
            #hint = contents.sizeHint()
            #contents.setMinimumSize(hint)
        if isinstance(nextShown, MapView):
            self.setCurrentMapView(nextShown)

        for mapView in mapViews:
            self.sigMapViewAdded.emit(mapView)

    def updateButtons(self, *args):
        b = len(self.mMapViews) > 0
        self.actionRemoveMapView.setEnabled(b)
        self.actionApplyStyles.setEnabled(b)
        self.actionHighlightMapView.setEnabled(b)


    def createMapView(self):


        mapView = MapView(self)

        n = len(self.mMapViews) + 1
        title = 'Map View {}'.format(n)
        while title in [m.title() for m in self.mMapViews]:
            n += 1
            title = 'Map View {}'.format(n)
        mapView.setTitle(title)


        mapView.sigShowProfiles.connect(self.sigShowProfiles)
        self.mMapViews.addMapView(mapView)
        #self.sigMapViewAdded.emit(mapView)
        return mapView


    def removeMapView(self, mapView):
        if isinstance(mapView, MapView):
            assert mapView in self.mMapViews

            i = self.mMapViews.mapView2idx(mapView)
            if not i == self.stackedWidget.indexOf(mapView.ui):
                s = ""

            self.mMapViews.removeMapView(mapView)

            mapView.ui.close()

            self.sigMapViewRemoved.emit(mapView)




    def __len__(self):
        return len(self.mMapViews)

    def __iter__(self):
        return iter(self.mMapViews)

    def __getitem__(self, slice):
        return self.mMapViews[slice]

    def __contains__(self, mapView):
        return mapView in self.mMapViews

    def index(self, mapView):
        assert isinstance(mapView, MapView)
        return self.mMapViews.index(mapView)

    def setVectorLayer(self, lyr):
        for mapView in self.mMapViews:
            assert isinstance(mapView, MapView)
            mapView.setVectorLayer(lyr)

    def addSensor(self, sensor):
        for mapView in self.mMapViews:
            mapView.addSensor(sensor)


    def removeSensor(self, sensor):
        for mapView in self.mMapViews:
            mapView.removeSensor(sensor)

    def applyStyles(self):
        for mapView in self.mMapViews:
            mapView.applyStyles()

    def setCrosshairStyle(self, crosshairStyle):
        for mapView in self.mMapViews:
            mapView.setCrosshairStyle(crosshairStyle)

    def setShowCrosshair(self, b):
        for mapView in self.mMapViews:
            mapView.setCrosshairVisibility(b)

    def index(self, mapView):
        assert isinstance(mapView, MapView)
        return self.mapViewsDefinitions.index(mapView)


    def setCurrentMapView(self, mapView):
        assert isinstance(mapView, MapView) and mapView in self.mMapViews
        idx = self.stackedWidget.indexOf(mapView.ui)
        if idx >= 0:
            self.stackedWidget.setCurrentIndex(idx)
            self.cbMapView.setCurrentIndex(self.mMapViews.mapView2idx(mapView).row())

        self.updateTitle()

    def updateTitle(self, *args):
        # self.btnToggleMapViewVisibility.setChecked(mapView)
        mapView = self.currentMapView()
        if isinstance(mapView, MapView):
            if mapView in self.mMapViews:
                i = str(self.mMapViews.mapView2idx(mapView).row()+1)
            else:
                i = ''
            #title = '{} | {} "{}"'.format(self.baseTitle, i, mapView.title())
            title = '{} | {}'.format(self.baseTitle, i)
            self.setWindowTitle(title)

    def currentMapView(self):
        if len(self.mMapViews) == 0:
            return None
        else:
            i = self.cbMapView.currentIndex()
            if i >= 0:
                return self.mMapViews.idx2MapView(i)
            else:
                return None


class MapViewCollectionDockV2(QgsDockWidget, loadUI('mapviewdockV2.ui')):

    sigMapViewAdded = pyqtSignal(MapView)
    sigMapViewRemoved = pyqtSignal(MapView)
    sigShowProfiles = pyqtSignal(SpatialPoint, MapCanvas, str)

    sigMapCanvasColorChanged = pyqtSignal(QColor)
    sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
    sigCrsChanged = pyqtSignal(QgsCoordinateReferenceSystem)
    sigMapSizeChanged = pyqtSignal(QSize)
    def setTimeSeries(self, timeSeries):
        assert isinstance(timeSeries, TimeSeries)
        self.TS = timeSeries
        self.TS.sigSensorAdded.connect(self.addSensor)
        self.TS.sigSensorRemoved.connect(self.removeSensor)

    def __init__(self, parent=None):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        super(MapViewCollectionDock, self).__init__(parent)
        self.setupUi(self)

        self.mMapViews = MapViewListModel()
        self.baseTitle = self.windowTitle()

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.btnAddMapView.setDefaultAction(self.actionAddMapView)
        self.btnRemoveMapView.setDefaultAction(self.actionRemoveMapView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.btnRefresh.setDefaultAction(self.actionApplyStyles)
        self.btnHighlightMapView.setDefaultAction(self.actionHighlightMapView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.btnCrs.crsChanged.connect(self.sigCrsChanged)
        self.btnMapCanvasColor.colorChanged.connect(self.sigMapCanvasColorChanged)
        self.btnApplySizeChanges.clicked.connect(lambda : self.sigMapSizeChanged.emit(QSize(self.spinBoxMapSizeX.value(),self.spinBoxMapSizeY.value())))
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.actionAddMapView.triggered.connect(self.createMapView)
        self.actionRemoveMapView.triggered.connect(lambda : self.removeMapView(self.currentMapView()) if self.currentMapView() else None)
        self.actionHighlightMapView.triggered.connect(lambda : self.currentMapView().setHighlighted(True) if self.currentMapView() else None)
        self.actionApplyStyles.triggered.connect(self.refreshCurrentMapView)
        #self.actionApplyStyles.triggered.connect(self.dummySlot)

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.mMapViews.sigMapViewsRemoved.connect(self.onMapViewsRemoved)
        self.mMapViews.sigMapViewsAdded.connect(self.onMapViewsAdded)
        self.mMapViews.sigMapViewsAdded.connect(self.updateButtons)
        self.mMapViews.sigMapViewsRemoved.connect(self.updateButtons)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.cbMapView.setModel(self.mMapViews)
benjamin.jakimow@geo.hu-berlin.de's avatar
benjamin.jakimow@geo.hu-berlin.de committed
        self.cbMapView.currentIndexChanged[int].connect(lambda i : None if i < 0 else self.setCurrentMapView(self.mMapViews.idx2MapView(i)) )
Benjamin Jakimow's avatar
Benjamin Jakimow committed


        self.spinBoxMapSizeX.valueChanged.connect(lambda: self.onMapSizeChanged('X'))
        self.spinBoxMapSizeY.valueChanged.connect(lambda: self.onMapSizeChanged('Y'))
        self.mLastMapSize = self.mapSize()
        #self.mapSize() #inits mLastMapSize
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.TS = None

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        if isinstance(crs, QgsCoordinateReferenceSystem):
            old = self.btnCrs.crs()
            if old != crs:
                self.btnCrs.setCrs(crs)
                self.btnCrs.setLayerCrs(crs)


    def setMapSize(self, size):
        assert isinstance(size, QSize)
        ws = [self.spinBoxMapSizeX, self.spinBoxMapSizeY]
        oldSize = self.mapSize()
        b = oldSize != size
        for w in ws:
            w.blockSignals(True)

        self.spinBoxMapSizeX.setValue(size.width()),
        self.spinBoxMapSizeY.setValue(size.height())
        self.mLastMapSize = QSize(size)
        for w in ws:
            w.blockSignals(False)
        self.mLastMapSize = QSize(size)
        if b:
            self.sigMapSizeChanged.emit(size)

    def onMapSizeChanged(self, dim):
        newSize = self.mapSize()
        #1. set size of other dimension accordingly
        if dim is not None:
            if self.checkBoxKeepSubsetAspectRatio.isChecked():
                if dim == 'X':
                    vOld = self.mLastMapSize.width()
                    vNew = newSize.width()
                    targetSpinBox = self.spinBoxMapSizeY
                elif dim == 'Y':
                    vOld = self.mLastMapSize.height()
                    vNew = newSize.height()
                    targetSpinBox = self.spinBoxMapSizeX

                oldState = targetSpinBox.blockSignals(True)
                targetSpinBox.setValue(int(round(float(vNew) / vOld * targetSpinBox.value())))
                targetSpinBox.blockSignals(oldState)
                newSize = self.mapSize()
            if newSize != self.mLastMapSize:
                self.btnApplySizeChanges.setEnabled(True)
        else:
            self.sigMapSizeChanged.emit(self.mapSize())
            self.btnApplySizeChanges.setEnabled(False)
        self.setMapSize(newSize)

    def mapSize(self):
        return QSize(self.spinBoxMapSizeX.value(),
                     self.spinBoxMapSizeY.value())


    def refreshCurrentMapView(self, *args):
        mv = self.currentMapView()
        if isinstance(mv, MapView):
            mv.refreshMapView()
        else:
            s  =""
    def dummySlot(self):
        s  =""

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def onMapViewsRemoved(self, mapViews):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        for mapView in mapViews:
            idx = self.stackedWidget.indexOf(mapView.ui)
            if idx >= 0:
                self.stackedWidget.removeWidget(mapView.ui)
                mapView.ui.close()
            else:
                s = ""

        self.actionRemoveMapView.setEnabled(len(self.mMapViews) > 0)

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def onMapViewsAdded(self, mapViews):
        nextShown = None
        for mapView in mapViews:
            mapView.sigTitleChanged.connect(self.updateTitle)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            self.stackedWidget.addWidget(mapView.ui)
            if nextShown is None:
                nextShown = mapView
            contents = mapView.ui.scrollAreaWidgetContents
            size = contents.size()
            hint = contents.sizeHint()
            #mapView.ui.scrollArea.update()
            s = ""
            #setMinimumSize(mapView.ui.scrollAreaWidgetContents.sizeHint())
            #hint = contents.sizeHint()
            #contents.setMinimumSize(hint)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        if isinstance(nextShown, MapView):
            self.setCurrentMapView(nextShown)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        for mapView in mapViews:
            self.sigMapViewAdded.emit(mapView)
    def updateButtons(self, *args):
        b = len(self.mMapViews) > 0
        self.actionRemoveMapView.setEnabled(b)
        self.actionApplyStyles.setEnabled(b)
        self.actionHighlightMapView.setEnabled(b)


Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def createMapView(self):

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        mapView = MapView(self)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        n = len(self.mMapViews) + 1
        title = 'Map View {}'.format(n)
        while title in [m.title() for m in self.mMapViews]:
            n += 1
            title = 'Map View {}'.format(n)
        mapView.setTitle(title)
        mapView.sigShowProfiles.connect(self.sigShowProfiles)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.mMapViews.addMapView(mapView)
benjamin.jakimow@geo.hu-berlin.de's avatar
benjamin.jakimow@geo.hu-berlin.de committed
        return mapView
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def removeMapView(self, mapView):
        if isinstance(mapView, MapView):
            assert mapView in self.mMapViews
Benjamin Jakimow's avatar
Benjamin Jakimow committed

            i = self.mMapViews.mapView2idx(mapView)
            if not i == self.stackedWidget.indexOf(mapView.ui):
                s = ""
Benjamin Jakimow's avatar
Benjamin Jakimow committed

            self.mMapViews.removeMapView(mapView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed

            self.sigMapViewRemoved.emit(mapView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def __len__(self):
        return len(self.mMapViews)

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def __iter__(self):
        return iter(self.mMapViews)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def __getitem__(self, slice):
        return self.mMapViews[slice]

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def __contains__(self, mapView):
        return mapView in self.mMapViews
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def index(self, mapView):
        assert isinstance(mapView, MapView)
        return self.mMapViews.index(mapView)

    def setVectorLayer(self, lyr):
        for mapView in self.mMapViews:
            assert isinstance(mapView, MapView)
            mapView.setVectorLayer(lyr)

    def addSensor(self, sensor):
        for mapView in self.mMapViews:
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def removeSensor(self, sensor):
        for mapView in self.mMapViews:
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def applyStyles(self):
        for mapView in self.mMapViews:
            mapView.applyStyles()

    def setCrosshairStyle(self, crosshairStyle):
        for mapView in self.mMapViews:
            mapView.setCrosshairStyle(crosshairStyle)

    def setShowCrosshair(self, b):
        for mapView in self.mMapViews:
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def index(self, mapView):
        assert isinstance(mapView, MapView)
        return self.mapViewsDefinitions.index(mapView)


Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def setCurrentMapView(self, mapView):
        assert isinstance(mapView, MapView) and mapView in self.mMapViews
        idx = self.stackedWidget.indexOf(mapView.ui)
        if idx >= 0:
            self.stackedWidget.setCurrentIndex(idx)
            self.cbMapView.setCurrentIndex(self.mMapViews.mapView2idx(mapView).row())
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.updateTitle()

    def updateTitle(self, *args):
        # self.btnToggleMapViewVisibility.setChecked(mapView)
        mapView = self.currentMapView()
        if isinstance(mapView, MapView):
            if mapView in self.mMapViews:
                i = str(self.mMapViews.mapView2idx(mapView).row()+1)
            else:
                i = ''
            #title = '{} | {} "{}"'.format(self.baseTitle, i, mapView.title())
            title = '{} | {}'.format(self.baseTitle, i)
            self.setWindowTitle(title)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def currentMapView(self):
        if len(self.mMapViews) == 0:
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            return None
        else:
            i = self.cbMapView.currentIndex()
            if i >= 0:
                return self.mMapViews.idx2MapView(i)
            else:
                return None