Skip to content
Snippets Groups Projects
temporalprofiles2d.py 56.5 KiB
Newer Older
        super(TemporalProfilePlotDataItem, self).__init__([], [], parent=parent)
        self.menu = None
        #self.setFlags(QGraphicsItem.ItemIsSelectable)
        self.mPlotStyle = plotStyle
        self.setAcceptedMouseButtons(Qt.LeftButton | Qt.RightButton)
        self.mPlotStyle.sigUpdated.connect(self.updateDataAndStyle)
        self.updateStyle()

    # On right-click, raise the context menu
    def mouseClickEvent(self, ev):
        if ev.button() == QtCore.Qt.RightButton:
            if self.raiseContextMenu(ev):
                ev.accept()

    def raiseContextMenu(self, ev):
        menu = self.getContextMenus()

        # Let the scene add on to the end of our context menu
        # (this is optional)
        menu = self.scene().addParentContextMenus(self, menu, ev)

        pos = ev.screenPos()
        menu.popup(QtCore.QPoint(pos.x(), pos.y()))
        return True

    # This method will be called when this item's _children_ want to raise
    # a context menu that includes their parents' menus.
    def getContextMenus(self, event=None):
        if self.menu is None:
            self.menu = QMenu()
            self.menu.setTitle(self.name + " options..")

            green = QAction("Turn green", self.menu)
            green.triggered.connect(self.setGreen)
            self.menu.addAction(green)
            self.menu.green = green

            blue = QAction("Turn blue", self.menu)
            blue.triggered.connect(self.setBlue)
            self.menu.addAction(blue)
            self.menu.green = blue

            alpha = QWidgetAction(self.menu)
            alphaSlider = QSlider()
            alphaSlider.setOrientation(QtCore.Qt.Horizontal)
            alphaSlider.setMaximum(255)
            alphaSlider.setValue(255)
            alphaSlider.valueChanged.connect(self.setAlpha)
            alpha.setDefaultWidget(alphaSlider)
            self.menu.addAction(alpha)
            self.menu.alpha = alpha
            self.menu.alphaSlider = alphaSlider
        return self.menu


    def updateDataAndStyle(self):

        TP = self.mPlotStyle.temporalProfile()
        sensor = self.mPlotStyle.sensor()

        if isinstance(TP, TemporalProfile) and isinstance(sensor, SensorInstrument):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            x, y = TP.dataFromExpression(self.mPlotStyle.sensor(), self.mPlotStyle.expression(), dateType='date')
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                x = np.asarray(x, dtype=np.float)
                y = np.asarray(y, dtype=np.float)
                self.setData(x=[], y=[]) # dummy
        else:
            self.setData(x=[], y=[])  # dummy for empty data
    def updateStyle(self):
        """
        Updates visibility properties
        """
        from pyqtgraph.graphicsItems.ScatterPlotItem import drawSymbol
#        path = drawSymbol(p, self.markerSymbol, self.markerSize, self.markerPen, self.markerBrush)
    #                    #painter, symbol, size, pen, brush
        self.setVisible(self.mPlotStyle.isVisible())
        self.setSymbol(self.mPlotStyle.markerSymbol)
        self.setSymbolSize(self.mPlotStyle.markerSize)
        self.setSymbolBrush(self.mPlotStyle.markerBrush)
        self.setSymbolPen(self.mPlotStyle.markerPen)
        self.setPen(self.mPlotStyle.linePen)
        self.update()

        #self.setPen(fn.mkPen(self.mPlotStyle.linePen))
        #self.setFillBrush(fn.mkBrush(self.mPlotStyle.mExpression))
        #self.setSymbolBrush(fn.mkBrush(self.mPlotStyle.markerBrush))

        # self.setFillBrush(self.mPlotStyle.)

        #self.update()

    def setClickable(self, b, width=None):
        assert isinstance(b, bool)
        self.curve.setClickable(b, width=width)

    def setColor(self, color):
        if not isinstance(color, QColor):

            color = QColor(color)
        self.setPen(color)

    def pen(self):
        return fn.mkPen(self.opts['pen'])

    def color(self):
        return self.pen().color()


    def setLineWidth(self, width):
        pen = pg.mkPen(self.opts['pen'])
        assert isinstance(pen, QPen)
        pen.setWidth(width)
        self.setPen(pen)



class TemporalProfileLayer(QgsVectorLayer):
    """
    A collection to store the TemporalProfile data delivered by a PixelLoader
    """

    #sigSensorAdded = pyqtSignal(SensorInstrument)
    #sigSensorRemoved = pyqtSignal(SensorInstrument)
    #sigPixelAdded = pyqtSignal()
    #sigPixelRemoved = pyqtSignal()

    sigTemporalProfilesAdded = pyqtSignal(list)
    sigTemporalProfilesRemoved = pyqtSignal(list)
    sigMaxProfilesChanged = pyqtSignal(int)
Benjamin Jakimow's avatar
Benjamin Jakimow committed


Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def __init__(self, timeSeries, name='Temporal Profiles'):
        assert isinstance(timeSeries, TimeSeries)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        crs = QgsCoordinateReferenceSystem('EPSG:4326')
        uri = 'Point?crs={}'.format(crs.authid())
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        lyrOptions = QgsVectorLayer.LayerOptions(loadDefaultStyle=False, readExtentFromXml=False)
        super(TemporalProfileLayer, self).__init__(uri, name, 'memory', lyrOptions)

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        from collections import OrderedDict
        self.mProfiles = OrderedDict()
        self.mTimeSeries = timeSeries
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        #symbol = QgsFillSymbol.createSimple({'style': 'no', 'color': 'red', 'outline_color': 'black'})
        #self.mLocations.renderer().setSymbol(symbol)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        fields.append(createQgsField(FN_ID, self.mNextID))
        fields.append(createQgsField(FN_NAME,''))
        fields.append(createQgsField(FN_X, 0.0, comment='Longitude'))
        fields.append(createQgsField(FN_Y, 0.0, comment='Latitude'))
        fields.append(createQgsField(FN_N_TOTAL, 0, comment='Total number of band values'))
        fields.append(createQgsField(FN_N_NODATA,0, comment='Total of no-data values.'))
        fields.append(createQgsField(FN_N_LOADED, 0, comment='Loaded valid band values.'))
        fields.append(createQgsField(FN_N_LOADED_PERCENT,0.0, comment='Loading progress (%)'))
        assert self.startEditing()
        assert self.dataProvider().addAttributes(fields)
        assert self.commitChanges()
        self.initConditionalStyles()

        self.committedFeaturesAdded.connect(self.onFeaturesAdded)
        self.committedFeaturesRemoved.connect(self.onFeaturesRemoved)
        return list(self.mProfiles.values())[slice]
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        """
        Returns the TimeSeries instance.
        :return: TimeSeries
        """
    def onFeaturesAdded(self, layerID, addedFeatures):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        """
        Create a TemporalProfile object for each QgsFeature added to the backend QgsVectorLayer
        :param layerID:
        :param addedFeatures:
        :return:
        """
            temporalProfiles = []
            for feature in addedFeatures:
                fid = feature.id()
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                if fid < 0:
                    continue
                self.mProfiles[fid] = tp
                temporalProfiles.append(tp)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            if len(temporalProfiles) > 0:
                pass
                #self.sigTemporalProfilesAdded.emit(temporalProfiles)
    def onFeaturesRemoved(self,  layerID, removedFIDs):
        if len(removedFIDs) > 0:
            for fid in removedFIDs:
                toRemove.append(self.mProfiles.pop(fid))
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            self.sigTemporalProfilesRemoved.emit(toRemove)
    def initConditionalStyles(self):
        styles = self.conditionalStyles()
        assert isinstance(styles, QgsConditionalLayerStyles)
        for fieldName in self.fields().names():
            red = QgsConditionalStyle("@value is NULL")
            red.setTextColor(QColor('red'))
            styles.setFieldStyles(fieldName, [red])
        #styles.setRowStyles([red])
    def createTemporalProfiles(self, coordinates):
        """
        Creates temporal profiles
        :param coordinates:
        :return:
        """
        if not isinstance(coordinates, list):
            coordinates = [coordinates]
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        n = self.featureCount()
        for i, coordinate in enumerate(coordinates):
            assert isinstance(coordinate, SpatialPoint)
            f = QgsFeature(self.fields())
            f.setGeometry(QgsGeometry.fromPointXY(coordinate.toCrs(self.crs())))
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            f.setAttribute(FN_ID, self.mNextID)
            f.setAttribute(FN_NAME, 'Location {}'.format(self.mNextID))
            f.setAttribute(FN_X, coordinate.x())
            f.setAttribute(FN_Y, coordinate.y())
            f.setAttribute(FN_N_LOADED_PERCENT, 0.0)
            f.setAttribute(FN_N_LOADED, 0)
            f.setAttribute(FN_N_TOTAL, 0)
            f.setAttribute(FN_N_NODATA, 0)
        b = self.isEditable()
        tps_before = list(self.mProfiles.values())
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.startEditing()
        success = self.addFeatures(features)
        self.saveEdits(leaveEditable=b)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            assert n+len(features) == self.featureCount()
            assert self.featureCount() == len(self.mProfiles)
            profiles = [tp for tp in self.mProfiles.values() if tp not in tps_before]
            for p in profiles:
                p.updateLoadingStatus()
            return profiles
    def saveEdits(self, leaveEditable=True, triggerRepaint=True):
        """
        function to save layer changes-
        :param layer:
        :param leaveEditable:
        :param triggerRepaint:
        """
        if not self.isEditable():
            return
        if not self.commitChanges():
            self.commitErrors()
        if leaveEditable:
            self.startEditing()
        if triggerRepaint:
            self.triggerRepaint()
    def addMissingFields(self, fields):
        missingFields = []
        for field in fields:
            assert isinstance(field, QgsField)
            i = self.dataProvider().fieldNameIndex(field.name())
            if i == -1:
                missingFields.append(field)
        if len(missingFields) > 0:
            b = self.isEditable()
            self.startEditing()
            self.dataProvider().addAttributes(missingFields)
            self.saveEdits(leaveEditable=b)
    def __len__(self):
        return self.featureCount()
    def __iter__(self):
        r = QgsFeatureRequest()
        for f in self.getFeatures(r):
            yield self.mProfiles[f.id()]
    def __contains__(self, item):
        return item in self.mProfiles.values()


    def temporalProfileToLocationFeature(self, tp:TemporalProfile):

        self.mLocations.selectByIds([tp.id()])
        for f in self.mLocations.selectedFeatures():
            assert isinstance(f, QgsFeature)
            return f

        return None

    def fromSpatialPoint(self, spatialPoint):
        """ Tests if a Temporal Profile already exists for the given spatialPoint"""
        spatialPoint = spatialPoint.toCrs(self.crs())
        unit = QgsUnitTypes.toAbbreviatedString(self.crs().mapUnits()).lower()
        x = spatialPoint.x() + 0.00001
        y = spatialPoint.y() + 0.
        if 'degree' in unit:
            dx = dy = 0.000001
            dx = dy = 0.1
        rect = QgsRectangle(x-dx,y-dy, x+dy,y+dy)
        for f  in self.getFeatures(rect):
            return self.mProfiles[f.id()]
        return None

    def removeTemporalProfiles(self, temporalProfiles):
        """
        Removes temporal profiles from this collection
        :param temporalProfile: TemporalProfile
        """

        if isinstance(temporalProfiles, TemporalProfile):
            temporalProfiles = [temporalProfiles]
        assert isinstance(temporalProfiles, list)

        temporalProfiles = [tp for tp in temporalProfiles if isinstance(tp, TemporalProfile) and tp.id() in self.mProfiles.keys()]
            b = self.isEditable()
            assert self.startEditing()

            fids = [tp.mID for tp in temporalProfiles]

            self.deleteFeatures(fids)
            self.saveEdits(leaveEditable=b)

            self.sigTemporalProfilesRemoved.emit(temporalProfiles)


    def setMaxProfiles(self, n):
        """
        Sets the maximum number of temporal profiles to be stored in this container.
        :param n: number of profiles, must be >= 1
        """
        old = self.mMaxProfiles

        assert n >= 1
        if old != n:
            self.mMaxProfiles = n

            self.prune()
            self.sigMaxProfilesChanged.emit(self.mMaxProfiles)

    def prune(self, nMax=None):
        """
        Reduces the number of temporal profile to the value n defined with .setMaxProfiles(n)
        :return: [list-of-removed-TemporalProfiles]
        """
        if nMax is None:
            nMax = self.mMaxProfiles

        nMax = max(nMax, 1)

        toRemove = len(self) - nMax
        if toRemove > 0:

            toRemove = sorted(self[:], key=lambda p:p.id())[0:toRemove]
            self.removeTemporalProfiles(toRemove)





    def getFieldDefn(self, name, values):
        if isinstance(values, np.ndarray):
            # add bands
            if values.dtype in [np.int8, np.int16, np.int32, np.int64,
                                np.uint8, np.uint16, np.uint32, np.uint64]:
                fType = QVariant.Int
                fTypeName = 'integer'
            elif values.dtype in [np.float16, np.float32, np.float64]:
                fType = QVariant.Double
                fTypeName = 'decimal'
        else:
            raise NotImplementedError()

        return QgsField(name, fType, fTypeName)


    def addPixelLoaderResult(self, d):
        assert isinstance(d, PixelLoaderTask)
        if d.success():
            for fid in d.temporalProfileIDs:
                TP = self.mProfiles.get(fid)
                if isinstance(TP, TemporalProfile):
                    TP.pullDataUpdate(d)
                else:
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                    pass

    def clear(self):
        #todo: remove TS Profiles
        #self.mTemporalProfiles.clear()
        #self.sensorPxLayers.clear()
        pass


class TemporalProfileTableFilterModel(QgsAttributeTableFilterModel):
    def __init__(self, sourceModel, parent=None):
        dummyCanvas = QgsMapCanvas()
        dummyCanvas.setDestinationCrs(DEFAULT_CRS)
        dummyCanvas.setExtent(QgsRectangle(-180,-90,180,90))
        super(TemporalProfileTableFilterModel, self).__init__(dummyCanvas, sourceModel, parent=parent)
class TemporalProfileTableModel(QgsAttributeTableModel):
    #sigPlotStyleChanged = pyqtSignal(SpectralProfile)
    #sigAttributeRemoved = pyqtSignal(str)
    #sigAttributeAdded = pyqtSignal(str)
    AUTOGENERATES_COLUMNS = [FN_Y, FN_X, FN_N_LOADED, FN_N_TOTAL, FN_N_NODATA, FN_ID, FN_N_LOADED_PERCENT]

    def __init__(self, temporalProfileLayer=None, parent=None):

        if temporalProfileLayer is None:
            temporalProfileLayer = TemporalProfileLayer()

        cache = QgsVectorLayerCache(temporalProfileLayer, 1000)

        super(TemporalProfileTableModel, self).__init__(cache, parent)
        self.mTemporalProfileLayer = temporalProfileLayer
        self.mCache = cache
        assert self.mCache.layer() == self.mTemporalProfileLayer
        self.loadLayer()

    def columnNames(self):
        return self.mTemporalProfileLayer.fields().names()

    def feature(self, index):

        id = self.rowToId(index.row())
        f = self.layer().getFeature(id)

        return f

    def temporalProfile(self, index):
        feature = self.feature(index)
        return self.mTemporalProfileLayer.temporalProfileFromFeature(feature)

    def data(self, index, role=Qt.DisplayRole):
        Returns Temporal Profile Layer values
        :param index: QModelIndex
        :param role: enum Qt.ItemDataRole
        :return: value
        """
        if role is None or not index.isValid():
            return None

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        result = super(TemporalProfileTableModel, self).data(index, role=role)

    def setData(self, index, value, role=None):
        """
        Sets Temporal Profile Data.
        :param index: QModelIndex()
        :param value: value to set
        :param role: role
        :return: True | False
        """
        if role is None or not index.isValid():
            return False

        f = self.feature(index)
        result = False

        if value == None:
            value = QVariant()
        cname = self.columnNames()[index.column()]
        if role == Qt.EditRole and cname not in TemporalProfileTableModel.AUTOGENERATES_COLUMNS:
            i = f.fieldNameIndex(cname)
            if f.attribute(i) == value:
                return False
            b = self.mTemporalProfileLayer.isEditable()
            self.mTemporalProfileLayer.startEditing()
            self.mTemporalProfileLayer.changeAttributeValue(f.id(), i, value)
            self.mTemporalProfileLayer.saveEdits(leaveEditable=b)
            result = True
            #f = self.layer().getFeature(profile.id())
            #i = f.fieldNameIndex(SpectralProfile.STYLE_FIELD)
            #self.layer().changeAttributeValue(f.id(), i, value)
            #result = super().setData(self.index(index.row(), self.mcnStyle), value, role=Qt.EditRole)
            #if not b:
            #    self.layer().commitChanges()
        if result:
            self.dataChanged.emit(index, index, [role])
        else:
            result = super().setData(index, value, role=role)


        return result


Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def headerData(self, section:int, orientation:Qt.Orientation, role:int):
        data = super(TemporalProfileTableModel, self).headerData(section, orientation, role)
        if role == Qt.ToolTipRole and orientation == Qt.Horizontal:
            #add the field comment to column description
            field = self.layer().fields().at(section)
            assert isinstance(field, QgsField)
            comment = field.comment()
            if len(comment) > 0:
                data = re.sub('</p>$', ' <i>{}</i></p>'.format(comment), data)

        return data

    def supportedDragActions(self):
        return Qt.CopyAction | Qt.MoveAction

    def supportedDropActions(self):
        return Qt.CopyAction | Qt.MoveAction


    def supportedDragActions(self):
        return Qt.CopyAction

    def supportedDropActions(self):
        return Qt.CopyAction

    def flags(self, index):

        if index.isValid():
            columnName = self.columnNames()[index.column()]
            flags = super(TemporalProfileTableModel, self).flags(index) | Qt.ItemIsSelectable
            #if index.column() == 0:
            #    flags = flags | Qt.ItemIsUserCheckable

            if columnName in TemporalProfileTableModel.AUTOGENERATES_COLUMNS:
                flags = flags ^ Qt.ItemIsEditable
            return flags
        return None


class TemporalProfileFeatureSelectionManager(QgsIFeatureSelectionManager):


    def __init__(self, layer, parent=None):
        s =""
        super(TemporalProfileFeatureSelectionManager, self).__init__(parent)
        assert isinstance(layer, QgsVectorLayer)
        self.mLayer = layer
        self.mLayer.selectionChanged.connect(self.selectionChanged)

    def layer(self):
        return self.mLayer

    def deselect(self, ids):

        if len(ids) > 0:
            selected = [id for id in self.selectedFeatureIds() if id not in ids]
            self.mLayer.deselect(ids)

            self.selectionChanged.emit(selected, ids, True)

    def select(self, ids):
        self.mLayer.select(ids)

    def selectFeatures(self, selection, command):

        super(TemporalProfileFeatureSelectionManager, self).selectF
        s = ""
    def selectedFeatureCount(self):
        return self.mLayer.selectedFeatureCount()

    def selectedFeatureIds(self):
        return self.mLayer.selectedFeatureIds()
    def setSelectedFeatures(self, ids):
        self.mLayer.selectByIds(ids)


class TemporalProfileTableView(QgsAttributeTableView):

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


        #self.setSelectionBehavior(QAbstractItemView.SelectRows)
        #self.setSelectionMode(QAbstractItemView.SingleSelection)
        self.horizontalHeader().setSectionsMovable(True)
        self.willShowContextMenu.connect(self.onWillShowContextMenu)
        self.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)


        self.mSelectionManager = None

    def setModel(self, filterModel):

        super(TemporalProfileTableView, self).setModel(filterModel)


        self.mSelectionManager = TemporalProfileFeatureSelectionManager(self.model().layer())
        self.setFeatureSelectionManager(self.mSelectionManager)
        #self.selectionModel().selectionChanged.connect(self.onSelectionChanged)
        self.mContextMenuActions = []
    def setContextMenuActions(self, actions:list):
        self.mContextMenuActions = actions

    #def contextMenuEvent(self, event):
    def onWillShowContextMenu(self, menu, index):
        assert isinstance(menu, QMenu)
        assert isinstance(index, QModelIndex)

        featureIDs = self.temporalProfileLayer().selectedFeatureIds()

        if len(featureIDs) == 0 and index.isValid():
            if isinstance(self.model(), QgsAttributeTableFilterModel):
                index = self.model().mapToSource(index)
                if index.isValid():
                    featureIDs.append(self.model().sourceModel().feature(index).id())
            elif isinstance(self.model(), QgsAttributeTableFilterModel):
                featureIDs.append(self.model().feature(index).id())



        if len(featureIDs) > 0:
            a = menu.addAction('Load missing values')
            a.setToolTip('Load missing values')
            #m = menu.addMenu('Copy...')
            #a = m.addAction("Values")
            #a.triggered.connect(lambda b, ids=featureIDs, mode=ClipboardIO.WritingModes.VALUES: self.onCopy2Clipboard(ids, mode))
            #a = m.addAction("Attributes")
            #a.triggered.connect(lambda b, ids=featureIDs, mode=ClipboardIO.WritingModes.ATTRIBUTES: self.onCopy2Clipboard(ids, mode))
            #a = m.addAction("Values + Attributes")
            #a.triggered.connect(lambda b, ids=featureIDs, mode=ClipboardIO.WritingModes.ALL: self.onCopy2Clipboard(ids, mode))

        a = menu.addAction('Save as...')
        a.triggered.connect(lambda b, ids=featureIDs : self.onSaveToFile(ids))
        menu.addSeparator()
        #a = menu.addAction('Set Style')
        #a.triggered.connect(lambda b, ids=featureIDs : self.onSetStyle(ids))
        #a = menu.addAction('Check')
        #a.triggered.connect(lambda : self.setCheckState(featureIDs, Qt.Checked))
        #a = menu.addAction('Uncheck')
        #a.triggered.connect(lambda: self.setCheckState(featureIDs, Qt.Unchecked))
        #menu.addSeparator()

        for a in self.mContextMenuActions:
            menu.addAction(a)

        for a in self.actions():
            menu.addAction(a)

    def temporalProfileLayer(self):
        return self.model().layer()



    def fidsToIndices(self, fids):
        """
        Converts feature ids into FilterModel QModelIndices
        :param fids: [list-of-int]
        :return:
        """
        if isinstance(fids, int):
            fids = [fids]
        assert isinstance(fids, list)
        fmodel = self.model()
        indices = [fmodel.fidToIndex(id) for id in fids]
        return [fmodel.index(idx.row(), 0) for idx in indices]

    def onRemoveFIDs(self, fids):

        layer = self.temporalProfileLayer()
        assert isinstance(layer, TemporalProfileLayer)
        b = layer.isEditable()
        layer.startEditing()
        layer.deleteFeatures(fids)
        layer.saveEdits(leaveEditable=b)


    def dropEvent(self, event):
        assert isinstance(event, QDropEvent)
        mimeData = event.mimeData()

        if self.model().rowCount() == 0:
            index = self.model().createIndex(0,0)
            index = self.indexAt(event.pos())

        #if mimeData.hasFormat(mimedata.MDF_SPECTRALLIBRARY):
         #   self.model().dropMimeData(mimeData, event.dropAction(), index.row(), index.column(), index.parent())
          #  event.accept()





    def dragEnterEvent(self, event):
        assert isinstance(event, QDragEnterEvent)
        #if event.mimeData().hasFormat(mimedata.MDF_SPECTRALLIBRARY):
        #    event.accept()

    def dragMoveEvent(self, event):
        assert isinstance(event, QDragMoveEvent)
        #if event.mimeData().hasFormat(mimedata.MDF_SPECTRALLIBRARY):
        #    event.accept()
        s = ""


    def mimeTypes(self):
        pass

if __name__ == '__main__':
    import site, sys
    from timeseriesviewer import utils
    qgsApp = utils.initQgisApplication()
    DEBUG = False

    w.show()

    #btn = TemporalProfile3DPlotStyleButton()
    #btn.show()
    qgsApp.exec_()
    qgsApp.exitQgis()