Skip to content
Snippets Groups Projects
main.py 24.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • unknown's avatar
    unknown committed
    # -*- coding: utf-8 -*-
    """
    /***************************************************************************
    
     HUB TimeSeriesViewer
                                     A QGIS based time series viewer
    
    unknown's avatar
    unknown committed
                                  -------------------
            begin                : 2015-08-20
            git sha              : $Format:%H$
    
            copyright            : (C) 2017 by HU-Berlin
            email                : benjamin.jakimow@geo.hu-berlin.de
    
    unknown's avatar
    unknown committed
     ***************************************************************************/
    
    /***************************************************************************
     *                                                                         *
     *   This program is free software; you can redistribute it and/or modify  *
     *   it under the terms of the GNU General Public License as published by  *
     *   the Free Software Foundation; either version 2 of the License, or     *
     *   (at your option) any later version.                                   *
     *                                                                         *
     ***************************************************************************/
    """
    
    unknown's avatar
    unknown committed
    
    
    # Import the code for the dialog
    
    import os, sys, re, fnmatch, collections, copy, traceback, six
    
    import logging
    logger = logging.getLogger(__name__)
    
    from qgis.core import *
    
    
    from timeseriesviewer.utils import *
    
    from timeseriesviewer.ui import load
    
    DEBUG = True
    
    unknown's avatar
    unknown committed
    
    import numpy as np
    
    import multiprocessing
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    #abbreviations
    
    from timeseriesviewer import jp, mkdir, DIR_SITE_PACKAGES, file_search
    
    from timeseriesviewer.timeseries import *
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    #I don't know why, but this is required to run this in QGIS
    
    #todo: still required?
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    path = os.path.abspath(jp(sys.exec_prefix, '../../bin/pythonw.exe'))
    
    unknown's avatar
    unknown committed
    if os.path.exists(path):
        multiprocessing.set_executable(path)
        sys.argv = [ None ]
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    #ensure that required non-standard modules are available
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    class TsvMimeDataUtils(QObject):
        def __init__(self, mimeData):
            assert isinstance(mimeData, QMimeData)
            super(TsvMimeDataUtils, self).__init__()
    
            self.mimeData = mimeData
    
            self.xmlDoc = QDomDocument()
    
            if self.mimeData.hasText():
                self.xmlDoc.setContent(self.mimeData.text())
            self.xmlRoot = self.xmlDoc.documentElement()
            pass
    
        def hasRasterStyle(self):
            if self.xmlRoot.tagName() == 'qgis':
                elem = self.xmlRoot.elementsByTagName('rasterrenderer')
                return elem.count() != 0
    
            return False
    
    
        def rasterStyle(self, qgisDataType):
    
            elem = self.xmlRoot.elementsByTagName('rasterrenderer').item(0).toElement()
            type = str(elem.attribute('type'))
            from qgis.core import QGis, QgsContrastEnhancement
    
            def bandSettings(colorName):
                band = int(elem.attribute(colorName + 'Band'))
                ceNode = elem.elementsByTagName(colorName + 'ContrastEnhancement').item(0)
                vMin = float(ceNode.firstChildElement('minValue').firstChild().nodeValue())
                vMax = float(ceNode.firstChildElement('maxValue').firstChild().nodeValue())
                ceName = ceNode.firstChildElement('algorithm').firstChild().nodeValue()
                ceAlg = QgsContrastEnhancement.contrastEnhancementAlgorithmFromString(ceName)
                ce = QgsContrastEnhancement(qgisDataType)
                ce.setContrastEnhancementAlgorithm(ceAlg)
                ce.setMinimumValue(vMin)
                ce.setMaximumValue(vMax)
                return band, ce
    
            style = None
            if type == 'multibandcolor':
                    A = int(elem.attribute('alphaBand'))
                    O = int(elem.attribute('opacity'))
                    R, ceR = bandSettings('red')
                    G, ceG = bandSettings('green')
                    B, ceB = bandSettings('blue')
    
                    style = QgsMultiBandColorRenderer(None, R, G, B)
                    style.setRedContrastEnhancement(ceR)
                    style.setGreenContrastEnhancement(ceG)
                    style.setBlueContrastEnhancement(ceB)
    
            elif type == 'singlebandgrey':
    
                pass
    
            return style
    
    class QgisTsvBridge(QObject):
        """
        Class to control interactions between TSV and a running QGIS instance
        """
        _instance = None
    
    
        @staticmethod
        def instance():
            return QgisTsvBridge._instance
    
    
            super(QgisTsvBridge, self).__init__()
            assert QgisTsvBridge._instance is None
    
            assert isinstance(TSV, TimeSeriesViewer)
    
            assert isinstance(iface, QgisInterface)
            self.iface = iface
    
            self.TSV = TSV
            self.ui = self.TSV.ui
            self.SpatTempVis = self
            self.syncBlocked = False
    
    
            from timeseriesviewer.ui.widgets import TimeSeriesViewerUI
            assert isinstance(self.ui, TimeSeriesViewerUI)
    
            self.cbQgsVectorLayer = self.ui.dockRendering.cbQgsVectorLayer
            self.gbQgsVectorLayer = self.ui.dockRendering.gbQgsVectorLayer
    
            self.cbQgsVectorLayer.setEnabled(True)
            self.gbQgsVectorLayer.setEnabled(True)
    
            self.qgsMapCanvas = self.iface.mapCanvas()
    
            assert isinstance(self.qgsMapCanvas, QgsMapCanvas)
    
            self.qgsMapCanvas.extentsChanged.connect(self.syncTsvWithQgs)
            self.qgsMapCanvas.destinationCrsChanged.connect(self.syncTsvWithQgs)
    
    
    
            assert isinstance(self.cbQgsVectorLayer, QgsMapLayerComboBox)
            assert isinstance(self.gbQgsVectorLayer, QgsCollapsibleGroupBox)
    
    
            self.TSV.spatialTemporalVis.sigSpatialExtentChanged.connect(self.syncQgsWithTsv)
    
            self.gbQgsVectorLayer.clicked.connect(self.onQgsVectorLayerChanged)
    
            self.cbQgsVectorLayer.layerChanged.connect(self.onQgsVectorLayerChanged)
    
            self.onQgsVectorLayerChanged(None)
    
    
        def syncTsvWithQgs(self, *args):
            if self.syncBlocked:
                return
            syncState = self.ui.dockNavigation.qgsSyncState()
            if any(syncState.values()):
                self.syncBlocked = True
                self.syncBlocked = True
                QTimer.singleShot(500, lambda: self.unblock())
                tsvExt = self.TSV.spatialTemporalVis.extent
                qgsExt = SpatialExtent.fromMapCanvas(self.qgsMapCanvas)
                newExtent = self.newExtent(tsvExt, syncState, qgsExt)
                self.TSV.spatialTemporalVis.setSpatialExtent(newExtent)
                self.syncBlocked = False
    
            pass
    
    
        def syncQgsWithTsv(self, spatialExtent):
    
            if self.syncBlocked:
                return
    
    
            syncState = self.ui.dockNavigation.qgsSyncState()
            if any(syncState.values()):
                self.syncBlocked = True
                QTimer.singleShot(500, lambda: self.unblock())
                tsvExt = self.TSV.spatialTemporalVis.extent
                qgsExt = SpatialExtent.fromMapCanvas(self.qgsMapCanvas)
                newExtent = self.newExtent(qgsExt, syncState, tsvExt)
                self.qgsMapCanvas.setDestinationCrs(newExtent.crs())
                self.qgsMapCanvas.setExtent(newExtent)
                self.syncBlocked = False
    
    
                QTimer.singleShot(1000, lambda : self.unblock())
    
    
    
        def unblock(self):
            self.syncBlocked = False
    
        def newExtent(self, oldExtent, syncState, newExtent):
    
            crs = newExtent.crs() if syncState['crs'] else oldExtent.crs()
            extent = oldExtent
            if syncState['extent']:
                extent = newExtent.toCrs(crs)
            elif syncState['center']:
                import copy
                extent = copy.copy(oldExtent)
                extent.setCenter(newExtent.center(), newExtent.crs())
    
            return extent
    
    
    
        def onQgsVectorLayerChanged(self, lyr):
    
            if self.gbQgsVectorLayer.isChecked() and \
               isinstance(self.cbQgsVectorLayer.currentLayer(), QgsVectorLayer):
                self.TSV.spatialTemporalVis.setVectorLayer(self.cbQgsVectorLayer.currentLayer())
            else:
                self.TSV.spatialTemporalVis.setVectorLayer(None)
    
    
        def extent(self):
            assert isinstance(self.qgsMapCanvas, QgsMapCanvas)
            return SpatialExtent.fromMapCanvas(self.qgsMapCanvas)
    
                self.cbSyncQgsMapCenter.setEnabled(False)
                self.cbSyncQgsMapCenter.blockSignals(True)
                self.cbSyncQgsMapCenter.setChecked(True)
                self.cbSyncQgsMapCenter.blockSignals(False)
    
                self.cbSyncQgsMapCenter.setEnabled(True)
    
            self.qgsSyncStateChanged()
    
        def qgsSyncState(self):
            return (self.cbSyncQgsMapCenter.isChecked(),
                    self.cbSyncQgsMapExtent.isChecked(),
                    self.cbSyncQgsCRS.isChecked())
    
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    unknown's avatar
    unknown committed
    
    
    class TimeSeriesViewerUI(QMainWindow,
                             load('timeseriesviewer.ui')):
    
        sigQgsSyncChanged = pyqtSignal(bool, bool, bool)
    
        def __init__(self, parent=None):
            """Constructor."""
            super(TimeSeriesViewerUI, self).__init__(parent)
            # Set up the user interface from Designer.
            # After setupUI you can access any designer object by doing
            # self.<objectname>, and you can use autoconnect slots - see
            # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
            # #widgets-and-dialogs-with-auto-connect
            self.setupUi(self)
            self.addActions(self.findChildren(QAction))
    
    
    
            #set button default actions -> this will show the action icons as well
            #I don't know why this is not possible in the QDesigner when QToolButtons are
            #placed outside a toolbar
    
            import timeseriesviewer.ui.docks as docks
    
            area = None
    
            def addDockWidget(dock):
                """
                shortcut to add a created dock and return it
                :param dock:
                :return:
                """
                self.addDockWidget(area, dock)
                return dock
    
            area = Qt.LeftDockWidgetArea
    
            self.dockRendering = addDockWidget(docks.RenderingDockUI(self))
            self.dockNavigation = addDockWidget(docks.NavigationDockUI(self))
    
            from timeseriesviewer.labeling import LabelingDockUI
            self.dockLabeling = addDockWidget(LabelingDockUI(self))
            #self.tabifyDockWidget(self.dockNavigation, self.dockRendering)
            #self.tabifyDockWidget(self.dockNavigation, self.dockLabeling)
    
            from timeseriesviewer.sensorvisualization import SensorDockUI
            self.dockSensors = addDockWidget(SensorDockUI(self))
            #area = Qt.RightDockWidgetArea
    
    
            area = Qt.BottomDockWidgetArea
    
            from timeseriesviewer.mapvisualization import MapViewDockUI
            self.dockMapViews = addDockWidget(MapViewDockUI(self))
    
            self.dockTimeSeries = addDockWidget(docks.TimeSeriesDockUI(self))
            from timeseriesviewer.profilevisualization import ProfileViewDockUI
            self.dockProfiles = addDockWidget(ProfileViewDockUI(self))
            self.tabifyDockWidget(self.dockTimeSeries, self.dockMapViews)
            self.tabifyDockWidget(self.dockTimeSeries, self.dockProfiles)
    
    
            for dock in self.findChildren(QDockWidget):
                if len(dock.actions()) > 0:
                    s = ""
                self.menuPanels.addAction(dock.toggleViewAction())
    
    
            self.dockLabeling.setHidden(True)
    
            self.dockTimeSeries.raise_()
            self.dockNavigation.raise_()
    
            self.dockMapViews.btnAddMapView.setDefaultAction(self.actionAddMapView)
    
    
            #todo: move to QGS_TSV_Bridge
            self.dockRendering.cbQgsVectorLayer.setFilters(QgsMapLayerProxyModel.VectorLayer)
    
            #define subset-size behaviour
    
            self.restoreSettings()
    
    
        def restoreSettings(self):
            from timeseriesviewer import SETTINGS
    
            #set last CRS
            self.dockNavigation.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
            s = ""
    
    
        def setQgsLinkWidgets(self):
            #enable/disable widgets that rely on QGIS instance interaction
            from timeseriesviewer import QGIS_TSV_BRIDGE
            from timeseriesviewer.main import QgisTsvBridge
            b = isinstance(QGIS_TSV_BRIDGE, QgisTsvBridge)
            self.dockNavigation.gbSyncQgs.setEnabled(b)
            self.dockRendering.gbQgsVectorLayer.setEnabled(b)
    
        def _blockSignals(self, widgets, block=True):
            states = dict()
            if isinstance(widgets, dict):
                for w, block in widgets.items():
                    states[w] = w.blockSignals(block)
            else:
                for w in widgets:
                    states[w] = w.blockSignals(block)
            return states
    
    
    
    
    
    
        sigSubsetSizeChanged = pyqtSignal(QSize)
        def setSubsetSize(self, size, blockSignal=False):
            old = self.subsetSize()
    
            if blockSignal:
                states = self._blockSignals(w, True)
    
            self.spinBoxSubsetSizeX.setValue(size.width())
            self.spinBoxSubsetSizeY.setValue(size.height())
            self._setUpdateBehaviour()
    
            if blockSignal:
                self._blockSignals(states)
            elif old != size:
                self.sigSubsetSizeChanged(size)
    
    
        def setProgress(self, value, valueMax=None, valueMin=0):
            p = self.progressBar
            if valueMin is not None and valueMin != self.progessBar.minimum():
                p.setMinimum(valueMin)
            if valueMax is not None and valueMax != self.progessBar.maximum():
                p.setMaximum(valueMax)
            self.progressBar.setValue(value)
    
    
    
    
    class TimeSeriesViewer:
    
    unknown's avatar
    unknown committed
    
        def __init__(self, iface):
            """Constructor.
    
            :param iface: An interface instance that will be passed to this class
                which provides the hook by which you can manipulate the QGIS
                application at run time.
            :type iface: QgsInterface
            """
            # Save reference to the QGIS interface
    
            self.ui = TimeSeriesViewerUI()
    
    
            #init empty time series
            self.TS = TimeSeries()
            self.hasInitialCenterPoint = False
    
            self.TS.sigTimeSeriesDatesAdded.connect(self.datesAdded)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            #self.ICP = D.scrollAreaSubsetContent.layout()
            #D.scrollAreaMapViews.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
            #self.BVP = self.ui.scrollAreaMapViews.layout()
    
            D.dockNavigation.connectTimeSeries(self.TS)
            D.dockTimeSeries.connectTimeSeries(self.TS)
    
            D.dockSensors.connectTimeSeries(self.TS)
    
            D.dockProfiles.connectTimeSeries(self.TS)
    
            self.spectralTemporalVis = D.dockProfiles
    
            from timeseriesviewer.mapvisualization import SpatialTemporalVisualization
    
            self.spatialTemporalVis = SpatialTemporalVisualization(self)
            self.spatialTemporalVis.sigLoadingStarted.connect(self.ui.dockRendering.addStartedWork)
            self.spatialTemporalVis.sigLoadingFinished.connect(self.ui.dockRendering.addFinishedWork)
    
            self.spatialTemporalVis.sigShowProfiles.connect(self.spectralTemporalVis.loadCoordinate)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            self.spectralTemporalVis.sigMoveToTSD.connect(self.spatialTemporalVis.navigateToTSD)
    
            D.dockNavigation.sigSetSpatialExtent.connect(self.spatialTemporalVis.setSpatialExtent)
    
    unknown's avatar
    unknown committed
            self.ValidatorPxX = QIntValidator(0,99999)
            self.ValidatorPxY = QIntValidator(0,99999)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
            #connect actions with logic
    
            #D.btn_showPxCoordinate.clicked.connect(lambda: self.showSubsetsStart())
    
            #connect actions with logic
    
            D.actionMoveCenter.triggered.connect(lambda : self.spatialTemporalVis.activateMapTool('moveCenter'))
    
            #D.actionSelectArea.triggered.connect(lambda : self.spatialTemporalVis.activateMapTool('selectArea'))
    
            D.actionZoomMaxExtent.triggered.connect(lambda : self.zoomTo('zoomMaxExtent'))
            D.actionZoomPixelScale.triggered.connect(lambda: self.zoomTo('zoomPixelScale'))
    
            D.actionZoomIn.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('zoomIn'))
            D.actionZoomOut.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('zoomOut'))
            D.actionPan.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('pan'))
    
            D.actionIdentifyTimeSeries.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('identifyProfile'))
            D.actionIdentifyMapLayers.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('identifyMapLayers'))
    
            D.actionAddMapView.triggered.connect(self.spatialTemporalVis.createMapView)
    
    
            D.actionAddTSD.triggered.connect(lambda : self.addTimeSeriesImages())
    
            D.actionRemoveTSD.triggered.connect(lambda: self.TS.removeDates(self.ui.dockTimeSeries.selectedTimeSeriesDates()))
    
            D.actionRefresh.triggered.connect(self.spatialTemporalVis.refresh)
    
            D.actionLoadTS.triggered.connect(self.loadTimeSeries)
    
            D.actionClearTS.triggered.connect(self.clearTimeSeries)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            D.actionSaveTS.triggered.connect(self.ua_saveTSFile)
            D.actionAddTSExample.triggered.connect(self.ua_loadExampleTS)
    
    
            D.actionShowCrosshair.toggled.connect(self.spatialTemporalVis.setShowCrosshair)
    
            #connect buttons with actions
    
            from timeseriesviewer.ui.widgets import AboutDialogUI, PropertyDialogUI
    
            D.actionAbout.triggered.connect(lambda: AboutDialogUI(self.ui).exec_())
            D.actionSettings.triggered.connect(lambda : PropertyDialogUI(self.ui).exec_())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            D.actionFirstTSD.triggered.connect(lambda: self.setDOISliderValue('first'))
            D.actionLastTSD.triggered.connect(lambda: self.setDOISliderValue('last'))
            D.actionNextTSD.triggered.connect(lambda: self.setDOISliderValue('next'))
            D.actionPreviousTSD.triggered.connect(lambda: self.setDOISliderValue('previous'))
    
    
    
            D.dockRendering.actionSetSubsetSize.triggered.connect(lambda : self.spatialTemporalVis.setSubsetSize(
                                                    D.dockRendering.subsetSize()))
            D.actionSetExtent.triggered.connect(lambda: self.spatialTemporalVis.setSpatialExtent(self.ui.spatialExtent()))
    
            self.canvasCrs = QgsCoordinateReferenceSystem()
    
            if iface:
                import timeseriesviewer
                timeseriesviewer.QGIS_TSV_BRIDGE = QgisTsvBridge(iface, self)
                self.ui.setQgsLinkWidgets()
    
    
        def loadImageFiles(self, files):
            assert isinstance(files, list)
            self.TS.addFiles(files)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def loadTimeSeries(self, path=None, n_max=None):
            if path is None or path is False:
                path = QFileDialog.getOpenFileName(self.ui, 'Open Time Series file', '')
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            if os.path.exists(path):
                M = self.ui.dockTimeSeries.tableView_TimeSeries.model()
                M.beginResetModel()
                self.clearTimeSeries()
                self.TS.loadFromFile(path, n_max=n_max)
                M.endResetModel()
    
            if key == 'zoomMaxExtent':
    
                ext = self.TS.getMaxSpatialExtent(self.ui.dockNavigation.crs())
    
            elif key == 'zoomPixelScale':
    
                extent = self.spatialTemporalVis.spatialExtent()
                center = extent.center()
                crs = extent.crs()
                pxSize = max(self.TS.getPixelSizes(), key= lambda s :s.width())
                canvasSize = self.spatialTemporalVis.subsetSize
                f = 0.05
                width = f * canvasSize.width() * pxSize.width()  # width in map units
                height = f * canvasSize.height() * pxSize.height()
    
                ext = SpatialExtent(crs, 0, 0, width, height)
                ext.setCenter(center)
            else:
                raise NotImplementedError(key)
            self.spatialTemporalVis.setSpatialExtent(ext)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    
        def icon(self):
            return TimeSeriesViewer.icon()
    
    
        def onTimeSeriesChanged(self):
    
                    if len(self.spatialTemporalVis.MVC) == 0:
                        # add two empty band-views by default
                        self.spatialTemporalVis.createMapView()
                        self.spatialTemporalVis.createMapView()
    
    
                    extent = self.TS.getMaxSpatialExtent()
                    self.spatialTemporalVis.setSubsetSize(self.ui.dockRendering.subsetSize())
                    self.spatialTemporalVis.setSpatialExtent(extent)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def ua_saveTSFile(self):
    
            path = QFileDialog.getSaveFileName(self.ui, caption='Save Time Series file')
    
            if path is not None:
                self.TS.saveToFile(path)
    
    
        def ua_loadExampleTS(self):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            from timeseriesviewer import PATH_EXAMPLE_TIMESERIES
            if not os.path.exists(PATH_EXAMPLE_TIMESERIES):
    
                QMessageBox.information(self.ui, 'File not found', '{} - this file describes an exemplary time series.'.format(PATH_EXAMPLE_TIMESERIES))
    
    unknown's avatar
    unknown committed
        def ua_selectByRectangle(self):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if self.RectangleMapTool is not None:
    
    unknown's avatar
    unknown committed
    
        def ua_selectByCoordinate(self):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if self.PointMapTool is not None:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def qgs_handleMouseDown(self, pt, btn):
    
    unknown's avatar
    unknown committed
    
    
        def ua_TSprogress(self, v_min, v, v_max):
            assert v_min <= v and v <= v_max
    
            if v_min < v_max:
    
                if P.minimum() != v_min or P.maximum() != v_max:
                    P.setRange(v_min, v_max)
                else:
                    s = ""
    
                P.setValue(v)
    
    unknown's avatar
    unknown committed
    
    
        def datesAdded(self, dates):
            assert isinstance(dates, list)
    
            self.ui.dockTimeSeries.tableView_TimeSeries.resizeColumnsToContents()
    
            self.onTimeSeriesChanged()
    
    unknown's avatar
    unknown committed
    
    
        # noinspection PyMethodMayBeStatic
        def tr(self, message):
            """Get the translation for a string using Qt translation API.
    
            We implement this ourselves since we do not inherit QObject.
    
            :param message: String for translation.
            :type message: str, QString
    
            :returns: Translated version of message.
            :rtype: QString
            """
            # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
            return QCoreApplication.translate('EnMAPBox', message)
    
    
    
    
    
    
        def ua_addTSD_to_QGIS(self, TSD, bands):
    
    unknown's avatar
    unknown committed
        def unload(self):
    
            """Removes the plugin menu item and icon """
            self.iface.removeToolBarIcon(self.action)
    
    unknown's avatar
    unknown committed
    
        def run(self):
    
    unknown's avatar
    unknown committed
    
    
    
        def scrollToDate(self, date_of_interest):
    
            HBar = self.ui.scrollArea_imageChips.horizontalScrollBar()
    
            TSDs = list(self.CHIPWIDGETS.keys())
            if len(TSDs) == 0:
    
                return
    
            #get date INDEX that is closest to requested date
    
            if type(date_of_interest) is str:
                date_of_interest = np.datetime64(date_of_interest)
    
    
            if type(date_of_interest) is np.datetime64:
                i_doi = TSDs.index(sorted(TSDs, key=lambda TSD: abs(date_of_interest - TSD.getDate()))[0])
            else:
                i_doi = date_of_interest
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            step = int(float(HBar.maximum()) / (len(TSDs)+1))
            HBar.setSingleStep(step)
            HBar.setPageStep(step*5)
            HBar.setValue(i_doi * step)
    
        def ua_collect_date(self, ICL, event):
    
            if self.ui.rb_labeling_activate.isChecked():
                txt = self.ui.tb_labeling_text.toPlainText()
    
                reg = re.compile('\d{4}-\d{2}-\d{2}', re.I | re.MULTILINE)
                dates = set([np.datetime64(m) for m in reg.findall(txt)])
                doi = ICL.TSD.getDate()
    
    
                if event.button() == Qt.LeftButton:
    
                    dates.add(doi)
    
                elif event.button() == Qt.MiddleButton and doi in dates:
                    dates.remove(doi)
    
    
                dates = sorted(list(dates))
                txt = ' '.join([d.astype(str) for d in dates])
    
                self.ui.tb_labeling_text.setText(txt)
    
    unknown's avatar
    unknown committed
    
        def clearLayoutWidgets(self, L):
            if L is not None:
                while L.count():
                    w = L.takeAt(0)
    
                    if w.widget():
                        w.widget().deleteLater()
    
    unknown's avatar
    unknown committed
                    #if w is not None:
                    #    w.widget().deleteLater()
    
    unknown's avatar
    unknown committed
    
    
        def addTimeSeriesImages(self, files=None):
    
    unknown's avatar
    unknown committed
            if files is None:
                files = QFileDialog.getOpenFileNames()
    
    
                #collect sublayers, if existing
    
    
    
    unknown's avatar
    unknown committed
            if files:
                self.TS.addFiles(files)
    
    
        def clearTimeSeries(self):
    
    unknown's avatar
    unknown committed
            #remove views
    
    
            M = self.ui.dockTimeSeries.tableView_TimeSeries.model()
    
    unknown's avatar
    unknown committed
            M.beginResetModel()
            self.TS.clear()
            M.endResetModel()
    
    
        def getSelectedTSDs(self):
    
            TV = self.ui.tableView_TimeSeries
    
            return [TVM.getTimeSeriesDatumFromIndex(idx) for idx in TV.selectionModel().selectedRows()]
    
    def disconnect_signal(signal):
        while True:
            try:
                signal.disconnect()
            except TypeError:
                break
    
    unknown's avatar
    unknown committed