Skip to content
Snippets Groups Projects
mapvisualization.py 64.5 KiB
Newer Older
  • Learn to ignore specific revisions
  •         if isinstance(srcCanvas, MapCanvas):
                dstCanvases = [c for c in self.mapCanvases() if c != srcCanvas]
            else:
                dstCanvases = [c for c in self.mapCanvases()]
    
    
            if isinstance(spatialPoint, SpatialPoint):
    
                    mapCanvas.setCrosshairPosition(spatialPoint, emitSignal=False)
    
    
    
        def setCrosshairStyle(self, crosshairStyle:CrosshairStyle):
            """
            Sets a crosshair style to all map canvas
            :param crosshairStyle: CrosshairStyle
    
            """
            for mapView in self.mapViews():
                assert isinstance(mapView, MapView)
                mapView.setCrosshairStyle(crosshairStyle)
    
        def setCrosshairVisibility(self, b:bool):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            Sets the Crosshair visiblity
            :param b: bool
            """
    
            assert isinstance(b, bool)
            self.onCrosshairChanged(b)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setVectorLayer(self, lyr:QgsVectorLayer):
            """
            Sets a QgsVectorLaye to be shown on top of raster images
            :param lyr: QgsVectorLayer
            """
    
        def setMapSize(self, size):
    
            self.mSize = size
    
            from eotimeseriesviewer.mapcanvas import MapCanvas
    
            for mapCanvas in self.mMapCanvases:
                assert isinstance(mapCanvas, MapCanvas)
                mapCanvas.setFixedSize(size)
    
            self.sigMapSizeChanged.emit(self.mSize)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def mapSize(self)->QSize:
            """
            Returns the MapCanvas size
            :return: QSize
            """
    
            return QSize(self.mSize)
    
    
            """
            Refreshes all visible MapCanvases
            """
            for c in self.mapCanvases():
                assert isinstance(c, MapCanvas)
                c.refresh()
    
            #self.mMapRefreshTimer.stop()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            Adjusts the scroll area widget to fit all visible widgets
            """
    
    
            nX = len(self.DVC)
    
            tsdViews = [v for v in self.DVC if v.ui.isVisible()]
    
            mapViews = [v for v in self.MVC if v.isVisible()]
            nX = len(tsdViews)
            nY = len(mapViews)
    
            spacing = self.targetLayout.spacing()
            margins = self.targetLayout.contentsMargins()
    
            sizeX = 1
            sizeY = 50
            if nX > 0:
                s = tsdViews[0].ui.sizeHint().width()
                s = nX * (s + spacing) + margins.left() + margins.right()
                sizeX = s
    
                    s = tsdViews[0].ui.sizeHint().height()
                    s = s + margins.top() + margins.bottom()
    
                #s = tsdViews[0].ui.sizeHint()
                #s = QSize(nX * (s.width() + spacing) + margins.left() + margins.right(),
                #          s.height() + margins.top() + margins.bottom())
    
            self.targetLayout.parentWidget().resize(QSize(sizeX, sizeY))
    
        def setMapTool(self, mapToolKey, *args, **kwds):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            Create a maptool instance to each MapCanvas
            :param mapToolKey: str which MapTool is to create, or QgsMapTool instance
            :param args: optional maptool arguments
            :param kwds: optional maptool keywords
            :return: [list-of-QgsMapTools]
            """
    
            from eotimeseriesviewer import MapTools, CursorLocationMapTool, SpectralProfileMapTool, TemporalProfileMapTool
    
            for canvas in self.mMapCanvases:
                mt = None
                if mapToolKey in MapTools.mapToolKeys():
                    mt = MapTools.create(mapToolKey, canvas, *args, **kwds)
    
                if isinstance(mapToolKey, QgsMapTool):
                    mt = MapTools.copy(mapToolKey, canvas, *args, **kwds)
    
                if isinstance(mt, QgsMapTool):
                    canvas.setMapTool(mt)
                    self.mMapTools.append(mt)
    
    
                    # if required, link map-tool with specific slots
    
                    if isinstance(mt, CursorLocationMapTool):
                        mt.sigLocationRequest[SpatialPoint, QgsMapCanvas].connect(lambda c, m : self.sigShowProfiles.emit(c,m, mapToolKey))
    
            return self.mMapTools
    
        def setSpatialCenter(self, center, mapCanvas0=None):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            Sets the spatial center of all MapCanvases
            :param center: SpatialPoint
            :param mapCanvas0:
            """
    
            assert isinstance(center, SpatialPoint)
            center = center.toCrs(self.mCRS)
            if not isinstance(center, SpatialPoint):
                return
    
    
            self.mSpatialExtent.setCenter(center)
            for mapCanvas in self.mMapCanvases:
                if mapCanvas != mapCanvas0:
                    oldState = mapCanvas.blockSignals(True)
                    mapCanvas.setCenter(center)
                    mapCanvas.blockSignals(oldState)
    
            self.sigSpatialExtentChanged.emit(self.mSpatialExtent)
    
    
    
        def setSpatialCenter(self, center:SpatialPoint, mapCanvas0=None):
            """
            Sets the MapCanvas center.
            :param center: SpatialPoint
            :param mapCanvas0: MapCanvas0 optional
            """
    
    
            assert isinstance(center, SpatialPoint)
            center = center.toCrs(self.mCRS)
            if not isinstance(center, SpatialPoint):
                return None
    
    
    
            for mapCanvas in self.mapCanvases():
                assert isinstance(mapCanvas, MapCanvas)
    
                if mapCanvas != mapCanvas0:
    
                    center0 = mapCanvas.spatialCenter()
                    if center0 != center:
                        oldState = mapCanvas.blockSignals(True)
                        mapCanvas.setCenter(center)
                        mapCanvas.blockSignals(oldState)
    
        def setSpatialExtent(self, extent, mapCanvas0=None):
    
            """
            Sets the spatial extent of all MapCanvases
            :param extent: SpatialExtent
            :param mapCanvas0:
            :return:
            """
    
            assert isinstance(extent, SpatialExtent)
            extent = extent.toCrs(self.mCRS)
            if not isinstance(extent, SpatialExtent) \
                or extent.isEmpty() or not extent.isFinite() \
                or extent.width() <= 0 \
                or extent.height() <= 0 \
                or extent == self.mSpatialExtent:
    
            self.mSpatialExtent = extent
    
            for mapCanvas in self.mapCanvases():
                assert isinstance(mapCanvas, MapCanvas)
                extent0 = mapCanvas.spatialExtent()
                if mapCanvas != mapCanvas0 and extent0 != extent:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    mapCanvas.addToRefreshPipeLine(extent)
    
            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)
    
                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 store a list of map views.
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
        """
        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 MapViewDock(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)
    
        def setTimeSeries(self, timeSeries:TimeSeries):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert isinstance(timeSeries, TimeSeries)
    
            self.mTimeSeries = timeSeries
            self.mTimeSeries.sigSensorAdded.connect(self.addSensor)
            self.mTimeSeries.sigSensorRemoved.connect(self.removeSensor)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
        def __init__(self, parent=None):
    
            super(MapViewDock, self).__init__(parent)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.setupUi(self)
    
    
            # self.mMapViews = MapViewListModel()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.baseTitle = self.windowTitle()
    
            self.btnAddMapView.setDefaultAction(self.actionAddMapView)
            self.btnRemoveMapView.setDefaultAction(self.actionRemoveMapView)
    
    #        self.btnRefresh.setDefaultAction(self.actionApplyStyles)
    
    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())))
    
            self.actionAddMapView.triggered.connect(self.createMapView)
            self.actionRemoveMapView.triggered.connect(lambda : self.removeMapView(self.currentMapView()) if self.currentMapView() else None)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            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)) )
    
    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
    
    
        def mapViews(self)->list:
            """
            Returns the defined MapViews
            :return: [list-of-MapViews]
            """
            assert isinstance(self.toolBox, QToolBox)
            mapViews = []
            for i in range(self.toolBox.count()):
                item = self.toolBox.widget(i)
                if isinstance(item, MapView):
                    mapViews.append(item)
            return mapViews
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    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  =""
    
    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)
    
    
    
        def createMapView(self)->MapView:
            """
            Create a new MapView
            :return: MapView
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            n = len(self.mapViews()) + 1
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            title = 'Map View {}'.format(n)
    
            while title in [m.title() for m in self.mapViews()]:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                n += 1
                title = 'Map View {}'.format(n)
            mapView.setTitle(title)
    
            mapView.sigShowProfiles.connect(self.sigShowProfiles)
    
    
            mapView.setTimeSeries(self.mTimeSeries)
    
            self.addMapView(mapView)
    
        def addMapView(self, mapView:MapView):
    
            """
            Adds a MapView
            :param mapView: MapView
            """
    
            assert isinstance(mapView, MapView)
    
            mapView.sigTitleChanged.connect(lambda *args, mv=mapView : self.onMapViewUpdated(mv))
            mapView.sigMapViewVisibility.connect(lambda *args, mv=mapView : self.onMapViewUpdated(mv))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            i = self.toolBox.addItem(mapView, mapView.windowIcon(), mapView.title())
            self.toolBox.setCurrentIndex(i)
            self.onMapViewUpdated(mapView)
            self.sigMapViewAdded.emit(mapView)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def onMapViewUpdated(self, mapView:MapView):
            """
            Handles updates that react on MapView changes
            :param mapView: MapView to make the update for
            """
            numMV = 0
            for i in range(self.toolBox.count()):
                item = self.toolBox.widget(i)
                if item == mapView:
                    numMV += 1
                    if mapView.isVisible():
                        icon = QIcon(":/timeseriesviewer/icons/mapview.svg")
                    else:
                        icon = QIcon(":/timeseriesviewer/icons/mapviewHidden.svg")
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                    self.toolBox.setItemIcon(i, icon)
                    self.toolBox.setItemText(i, 'Map View {} "{}"'.format(numMV, mapView.title()))
                    break
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def removeMapView(self, mapView:MapView)->MapView:
            """
            Removes a MapView
            :param mapView: MapView
            :return: MapView
            """
            assert mapView in self.mapViews()
            for i in range(self.toolBox.count()):
                w = self.toolBox.widget(i)
                if isinstance(w, MapView) and w == mapView:
                    self.toolBox.removeItem(i)
                    mapView.close()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            self.sigMapViewRemoved.emit(mapView)
            return mapView
    
        def __len__(self)->int:
            """
            Returns the number of MapViews
            :return: int
            """
    
            return len(self.mapViews())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def __iter__(self):
    
            """
            Provides an iterator over all MapViews
            :return:
            """
    
            return iter(self.mapViews())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def __getitem__(self, slice):
    
            return self.mapViews()[slice]
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def __contains__(self, mapView):
    
            return mapView in self.mapViews()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
        def index(self, mapView):
            assert isinstance(mapView, MapView)
    
            return self.mapViews().index(mapView)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def addSensor(self, sensor:SensorInstrument):
            """
            Adds a new SensorInstrument
            :param sensor: SensorInstrument
            """
    
            for mapView in self.mapViews():
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def removeSensor(self, sensor:SensorInstrument):
            """
            Removes a Sensor
            :param sensor: SensorInstrument
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            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):
    
            w = self.toolBox.currentWidget()
            if isinstance(w, MapView):
                return w
            return None