From 03f976ec2935d3f20b7713ead314f18c5fd54d5c Mon Sep 17 00:00:00 2001
From: "benjamin.jakimow@geo.hu-berlin.de" <q8DTkxUg-BB>
Date: Wed, 29 Mar 2017 19:21:09 +0200
Subject: [PATCH] added module classificationscheme.py with ClassInfo,
 ClassificationScheme, ClassificationSchemeTableModel,
 ClassificationSchemeWidget and ClassificationSchemeDialog

---
 timeseriesviewer/classificationscheme.py | 283 +++++++++++++++++++++++
 1 file changed, 283 insertions(+)
 create mode 100644 timeseriesviewer/classificationscheme.py

diff --git a/timeseriesviewer/classificationscheme.py b/timeseriesviewer/classificationscheme.py
new file mode 100644
index 00000000..5596e275
--- /dev/null
+++ b/timeseriesviewer/classificationscheme.py
@@ -0,0 +1,283 @@
+
+
+import os
+
+from qgis.core import *
+from qgis.gui import *
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+import numpy as np
+from timeseriesviewer import *
+from timeseriesviewer.utils import *
+
+from timeseriesviewer.ui.widgets import loadUIFormClass
+
+load = lambda p : loadUIFormClass(jp(DIR_UI,p))
+
+class ClassInfo(QObject):
+
+    def __init__(self, name=None, color=None):
+        self.mName = ''
+        self.mColor = QColor('black')
+        if name:
+            self.setName(name)
+        if color:
+            self.setColor(color)
+
+    def setColor(self, color):
+        assert isinstance(color, QColor)
+        self.mColor = color
+
+    def setName(self, name):
+        assert isinstance(name, str)
+        self.mName = name
+
+    def clone(self):
+        return ClassInfo(name=self.mName, color=self.mColor)
+
+class ClassificationScheme(QObject):
+    @staticmethod
+    def fromRasterImage(path, bandIndex=None):
+        ds = gdal.Open(path)
+        assert ds is not None
+        if bandIndex is None:
+            for b in range(ds.RasterCount):
+                band = ds.GetRasterBand(b + 1)
+                cat = band.GetCategoryNames()
+
+                if cat != None:
+                    bandIndex = b
+                    break
+                s = ""
+
+
+        assert bandIndex >= 0 and bandIndex < ds.RasterCount
+        band = ds.GetRasterBand(bandIndex + 1)
+        cat = band.GetCategoryNames()
+        ct = band.GetColorTable()
+        if len(cat) == 0:
+            return None
+        scheme = ClassificationScheme()
+        for i, catName in enumerate(cat):
+            cli = ClassInfo(name=catName)
+            if ct is not None:
+                cli.setColor(QColor(*ct.GetColorEntry(i)))
+            scheme.addClass(cli)
+        return scheme
+
+    @staticmethod
+    def fromVectorFile(self, path, fieldClassName='classname', fieldClassColor='classColor'):
+        pass
+
+    def clear(self):
+        del self.classes[:]
+
+    def __init__(self):
+        super(ClassificationScheme, self).__init__()
+
+        self.classes = []
+
+    def __len__(self):
+        return len(self.classes)
+
+    def __iter__(self):
+        return  self.classes.__iter__()
+
+    def removeClass(self, c):
+        assert c in self.classes
+
+    def addClass(self, c, index=None):
+        assert isinstance(c, ClassInfo)
+        if index is None:
+            index = len(self.classes)
+        self.classes.insert(index, c)
+
+
+class ClassificationSchemeTableModel(QAbstractTableModel):
+    columnNames = ['label', 'name', 'color']
+
+    def __init__(self, parent=None):
+        super(ClassificationSchemeTableModel, self).__init__(parent)
+
+        self.scheme = ClassificationScheme()
+
+    def loadClassesFromImage(self, path, append=True):
+
+        if not append:
+            for c in self.classes:
+                self.removeClass(c)
+
+    def rowCount(self, QModelIndex_parent=None, *args, **kwargs):
+        return len(self.scheme)
+
+    def columnCount(self, parent = QModelIndex()):
+        return len(self.columNames)
+
+    def getIndexFromClassInfo(self, classInfo):
+        return self.createIndex(self.scheme.index(classInfo),0)
+
+    def getClassInfoFromIndex(self, index):
+        if index.isValid():
+            return self.scheme[index.row()]
+        return None
+
+
+
+    def data(self, index, role=Qt.DisplayRole):
+        if role is None or not index.isValid():
+            return None
+
+        columnName = self.columnames[index.column()]
+
+        classInfo = self.getClassInfoFromIndex(index)
+        assert isinstance(classInfo, ClassInfo)
+
+        value = None
+        if role == Qt.DisplayRole:
+            if columnName == 'id':
+                value = index.row()
+            if columnName == 'name':
+                value = classInfo.mName
+            elif columnName == 'color':
+                value = str(classInfo.mColor)
+        return value
+
+    def setData(self, index, value, role=None):
+        if role is None or not index.isValid():
+            return None
+
+        columnName = self.columnames[index.column()]
+
+        classInfo = self.getClassInfoFromIndex(index)
+        assert isinstance(classInfo, ClassInfo)
+
+        if role == Qt.EditRole and columnName == 'name':
+            if len(value) == 0:  # do not accept empty strings
+                return False
+            classInfo.setName(str(value))
+            return True
+
+        return False
+
+    def flags(self, index):
+        if index.isValid():
+            columnName = self.columnames[index.column()]
+            flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
+            if columnName in ['name']:  # allow check state
+                flags = flags | Qt.ItemIsUserCheckable | Qt.ItemIsEditable
+            return flags
+            # return item.qt_flags(index.column())
+        return None
+
+    def headerData(self, col, orientation, role):
+        if Qt is None:
+            return None
+        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
+            return self.columnames[col]
+        elif orientation == Qt.Vertical and role == Qt.DisplayRole:
+            return col
+        return None
+
+class ClassificationSchemeWidget(QWidget, load('classificationscheme.ui')):
+
+    def __init__(self, parent=None, classificationScheme=None):
+        super(ClassificationSchemeWidget, self).__init__(parent)
+        self.setupUi(self)
+
+        self.mScheme = ClassificationScheme()
+        if classificationScheme is not None:
+            self.setClassificationScheme(classificationScheme)
+        self.tableViewModel = ClassificationSchemeTableModel(self)
+        self.tableClassificationScheme.setModel(self.tableViewModel)
+
+        self.btnLoadClasses.clicked.connect(self.loadClasses)
+        self.btnRemoveClasses.clicked.connect(self.removeSelectedClasses)
+        self.btnAddClasses.clicked.connect(self.addClasses)
+
+    def addClasses(self, n):
+        for i in range(n):
+            c = ClassInfo(name = '<empty>', color = QColor('red'))
+            self.mScheme.addClass(c)
+
+
+    def loadClasses(self, *args):
+        path = QFileDialog.getOpenFileName(self, 'Select Raster File', '')
+        if os.path.exists(path):
+            scheme = ClassificationScheme.fromRasterImage(path)
+            if scheme is not None:
+                self.appendClassificationScheme(scheme)
+
+
+    def appendClassificationScheme(self, classificationScheme):
+        assert isinstance(classificationScheme, ClassificationScheme)
+        for c in classificationScheme:
+            self.mScheme.addClass(c)
+
+
+    def setClassificationScheme(self, classificationScheme):
+        assert isinstance(classificationScheme, ClassificationScheme)
+        self.mScheme.classes[:]
+        self.appendClassificationScheme(classificationScheme)
+
+
+class ClassificationSchemeDialog(QgsDialog):
+
+    @staticmethod
+    def getClassificationScheme(*args, **kwds):
+        """
+        Opens a CrosshairDialog.
+        :param args:
+        :param kwds:
+        :return: specified CrosshairStyle if accepted, else None
+        """
+        d = ClassificationSchemeDialog(*args, **kwds)
+        d.exec_()
+
+        if d.result() == QDialog.Accepted:
+            return d.classificationSheme()
+        else:
+            return None
+
+    def __init__(self, parent=None, classificationScheme=None, title='Specify Classification Scheme'):
+        super(ClassificationSchemeDialog, self).__init__(parent=parent , \
+            buttons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
+        self.w = ClassificationSchemeWidget(parent=self, classificationScheme=classificationScheme)
+        self.setWindowTitle(title)
+        self.btOk = QPushButton('Ok')
+        self.btCancel = QPushButton('Cancel')
+        buttonBar = QHBoxLayout()
+        #buttonBar.addWidget(self.btCancel)
+        #buttonBar.addWidget(self.btOk)
+        l = self.layout()
+        l.addWidget(self.w)
+        l.addLayout(buttonBar)
+        #self.setLayout(l)
+
+        if isinstance(classificationScheme, ClassificationScheme):
+            self.setClassificationSheme(classificationScheme)
+        s = ""
+
+    def classificationScheme(self):
+        return self.w.crosshairStyle()
+
+    def setClassificationScheme(self, classificationScheme):
+        assert isinstance(classificationScheme, ClassificationScheme)
+        self.w.setClassificationScheme(classificationScheme)
+
+
+if __name__ == '__main__':
+    import site, sys
+    #add site-packages to sys.path as done by enmapboxplugin.py
+
+    from timeseriesviewer import sandbox
+    qgsApp = sandbox.initQgisEnvironment()
+
+    pathClassImg = r'D:\Repositories\QGIS_Plugins\enmap-box\enmapbox\testdata\HymapBerlinA\HymapBerlinA_test.img'
+    pathShp = r''
+
+    w = ClassificationSchemeWidget()
+    w.setClassificationScheme(ClassificationScheme.fromRasterImage(pathClassImg))
+    w.show()
+
+    qgsApp.exec_()
+    qgsApp.exitQgis()
-- 
GitLab