diff --git a/timeseriesviewer/main.py b/timeseriesviewer/main.py index 87724a28d0a1aa70763457bbf44335c1baf19314..67a6aae315271fa0384309b8054ccea8ebd63f68 100644 --- a/timeseriesviewer/main.py +++ b/timeseriesviewer/main.py @@ -531,6 +531,9 @@ class TimeSeriesViewer(QObject): def createMapView(self): self.spatialTemporalVis.createMapView() + def mapViews(self): + return self.spatialTemporalVis.MVC[:] + def zoomTo(self, key): if key == 'zoomMaxExtent': ext = self.TS.getMaxSpatialExtent(self.ui.dockRendering.crs()) @@ -733,7 +736,23 @@ def main(): ts = TimeSeriesViewer(None) ts.run() - ts.loadExampleTimeSeries() + from example.Images import Img_2014_01_15_LC82270652014015LGN00_BOA + ts.createMapView() + ts.addTimeSeriesImages([Img_2014_01_15_LC82270652014015LGN00_BOA]) + #ts.loadExampleTimeSeries() + + if False: + from example import exampleEvents + lyr = QgsVectorLayer(exampleEvents, 'Events', 'ogr', True) + lyr2 = QgsVectorLayer(exampleEvents, 'Events2', 'ogr', True) + QgsMapLayerRegistry.instance().addMapLayers([lyr, lyr2]) + mapView = ts.mapViews()[0] + from timeseriesviewer.mapvisualization import MapView + assert isinstance(mapView, MapView) + #mapView.setVectorLayer(lyr) + + + # ts.createMapView() # close QGIS qgsApp.exec_() diff --git a/timeseriesviewer/mapcanvas.py b/timeseriesviewer/mapcanvas.py index 3a87726fb538ad3a252292d6c050b8ee5148be50..6d377dbe4b60b829b59c80636e5c0a309f8f970a 100644 --- a/timeseriesviewer/mapcanvas.py +++ b/timeseriesviewer/mapcanvas.py @@ -32,10 +32,175 @@ from timeseriesviewer import SETTINGS from timeseriesviewer.utils import * -class MapCanvas(QgsMapCanvas): +class MapLayerInfo(object): + """ + A minimum description of a QgsMapLayer source. + """ + + def __init__(self, mapLayer, isVisible, provider='gdal'): + + self.mSrc = '' + self.mLayer = None + self.mProvider = provider + + if isinstance(mapLayer, QgsMapLayer): + self.mSrc = mapLayer.source() + self.mProvider = mapLayer.providerType() + self.mLayer = mapLayer + else: + self.mSrc = mapLayer + + + self.mIsVisible = isVisible + + + def isSameSource(self, other): + if not isinstance(other, MapLayerInfo): + return False + return self.mSrc == other.mSrc + + def initMapLayer(self): + if self.mProvider == 'gdal': + self.mLayer = QgsRasterLayer(self.mSrc) + elif self.mProvider == 'ogr': + self.mLayer = QgsVectorLayer(self.mSrc,os.path.basename(self.mSrc), 'ogr', True) + + + def setIsVisible(self, b): + self.mIsVisible = b + + def isVisible(self): + return self.mIsVisible + + def layer(self): + """returns a QgsMapLayer object related to the specified source. + If not provided in the constructor, the QgsMapLayer will be initialized with first call of this method. + """ + if not self.isInitialized(): + self.initMapLayer() + return self.mLayer + + def isInitialized(self): + return isinstance(self.mLayer, QgsMapLayer) + + def isRegistered(self): + if not self.isInitialized(): + return None + ref = QgsMapLayerRegistry.instance().mapLayer(self.mLayer.layerId()) + return isinstance(ref, QgsMapLayer) + + +class MapCanvasLayerModel(QAbstractTableModel): + """ + A model to save a list of QgsMapLayers and additional properties. + """ + + + def __init__(self, parent=None): + super(MapCanvasLayerModel, self).__init__(parent=parent) + + self.mColumnNames = ['layerID', 'isVisible', ''] + self.mLayerInfos = [] + + def __len__(self): + return len(self.mLayerInfos) + + def __iter__(self): + return iter(self.mLayerInfos) + + def __repr__(self): + info = 'MapLayerModel::' + for li in self.mLayerInfos: + if li.isVisible(): + info += '{}'.format(li.mSrc) + return info + + def setRenderer(self, renderer): + from timeseriesviewer.utils import copyRenderer + #do we need to set a reference on the renderer???? + return [copyRenderer(renderer, li.mLayer) for li in self.mLayerInfos if isinstance(li.mLayer, QgsMapLayer)] + + + def setVectorLayerSources(self, rasterSources, isVisible=True): + self.removeLayerInfos(self.vectorLayerInfos()) + self.insertLayerInfos(0, rasterSources, isVisible=isVisible, provider='ogr') + + def setVectorLayerVisibility(self, b): + for li in self.vectorLayerInfos(): + li.setIsVisible(b) + + def setRasterLayerVisibility(self, b): + for li in self.rasterLayerInfos(): + li.setIsVisible(b) + + + def setRasterLayerSources(self, rasterSources, isVisible=True): + self.removeLayerInfos(self.rasterLayerInfos()) + self.addLayerInfos(rasterSources, isVisible=isVisible, provider='gdal') + + def vectorLayerInfos(self): + return [li for li in self.mLayerInfos if li.mProvider == 'ogr'] + + def rasterLayerInfos(self): + return [li for li in self.mLayerInfos if li.mProvider == 'gdal'] + + + def addLayerInfo(self, mapLayer, isVisible=True, provider='gdal'): + self.addLayerInfos([mapLayer], isVisible=isVisible, provider=provider) + + def addLayerInfos(self, mapLayers, isVisible=True, provider='gdal'): + self.insertLayerInfos(len(self), mapLayers, isVisible=isVisible, provider=provider) + + def insertLayerInfo(self, i, mapLayer, isVisible=True, provider='gdal'): + self.insertLayerInfo(i, [mapLayer], isVisible=isVisible, provider=provider) + + def insertLayerInfos(self, i, mapLayers, isVisible=True, provider='gdal'): + for mapLayer in mapLayers: + if isinstance(mapLayer, QgsRasterLayer) and provider != 'gdal': + continue + if isinstance(mapLayer, QgsVectorLayer) and provider != 'ogr': + continue + li = MapLayerInfo(mapLayer, isVisible=isVisible, provider=provider) + self.mLayerInfos.insert(i, li) + i += 1 + + def removeLayerInfo(self, mapLayer): + self.removeLayerInfos([mapLayer]) + + def removeLayerInfos(self, mapLayers): + toRemove = [] + sourcesToRemove = [] + for ml in mapLayers: + if isinstance(ml, QgsMapLayer): + sourcesToRemove.append(ml.source()) + else: + sourcesToRemove.append(ml) + + toRemove = [li for li in self.mLayerInfos if li.mSrc in sourcesToRemove] + + for li in toRemove: + self.mLayerInfos.remove(li) + + + def layerSources(self): + return [li.mSrc for li in self.mLayerInfos] + + def layers(self): + return [li.layer() for li in self.mLayerInfos] + + def visibleLayers(self): + return [li.layer() for li in self.mLayerInfos if li.isVisible()] + + def rowCount(self, QModelIndex_parent=None, *args, **kwargs): + return len(self.mLayers) + + def columnCount(self, QModelIndex_parent=None, *args, **kwargs): + return self +class MapCanvas(QgsMapCanvas): + from timeseriesviewer.main import SpatialExtent, SpatialPoint saveFileDirectories = dict() sigShowProfiles = pyqtSignal(SpatialPoint) @@ -49,10 +214,10 @@ class MapCanvas(QgsMapCanvas): super(MapCanvas, self).__init__(parent=parent) from timeseriesviewer.mapvisualization import DatumView, MapView, SpatialTemporalVisualization - + self.mLayerModel = MapCanvasLayerModel(parent=self) #the canvas - + self.mRefreshScheduled = False def resetRenderStartTime(): self.mRenderStartTime = np.datetime64('now' ,'ms') @@ -73,18 +238,20 @@ class MapCanvas(QgsMapCanvas): #self.extentsChanged.connect(lambda : self._setDataRefreshed()) self.extentsChanged.connect(lambda : self.sigSpatialExtentChanged.emit(self.spatialExtent())) - self.mLazyRasterSources = [] - self.mLazyVectorSources = [] + #self.mLazyRasterSources = [] + #self.mLazyVectorSources = [] self.mRendererRaster = None self.mRendererVector = None + + #self.tsdView = tsdView #self.referenceLayer = QgsRasterLayer(self.tsdView.timeSeriesDatum.pathImg) self.mWasVisible = False self.mMapSummary = self.mapSummary() - self.mLayers = [] + #self.mapView = mapView #self.spatTempVis = mapView.spatTempVis #assert isinstance(self.spatTempVis, SpatialTemporalVisualization) @@ -127,13 +294,14 @@ class MapCanvas(QgsMapCanvas): self.refresh() - def mapLayersToRender(self, *args): - """Returns the map layers to be rendered""" + """ + def depr_mapLayersToRender(self, *args): + if len(self.mLazyRasterSources) > 0: mls = [QgsRasterLayer(src) for src in self.mLazyRasterSources] QgsMapLayerRegistry.instance().addMapLayers(mls, False) del self.mLazyRasterSources[:] - self.mLayers.extend(mls) + self.mLayerModel.extend(mls) self.setRenderer(self.mRendererRaster, refresh=False) if len(self.mLazyVectorSources) > 0: for t in self.mLazyVectorSources: @@ -143,23 +311,24 @@ class MapCanvas(QgsMapCanvas): #lyr = t #add vector layers on top lyr.rendererChanged.connect(self.onVectorOverlayChange) - self.mLayers.insert(0, lyr) + self.mLayerModel.insert(0, lyr) del self.mLazyVectorSources[:] self.setRenderer(self.mRendererVector, refresh=False) - return self.mLayers + return self.mLayerModel + """ - def setLazyRasterSources(self, sources): - del self.mLazyRasterSources[:] - assert isinstance(sources, list) - self.mLazyRasterSources.extend(sources[:]) + #def setLazyRasterSources(self, sources): + # del self.mLazyRasterSources[:] + # assert isinstance(sources, list) + # self.mLazyRasterSources.extend(sources[:]) - def setLazyVectorSources(self, sourceLayers): - assert isinstance(sourceLayers, list) - del self.mLazyVectorSources[:] - for lyr in sourceLayers: - assert isinstance(lyr, QgsVectorLayer) - self.mLazyVectorSources.append((lyr, lyr.source(), lyr.name(), lyr.providerType())) + #def setLazyVectorSources(self, sourceLayers): + # assert isinstance(sourceLayers, list) + # del self.mLazyVectorSources[:] + # for lyr in sourceLayers: + # assert isinstance(lyr, QgsVectorLayer) + # self.mLazyVectorSources.append((lyr, lyr.source(), lyr.name(), lyr.providerType())) def mapSummary(self): from PyQt4.QtXml import QDomDocument @@ -171,12 +340,13 @@ class MapCanvas(QgsMapCanvas): if self.mRendererRaster: self.mRendererRaster.writeXML(dom, root) xml = dom.toString() - - return (self.crs(), self.spatialExtent(), self.size(), str(self.layers()), str(self.mLazyVectorSources), str(self.mLazyRasterSources), xml) + return (self.crs(), self.spatialExtent(), self.size(), self.mLayerModel.visibleLayers(), xml) def setLayerSet(self, *args): raise DeprecationWarning() + def layerModel(self): + return self.mLayerModel def setLayers(self, mapLayers): @@ -187,18 +357,33 @@ class MapCanvas(QgsMapCanvas): if len(newLayers) > 0: reg = QgsMapLayerRegistry.instance() reg.addMapLayers(newLayers, False) - self.mLayers = mapLayers[:] - super(MapCanvas, self).setLayerSet([QgsMapCanvasLayer(l) for l in self.mLayers]) + + super(MapCanvas, self).setLayerSet([QgsMapCanvasLayer(l) for l in mapLayers]) #self.refresh() def refresh(self, force=False): #low-level, only performed if MapCanvas is visible - self.checkRenderFlag() - if self.renderFlag() or force: - self.setLayers(self.mapLayersToRender()) - super(MapCanvas, self).refresh() + isVisible = self.visibleRegion().boundingRect().isValid() and self.isVisible() + + if not isVisible: + self.mRefreshScheduled = True + else: + mLyrs = self.layers() + vLyrs = self.mLayerModel.visibleLayers() + if mLyrs != vLyrs: + self.setLayers(vLyrs) + if self.renderFlag() or force: + super(MapCanvas, self).refresh() + + + + ##self.checkRenderFlag() + #if self.renderFlag() or force: + # self.setLayers(self.mLayerModel.visibleLayers()) + # super(MapCanvas, self).refresh() + #self.refreshAllLayers() @@ -231,13 +416,15 @@ class MapCanvas(QgsMapCanvas): else: #the canvas is visible, but is a new rendering required? lastSummary = self.mMapSummary - + self.mMapSummary = self.mapSummary() #isRequired = (wasVisible == False) or self.renderFlag() or self.mDataRefreshed + #print(lastSummary) + #print(self.mMapSummary) isRequired = lastSummary != self.mapSummary() self.mWasVisible = True if isRequired: self.setRenderFlag(True) - self.mMapSummary = self.mapSummary() + #self.mMapSummary = self.mapSummary() else: self.setRenderFlag(False) @@ -452,49 +639,11 @@ class MapCanvas(QgsMapCanvas): def setRenderer(self, renderer, refresh=True): - from timeseriesviewer.utils import copyRenderer - if renderer is None: - return - if isinstance(renderer, QgsRasterRenderer): - self.mRendererRaster = renderer - elif isinstance(renderer, QgsFeatureRendererV2): - self.mRendererVector = renderer - - success = [copyRenderer(renderer, lyr) for lyr in self.mLayers] - if refresh and any(success): - self.refresh() - def depr_setVectorRenderer(self, renderer, refresh=True): - self.mRendererVector = renderer - lyrs = [l for l in self.mLayers if isinstance(l, QgsVectorLayer)] - for lyr in lyrs: - # todo: do we need to clone this? - lyr.setRenderer(renderer) - if refresh: + success = self.layerModel().setRenderer(renderer) + if refresh and any(success): self.refresh() - def depr_setRasterRenderer(self, renderer, refresh=False): - self.mRendererRaster = renderer - lyrs = [l for l in self.mLayers if isinstance(l, QgsRasterLayer)] - for lyr in lyrs: - if isinstance(renderer, QgsMultiBandColorRenderer): - r = renderer.clone() - r.setInput(lyr.dataProvider()) - elif isinstance(renderer, QgsSingleBandPseudoColorRenderer): - r = renderer.clone() - # r = QgsSingleBandPseudoColorRenderer(None, renderer.band(), None) - r.setInput(lyr.dataProvider()) - cmin = renderer.classificationMin() - cmax = renderer.classificationMax() - r.setClassificationMin(cmin) - r.setClassificationMax(cmax) - # r.setShader(renderer.shader()) - s = "" - else: - raise NotImplementedError() - lyr.setRenderer(r) - if refresh: - self.refresh() def setSpatialExtent(self, spatialExtent): assert isinstance(spatialExtent, SpatialExtent) @@ -511,7 +660,7 @@ class MapCanvas(QgsMapCanvas): def spatialExtentHint(self): crs = self.crs() ext = SpatialExtent.world() - for lyr in self.mLayers + self.layers(): + for lyr in self.mLayerModel + self.layers(): ext = SpatialExtent.fromLayer(lyr).toCrs(crs) break return ext @@ -659,20 +808,30 @@ def exampleSyncedCanvases(): qgsApp.exec_() qgsApp.exitQgis() - if __name__ == '__main__': from timeseriesviewer import utils from timeseriesviewer.mapcanvas import MapCanvas from example.Images import Img_2014_01_15_LC82270652014015LGN00_BOA + from example import exampleEvents qgsApp = utils.initQgisApplication() + + def printTimeDelta(dt): print(dt) c = MapCanvas() c.sigDataLoadingFinished.connect(printTimeDelta) c.show() - lyr = QgsRasterLayer(Img_2014_01_15_LC82270652014015LGN00_BOA) - c.setDestinationCrs(lyr.crs()) - c.setExtent(lyr.extent()) - c.setLayers([lyr]) + lyr1 = QgsRasterLayer(Img_2014_01_15_LC82270652014015LGN00_BOA) + lyr2 = QgsVectorLayer(exampleEvents, 'events', 'ogr', True) + + c.layerModel().addLayerInfo(lyr2, True) + c.layerModel().addLayerInfo(lyr1, True) + + for l in c.layerModel().visibleLayers(): + print(l) + + c.setDestinationCrs(lyr1.crs()) + c.setExtent(lyr1.extent()) + c.refresh() qgsApp.exec_() \ No newline at end of file diff --git a/timeseriesviewer/mapvisualization.py b/timeseriesviewer/mapvisualization.py index e38c5d54c25168caa1f1ca6da4647bc193448b02..3470e9dd4c375da8d19b5fd21db6056b65ea60f0 100644 --- a/timeseriesviewer/mapvisualization.py +++ b/timeseriesviewer/mapvisualization.py @@ -52,10 +52,20 @@ class MapViewUI(QFrame, loadUi('mapviewdefinition.ui')): self.btnToggleCrosshair.setMenu(m) - self.gbVectorRendering.toggled.connect(self.actionToggleMapViewVisibility.toggle) - #self.btnToggleMapViewVisibility.setDefaultAction(self.actionToggleMapViewVisibility) - #self.btnToggleVectorOverlay.setDefaultAction(self.actionToggleVectorVisibility) + #connect the QActions with the QgsCollapsibleGroupBoxes + self.gbVectorRendering.toggled.connect(self.actionToggleVectorVisibility.toggle) + self.gbRasterRendering.toggled.connect(self.actionToggleRasterVisibility.toggle) + + self.actionToggleVectorVisibility.toggled.connect(self.gbVectorRendering.setChecked) + self.actionToggleRasterVisibility.toggled.connect(self.gbRasterRendering.setChecked) + #self.actionToggleRasterVisibility.toggled.connect(self.dummy) + self.btnToggleCrosshair.setDefaultAction(self.actionToggleCrosshairVisibility) + self.btnToggleMapViewVisibility.setDefaultAction(self.actionToggleMapViewVisibility) + + def dummy(self, *args): + print((self.sender(), args)) + print(args) def addSensor(self, sensor): assert isinstance(sensor, SensorInstrument) @@ -90,7 +100,8 @@ class MapView(QObject): sigRemoveMapView = pyqtSignal(object) sigMapViewVisibility = pyqtSignal(bool) - sigVectorVisibility = pyqtSignal(bool) + #sigVectorVisibility = pyqtSignal(bool) + #sigRasterVisibility = pyqtSignal(bool) sigTitleChanged = pyqtSignal([str],[unicode]) sigSensorRendererChanged = pyqtSignal(SensorInstrument, QgsRasterRenderer) @@ -108,6 +119,7 @@ class MapView(QObject): self.ui = MapViewUI(mapViewCollection.stackedWidget) self.ui.show() self.ui.cbQgsVectorLayer.setFilters(QgsMapLayerProxyModel.VectorLayer) + self.ui.cbQgsVectorLayer.layerChanged.connect(self.setVectorLayer) self.ui.tbName.textChanged.connect(self.sigTitleChanged) from timeseriesviewer.crosshair import getCrosshairStyle self.ui.actionSetCrosshairStyle.triggered.connect( @@ -121,20 +133,32 @@ class MapView(QObject): self.mVectorLayer = None self.setVectorLayer(None) - self.mShowVectorLayer = True self.mCrosshairStyle = CrosshairStyle() self.mShowCrosshair = True self.mIsVisible = True + self.mVectorsVisible = True + self.mRastersVisible = True + + self.ui.actionToggleVectorVisibility.setChecked(True) + self.ui.actionToggleVectorVisibility.toggled.connect(self.setVectorVisibility) + + self.ui.actionToggleRasterVisibility.setChecked(True) + self.ui.actionToggleRasterVisibility.toggled.connect(self.setRasterVisibility) - self.ui.actionToggleVectorVisibility.toggled.connect(self.setShowVectorOverlay) self.ui.actionToggleCrosshairVisibility.toggled.connect(self.setShowCrosshair) self.ui.actionToggleMapViewVisibility.toggled.connect(lambda b: self.setIsVisible(not b)) + + + self.ui.actionToggleVectorVisibility.setChecked(True) + self.ui.actionToggleRasterVisibility.setChecked(True) + self.setTitle(name) #forward actions with reference to this band view - + def dummy(self, *args): + print(args) def setIsVisible(self, b): assert isinstance(b, bool) changed = b != self.mIsVisible @@ -168,6 +192,7 @@ class MapView(QObject): self.mVectorLayer.setRendererV2(renderer) def setVectorLayer(self, lyr): + if isinstance(lyr, QgsVectorLayer): #add vector layer @@ -176,15 +201,18 @@ class MapView(QObject): for mapCanvas in self.mapCanvases(): assert isinstance(mapCanvas, MapCanvas) - mapCanvas.setLayers([l for l in mapCanvas.layers() if isinstance(l, QgsRasterLayer)]) - mapCanvas.setLazyVectorSources([lyr]) + mapCanvas.layerModel().setVectorLayerSources([self.mVectorLayer]) + #mapCanvas.setLayers([l for l in mapCanvas.layers() if isinstance(l, QgsRasterLayer)]) + #mapCanvas.setLazyVectorSources([lyr]) mapCanvas.refresh() else: #remove vector layers self.mVectorLayer = None for mapCanvas in self.mapCanvases(): - mapCanvas.setLayers([l for l in mapCanvas.mLayers if not isinstance(l, QgsVectorLayer)]) + mapCanvas.layerModel().setVectorLayers([]) + #mapCanvas.setLayers([l for l in mapCanvas.mLayers if not isinstance(l, QgsVectorLayer)]) + mapCanvas.refresh() self.sigVectorLayerChanged.emit() @@ -236,12 +264,36 @@ class MapView(QObject): def showCrosshair(self): return self.mShowCrosshair and self.mCrosshairStyle is not None - def setShowVectorOverlay(self, b): + + def rasterVisibility(self): + return self.mRastersVisible + + def vectorVisibility(self): + return self.mVectorsVisible + + def setRasterVisibility(self, b): assert isinstance(b, bool) - self.sigVectorVisibility.emit(b) + if self.rasterVisibility() != b: + self.mRastersVisible = b + self.ui.actionToggleRasterVisibility.setChecked(b) + + for mapCanvas in self.mapCanvases(): + assert isinstance(mapCanvas, MapCanvas) + mapCanvas.layerModel().setRasterLayerVisibility(b) + mapCanvas.refresh() - def showVectorOverlay(self): - return isinstance(self.mVectorLayer, QgsVectorLayer) and self.sigVectorVisibility + #self.sigRasterVisibility.emit(b) + + def setVectorVisibility(self, b): + assert isinstance(b, bool) + if self.vectorVisibility() != b: + self.mVectorsVisible = b + self.ui.actionToggleVectorVisibility.setChecked(b) + + for mapCanvas in self.mapCanvases(): + assert isinstance(mapCanvas, MapCanvas) + mapCanvas.layerModel().setVectorLayerVisibility(b) + mapCanvas.refresh() def removeSensor(self, sensor): assert sensor in self.sensorViews.keys() @@ -258,22 +310,20 @@ class MapView(QObject): assert isinstance(mapCanvas, MapCanvas) assert isinstance(sensor, SensorInstrument) - #set basic settings - if sensor not in self.sensorViews.keys(): - s = "" sensorView = self.sensorViews[sensor] assert isinstance(sensorView, MapViewSensorSettings) sensorView.registerMapCanvas(mapCanvas) #register signals sensor specific signals mapCanvas.setRenderer(sensorView.rasterLayerRenderer()) + mapCanvas.setRenderer(self.vectorLayerRenderer()) #register non-sensor specific signals for this mpa view self.sigMapViewVisibility.connect(mapCanvas.refresh) self.sigCrosshairStyleChanged.connect(mapCanvas.setCrosshairStyle) self.sigShowCrosshair.connect(mapCanvas.setShowCrosshair) self.sigVectorLayerChanged.connect(mapCanvas.refresh) - self.sigVectorVisibility.connect(mapCanvas.refresh) +# self.sigVectorVisibility.connect(mapCanvas.refresh) @@ -287,8 +337,15 @@ class MapView(QObject): assert sensor not in self.sensorViews.keys() #w.showSensorName(False) - self.sensorViews[sensor] = self.ui.addSensor(sensor) + w = self.ui.addSensor(sensor) + w.sigSensorRendererChanged.connect(self.onSensorRenderingChanged) + self.sensorViews[sensor] = w + s ="" + def onSensorRenderingChanged(self, renderer): + for mapCanvas in self.mapCanvases(): + mapCanvas.setRenderer(renderer) + #mapCanvas.refresh() def getSensorWidget(self, sensor): assert type(sensor) is SensorInstrument @@ -332,7 +389,7 @@ class MapViewSensorSettings(QObject): Describes the rendering of images of one Sensor """ - #sigSensorRendererChanged = pyqtSignal(QgsRasterRenderer) + sigSensorRendererChanged = pyqtSignal(QgsRasterRenderer) def __init__(self, sensor, parent=None): """Constructor.""" @@ -645,7 +702,7 @@ class MapViewSensorSettings(QObject): self.mLastRenderer = self.rasterLayerRenderer() if updated and MapViewSensorSettings.SignalizeImmediately: - #self.sigSensorRendererChanged.emit(renderer.clone()) + self.sigSensorRendererChanged.emit(renderer.clone()) self.applyStyle() def mimeDataStyle(self): @@ -933,8 +990,9 @@ class DatumView(QObject): from timeseriesviewer.mapcanvas import MapCanvas assert isinstance(mapCanvas, MapCanvas) self.mapCanvases[mapView] = mapCanvas - mapCanvas.setLazyRasterSources([self.TSD.pathImg]) - #mapCanvas.setLayers([QgsRasterLayer(self.TSD.pathImg)]) + + mapCanvas.layerModel().setRasterLayerSources([self.TSD.pathImg]) + self.ui.layout().insertWidget(self.wOffset + len(self.mapCanvases), mapCanvas) self.ui.update() @@ -1096,37 +1154,38 @@ class SpatialTemporalVisualization(QObject): def adjustScrollArea(self): #adjust scroll area widget to fit all visible widgets m = self.targetLayout.contentsMargins() - n = len(self.DVC) + nX = len(self.DVC) w = h = 0 s = QSize() r = None tsdViews = [v for v in self.DVC if v.ui.isVisible()] - n = len(tsdViews) - + mapViews = [v for v in self.MVC if v.isVisible()] + nX = len(tsdViews) + nY = len(mapViews) spacing = self.targetLayout.spacing() margins = self.targetLayout.contentsMargins() - if n > 0: - s = tsdViews[0].ui.sizeHint() - s = QSize(n * (s.width() + spacing) + margins.left() + margins.right(), - s.height() + margins.top() + margins.bottom()) - self.targetLayout.parentWidget().setFixedSize(s) - - """ - if r is None: - r = TSDView.sizeHint() - if r: + sizeX = 1 + sizeY = 50 + if nX > 0: + s = tsdViews[0].ui.sizeHint().width() + s = nX * (s + spacing) + margins.left() + margins.right() + sizeX = s + if nY > 0: + if nX > 0: + s = tsdViews[0].ui.sizeHint().height() + s = s + margins.top() + margins.bottom() + else: + s = 50 + sizeY = s - if isinstance(self.targetLayout, QHBoxLayout): + #s = tsdViews[0].ui.sizeHint() + #s = QSize(nX * (s.width() + spacing) + margins.left() + margins.right(), + # s.height() + margins.top() + margins.bottom()) - s = QSize(s.width(), r.height()+spacing) - else: - s = QSize(r.width(), s.height()+spacing) + self.targetLayout.parentWidget().setFixedSize(QSize(sizeX, sizeY)) - s = s + QSize(m.left() + m.right(), m.top() + m.bottom()) - self.targetLayout.parentWidget().setFixedSize(s) - """ @@ -1274,7 +1333,7 @@ class DateViewCollection(QObject): for tsdv in self.views: tsdv.ui.setUpdatesEnabled(True) - #mapView.sigSensorRendererChanged.connect(lambda *args : self.setRasterRenderer(mapView, *args)) + mapView.sigSensorRendererChanged.connect(lambda *args : self.setRasterRenderer(mapView, *args)) mapView.sigMapViewVisibility.connect(lambda: self.sigResizeRequired.emit()) w.setUpdatesEnabled(True) @@ -1386,221 +1445,6 @@ class DateViewCollection(QObject): def __delitem__(self, slice): self.removeDates(self.views[slice]) -""" -class DEPR_MapViewCollection(QObject): - - sigMapViewAdded = pyqtSignal(MapView) - sigMapViewRemoved = pyqtSignal(MapView) - sigSetMapViewVisibility = pyqtSignal(MapView, bool) - sigShowProfiles = pyqtSignal(SpatialPoint) - - def __init__(self, spatialTemporalVisualization): - assert isinstance(spatialTemporalVisualization, SpatialTemporalVisualization) - super(MapViewCollection, self).__init__() - self.STV = spatialTemporalVisualization - self.STV.dockMapViews.actionApplyStyles.triggered.connect(self.applyStyles) - self.STV.TS.sigSensorAdded.connect(self.addSensor) - self.STV.TS.sigSensorRemoved.connect(self.removeSensor) - self.ui = spatialTemporalVisualization.dockMapViews - self.uiV2 = spatialTemporalVisualization.dockMapViewsV2 - self.btnList = spatialTemporalVisualization.dockMapViews.BVButtonList - self.scrollArea = spatialTemporalVisualization.dockMapViews.scrollAreaMapViews - self.scrollAreaContent = spatialTemporalVisualization.dockMapViews.scrollAreaMapsViewDockContent - self.mapViewsDefinitions = [] - self.mapViewButtons = dict() - self.adjustScrollArea() - - def applyStyles(self): - for mapView in self.mapViewsDefinitions: - mapView.applyStyles() - - def setCrosshairStyle(self, crosshairStyle): - for mapView in self.mapViewsDefinitions: - mapView.setCrosshairStyle(crosshairStyle) - - def setShowCrosshair(self, b): - for mapView in self.mapViewsDefinitions: - mapView.setShowCrosshair(b) - - def index(self, mapView): - assert isinstance(mapView, MapView) - return self.mapViewsDefinitions.index(mapView) - - def adjustScrollArea(self): - #adjust scroll area widget to fit all visible widgets - l = self.scrollAreaContent.layout() - from timeseriesviewer.ui.widgets import maxWidgetSizes - newSize = maxWidgetSizes(l) - #print(newSize) - #newSize = self.scrollAreaContent.sizeHint() - self.scrollAreaContent.setFixedSize(newSize) - - def setVectorLayer(self, lyr): - for mapView in self.mapViewsDefinitions: - assert isinstance(mapView, MapView) - mapView.setVectorLayer(lyr) - - def addSensor(self, sensor): - for mapView in self.mapViewsDefinitions: - mapView.addSensor(sensor) - self.adjustScrollArea() - - def removeSensor(self, sensor): - for mapView in self.mapViewsDefinitions: - mapView.removeSensor(sensor) - - def createMapView(self): - - btn = QToolButton(self.btnList) - self.btnList.layout().insertWidget(self.btnList.layout().count() - 1, btn) - - mapView = MapView(self, parent=self.scrollArea) - mapView.sigRemoveMapView.connect(self.removeMapView) - mapView.sigShowProfiles.connect(self.sigShowProfiles.emit) - - for sensor in self.STV.TS.Sensors: - mapView.addSensor(sensor) - - self.mapViewButtons[mapView] = btn - self.mapViewsDefinitions.append(mapView) - - - btn.clicked.connect(lambda : self.showMapViewDefinition(mapView)) - self.refreshMapViewTitles() - if len(self) == 1: - self.showMapViewDefinition(mapView) - self.sigMapViewAdded.emit(mapView) - self.adjustScrollArea() - - def removeMapView(self, mapView): - assert isinstance(mapView, MapView) - btn = self.mapViewButtons[mapView] - - idx = self.mapViewsDefinitions.index(mapView) - - self.mapViewsDefinitions.remove(mapView) - self.mapViewButtons.pop(mapView) - - mapView.ui.setVisible(False) - btn.setVisible(False) - self.btnList.layout().removeWidget(btn) - l = self.scrollAreaContent.layout() - - for d in self.recentMapViewDefinitions(): - d.ui.setVisible(False) - l.removeWidget(d.ui) - l.removeWidget(mapView.ui) - mapView.ui.close() - btn.close() - self.refreshMapViewTitles() - self.sigMapViewRemoved.emit(mapView) - if len(self) > 0: - #show previous mapViewDefinition - idxNext = max([idx-1, 0]) - self.showMapViewDefinition(self.mapViewsDefinitions[idxNext]) - - def refreshMapViewTitles(self): - - for i, mapView in enumerate(self.mapViewsDefinitions): - number = i+1 - title = '#{}'.format(number) - mapView.setTitle(title) - btn = self.mapViewButtons[mapView] - btn.setText('{}'.format(number)) - btn.setToolTip('Show definition for map view {}'.format(number)) - btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) - - - - def showMapViewDefinition(self, mapViewDefinition): - assert mapViewDefinition in self.mapViewsDefinitions - assert isinstance(mapViewDefinition, MapView) - l = self.scrollAreaContent.layout() - - for d in self.recentMapViewDefinitions(): - d.ui.setVisible(False) - l.removeWidget(d.ui) - - l.insertWidget(l.count() - 1, mapViewDefinition.ui) - mapViewDefinition.ui.setVisible(True) - self.ui.setWindowTitle(self.ui.baseTitle + '|'+mapViewDefinition.title()) - - def recentMapViewDefinitions(self): - parent = self.scrollAreaContent - return [ui.mapViewDefinition() for ui in parent.findChildren(MapViewDefinitionUI)] - - - def setMapViewVisibility(self, bandView, isVisible): - assert isinstance(bandView, MapView) - assert isinstance(isVisible, bool) - - - - - - def __len__(self): - return len(self.mapViewsDefinitions) - - def __iter__(self): - return iter(self.mapViewsDefinitions) - - def __getitem__(self, key): - return self.mapViewsDefinitions[key] - - def __contains__(self, mapView): - return mapView in self.mapViewsDefinitions -""" - - -""" -class MapViewDefinitionUI(QGroupBox, loadUi('mapviewdefinition.ui')): - - sigHideMapView = pyqtSignal() - sigShowMapView = pyqtSignal() - sigVectorVisibility = pyqtSignal(bool) - - def __init__(self, mapViewDefinition,parent=None): - super(MapViewDefinitionUI, self).__init__(parent) - - self.setupUi(self) - self.mMapViewDefinition = mapViewDefinition - self.btnRemoveMapView.setDefaultAction(self.actionRemoveMapView) - self.btnMapViewVisibility.setDefaultAction(self.actionToggleVisibility) - self.btnApplyStyles.setDefaultAction(self.actionApplyStyles) - self.btnVectorOverlayVisibility.setDefaultAction(self.actionToggleVectorVisibility) - self.btnShowCrosshair.setDefaultAction(self.actionShowCrosshair) - - - self.actionToggleVisibility.toggled.connect(lambda: self.setVisibility(not self.actionToggleVisibility.isChecked())) - self.actionToggleVectorVisibility.toggled.connect(lambda : self.sigVectorVisibility.emit(self.actionToggleVectorVisibility.isChecked())) - - def DEPRsizeHint(self): - - #m = self.layout().contentsMargins() - #sl = maxWidgetSizes(self.sensorList) - #sm = self.buttonList.size() - #w = sl.width() + m.left()+ m.right() + sm.width() - #h = sl.height() + m.top() + m.bottom() + sm.height() - return maxWidgetSizes(self.sensorList.layout()) - - - - def mapViewDefinition(self): - return self.mMapViewDefinition - - - def setVisibility(self, isVisible): - if isVisible != self.actionToggleVisibility.isChecked(): - self.btnMapViewVisibility.setChecked(isVisible) - if isVisible: - self.sigShowMapView.emit() - else: - self.sigHideMapView.emit() - - def visibility(self): - return self.actionToggleVisibility.isChecked() -""" - class MapViewListModel(QAbstractListModel): """ @@ -1685,6 +1529,9 @@ class MapViewListModel(QAbstractListModel): def __iter__(self): return iter(self.mMapViewList) + def __getitem__(self, slice): + return self.mMapViewList[slice] + def data(self, index, role=Qt.DisplayRole): if not index.isValid(): return None @@ -1761,9 +1608,18 @@ class MapViewCollectionDock(QgsDockWidget, loadUi('mapviewdock.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) + def updateButtons(self, *args): b = len(self.mMapViews) > 0 self.actionRemoveMapView.setEnabled(b) @@ -1773,7 +1629,7 @@ class MapViewCollectionDock(QgsDockWidget, loadUi('mapviewdock.ui')): def createMapView(self): - #todo: add entry to combobox + stacked widget + mapView = MapView(self) n = len(self.mMapViews) + 1 @@ -1815,6 +1671,9 @@ class MapViewCollectionDock(QgsDockWidget, loadUi('mapviewdock.ui')): def __iter__(self): return iter(self.mMapViews) + def __getitem__(self, slice): + return self.mMapViews[slice] + def __contains__(self, mapView): return mapView in self.mMapViews diff --git a/timeseriesviewer/ui/mapviewdefinition.ui b/timeseriesviewer/ui/mapviewdefinition.ui index acbfe3f4787805ae235149d2b470dfa42b73dae2..7c24b8b36b47fcb9b4b2b73c091dbaab7596d210 100644 --- a/timeseriesviewer/ui/mapviewdefinition.ui +++ b/timeseriesviewer/ui/mapviewdefinition.ui @@ -6,10 +6,22 @@ <rect> <x>0</x> <y>0</y> - <width>232</width> - <height>380</height> + <width>286</width> + <height>339</height> </rect> </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>290</width> + <height>16777215</height> + </size> + </property> <property name="windowTitle"> <string>Frame</string> </property> @@ -23,14 +35,26 @@ <property name="spacing"> <number>2</number> </property> + <property name="sizeConstraint"> + <enum>QLayout::SetMinAndMaxSize</enum> + </property> <property name="margin"> <number>2</number> </property> <item> <widget class="QScrollArea" name="scrollArea"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOn</enum> + </property> <property name="horizontalScrollBarPolicy"> <enum>Qt::ScrollBarAlwaysOff</enum> </property> @@ -42,14 +66,29 @@ <rect> <x>0</x> <y>0</y> - <width>226</width> - <height>374</height> + <width>263</width> + <height>333</height> </rect> </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>2</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> <layout class="QVBoxLayout" name="verticalLayout_3"> <property name="spacing"> <number>2</number> </property> + <property name="sizeConstraint"> + <enum>QLayout::SetFixedSize</enum> + </property> <property name="margin"> <number>2</number> </property> @@ -170,10 +209,16 @@ </item> <item> <widget class="QgsCollapsibleGroupBox" name="gbVectorRendering"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="minimumSize"> <size> <width>0</width> - <height>50</height> + <height>0</height> </size> </property> <property name="title"> @@ -183,10 +228,13 @@ <bool>true</bool> </property> <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="sizeConstraint"> + <enum>QLayout::SetMinAndMaxSize</enum> + </property> <item> <widget class="QgsMapLayerComboBox" name="cbQgsVectorLayer"> <property name="enabled"> - <bool>false</bool> + <bool>true</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> @@ -205,61 +253,73 @@ <item> <widget class="QLabel" name="label_3"> <property name="text"> - <string>(add and modify vector layers in QGIS)</string> + <string>(modify vector layers in QGIS)</string> </property> </widget> </item> </layout> <zorder>cbQgsVectorLayer</zorder> - <zorder></zorder> + <zorder>collapseButton</zorder> <zorder>label_3</zorder> </widget> </item> <item> - <widget class="QGroupBox" name="gbRasterRendering"> + <widget class="QgsCollapsibleGroupBox" name="gbRasterRendering"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> - <verstretch>2</verstretch> + <verstretch>0</verstretch> </sizepolicy> </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>50</height> + </size> + </property> <property name="title"> <string>Raster Rendering</string> </property> <property name="checkable"> <bool>true</bool> </property> + <property name="collapsed"> + <bool>false</bool> + </property> <layout class="QVBoxLayout" name="verticalLayout_4"> <property name="spacing"> - <number>1</number> + <number>0</number> </property> <property name="margin"> - <number>2</number> + <number>0</number> </property> <item> <layout class="QVBoxLayout" name="renderSettingsLayout"> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> + <property name="sizeConstraint"> + <enum>QLayout::SetMinAndMaxSize</enum> + </property> + <property name="margin"> + <number>9</number> + </property> </layout> </item> </layout> </widget> </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>25</height> + </size> + </property> + </spacer> + </item> </layout> - <zorder>gbRasterRendering</zorder> - <zorder>btnBar</zorder> - <zorder>gbVectorRendering</zorder> </widget> </widget> </item> @@ -286,53 +346,61 @@ <string>Toogle visibility of this map view</string> </property> </action> - <action name="actionToggleVectorVisibility"> + <action name="actionToggleCrosshairVisibility"> <property name="checkable"> <bool>true</bool> </property> <property name="checked"> <bool>false</bool> </property> - <property name="enabled"> - <bool>true</bool> - </property> <property name="icon"> <iconset resource="resources.qrc"> - <normaloff>:/timeseriesviewer/icons/mIconPolygonLayer.svg</normaloff> - <normalon>:/timeseriesviewer/icons/mIconPolygonLayer.svg</normalon>:/timeseriesviewer/icons/mIconPolygonLayer.svg</iconset> + <normaloff>:/timeseriesviewer/icons/crosshair.svg</normaloff>:/timeseriesviewer/icons/crosshair.svg</iconset> </property> <property name="text"> - <string>Toogle vector overlay visibility</string> + <string>Show/hide Crosshair</string> </property> <property name="toolTip"> - <string>Toogle the visibility of the overlayed vector file</string> + <string>Show/hide a crosshair</string> </property> </action> - <action name="actionToggleCrosshairVisibility"> + <action name="actionSetCrosshairStyle"> + <property name="icon"> + <iconset resource="resources.qrc"> + <normaloff>:/timeseriesviewer/icons/symbology.svg</normaloff>:/timeseriesviewer/icons/symbology.svg</iconset> + </property> + <property name="text"> + <string>Set crosshair style</string> + </property> + </action> + <action name="actionToggleVectorVisibility"> <property name="checkable"> <bool>true</bool> </property> <property name="checked"> <bool>false</bool> </property> + <property name="enabled"> + <bool>true</bool> + </property> <property name="icon"> <iconset resource="resources.qrc"> - <normaloff>:/timeseriesviewer/icons/crosshair.svg</normaloff>:/timeseriesviewer/icons/crosshair.svg</iconset> + <normaloff>:/timeseriesviewer/icons/mIconPolygonLayer.svg</normaloff> + <normalon>:/timeseriesviewer/icons/mIconPolygonLayer.svg</normalon>:/timeseriesviewer/icons/mIconPolygonLayer.svg</iconset> </property> <property name="text"> - <string>Show/hide Crosshair</string> + <string>Toogle vector overlay visibility</string> </property> <property name="toolTip"> - <string>Show/hide a crosshair</string> + <string>Toogle the visibility of the overlayed vector file</string> </property> </action> - <action name="actionSetCrosshairStyle"> - <property name="icon"> - <iconset resource="resources.qrc"> - <normaloff>:/timeseriesviewer/icons/symbology.svg</normaloff>:/timeseriesviewer/icons/symbology.svg</iconset> + <action name="actionToggleRasterVisibility"> + <property name="checkable"> + <bool>true</bool> </property> <property name="text"> - <string>Set crosshair style</string> + <string>toggleRasterVisibility</string> </property> </action> </widget> diff --git a/timeseriesviewer/ui/mapviewdock.ui b/timeseriesviewer/ui/mapviewdock.ui index fa51c60a87e401efcc4ceee58179a6667cf1f23e..a367cc34ddf0a561c7b8dbdc84bd3e1ba7861757 100644 --- a/timeseriesviewer/ui/mapviewdock.ui +++ b/timeseriesviewer/ui/mapviewdock.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>218</width> - <height>272</height> + <width>299</width> + <height>369</height> </rect> </property> <property name="minimumSize"> @@ -160,7 +160,14 @@ </widget> </item> <item> - <widget class="QStackedWidget" name="stackedWidget"/> + <widget class="QStackedWidget" name="stackedWidget"> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + </widget> </item> </layout> </widget> diff --git a/timeseriesviewer/ui/mapviewrendersettings.ui b/timeseriesviewer/ui/mapviewrendersettings.ui index 99d0ea2aa4b541f7f045b4d521460d14c51d0954..1fb59a4fb48b170deb0ed84bb12a487f82cf8074 100644 --- a/timeseriesviewer/ui/mapviewrendersettings.ui +++ b/timeseriesviewer/ui/mapviewrendersettings.ui @@ -6,26 +6,26 @@ <rect> <x>0</x> <y>0</y> - <width>300</width> + <width>150</width> <height>250</height> </rect> </property> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <sizepolicy hsizetype="Ignored" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> - <width>260</width> + <width>150</width> <height>0</height> </size> </property> <property name="maximumSize"> <size> - <width>300</width> - <height>250</height> + <width>16000</width> + <height>16000</height> </size> </property> <property name="font"> @@ -52,6 +52,9 @@ <property name="spacing"> <number>2</number> </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> <property name="leftMargin"> <number>2</number> </property> @@ -187,7 +190,7 @@ <property name="minimumSize"> <size> <width>0</width> - <height>0</height> + <height>130</height> </size> </property> <property name="frameShape"> @@ -297,7 +300,7 @@ </property> <property name="minimumSize"> <size> - <width>50</width> + <width>0</width> <height>0</height> </size> </property> @@ -525,7 +528,7 @@ </property> <property name="minimumSize"> <size> - <width>50</width> + <width>0</width> <height>0</height> </size> </property> @@ -932,14 +935,14 @@ <item row="3" column="0" colspan="2"> <widget class="QSlider" name="sliderSingleBand"> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> - <width>75</width> + <width>0</width> <height>0</height> </size> </property>