From d824e2c699d7c8f033f2b609e8d07d31a1a1d59c Mon Sep 17 00:00:00 2001 From: "benjamin.jakimow" <benjamin.jakimow@geo.hu-berlin.de> Date: Thu, 24 May 2018 19:55:47 +0200 Subject: [PATCH] refactoring Speclib MIMEDATA Handling added ClipboardIO(AbstractSpectralLibraryIO) to write/read Speclibs from Clipboard --- test/test_spectrallibraries.py | 77 ++++- timeseriesviewer/spectrallibraries.py | 435 ++++++++++++++++++-------- 2 files changed, 356 insertions(+), 156 deletions(-) diff --git a/test/test_spectrallibraries.py b/test/test_spectrallibraries.py index 9863e04e..0262d1eb 100644 --- a/test/test_spectrallibraries.py +++ b/test/test_spectrallibraries.py @@ -37,6 +37,8 @@ class TestInit(unittest.TestCase): QgsProject.instance().addMapLayers(self.layers) + + def createSpeclib(self): from example.Images import Img_2014_06_16_LE72270652014167CUB00_BOA, re_2014_06_25 @@ -59,8 +61,24 @@ class TestInit(unittest.TestCase): speclib.addProfiles([p1,p2]) speclib.addSpeclib(SpectralLibrary.readFromRasterPositions(path, pos)) + return speclib + + def test_fields(self): + + f = createQgsField('foo', 9999) + + self.assertEqual(f.name(),'foo') + self.assertEqual(f.type(), QVariant.Int) + self.assertEqual(f.typeName(), 'int') + + f = createQgsField('bar', 9999.) + self.assertEqual(f.type(), QVariant.Double) + self.assertEqual(f.typeName(), 'double') + + + def test_spectralprofile(self): canvas = QgsMapCanvas() @@ -73,7 +91,8 @@ class TestInit(unittest.TestCase): self.assertEqual(len(profiles), 2) for p in profiles: self.assertIsInstance(p, SpectralProfile) - + self.assertIsInstance(p.geometry(), QgsGeometry) + self.assertTrue(p.hasGeometry()) @@ -157,11 +176,13 @@ class TestInit(unittest.TestCase): def test_spectralLibrary(self): sp1 = SpectralProfile() + sp1.setName('Name A') sp1.setYValues([0, 4, 3, 2, 1]) sp1.setXValues([450, 500, 750, 1000, 1500]) sp2 = SpectralProfile() + sp2.setName('Name B') sp2.setYValues([3, 2, 1, 0, 1]) sp2.setXValues([450, 500, 750, 1000, 1500]) @@ -174,11 +195,20 @@ class TestInit(unittest.TestCase): sl1.addProfiles([sp1, sp2]) self.assertEqual(len(sl1),2) t = sl1[0:1] + + + self.assertIsInstance(sl1[0], SpectralProfile) self.assertEqual(sl1[0], sp1) self.assertEqual(sl1[1], sp2) self.assertNotEqual(sl1[0], sp2) + sl2 = sl1.speclibFromFeatureIDs(sl1[:][1].id()) + self.assertIsInstance(sl2, SpectralLibrary) + self.assertEqual(len(sl2), 1) + self.assertEqual(sl2[0], sl1[1]) + + dump = pickle.dumps(sl1) sl2 = pickle.loads(dump) @@ -201,20 +231,37 @@ class TestInit(unittest.TestCase): s ="" sl1 = SpectralLibrary.readFromRasterPositions(Img_2014_06_16_LE72270652014167CUB00_BOA,center1) sl2 = SpectralLibrary.readFromRasterPositions(Img_2014_06_16_LE72270652014167CUB00_BOA,center2) - sl3 = SpectralLibrary.readFromRasterPositions(Img_2014_06_16_LE72270652014167CUB00_BOA,[center1, center2]) for sl in [sl1, sl2]: self.assertIsInstance(sl, SpectralLibrary) self.assertTrue(len(sl) == 1) + self.assertIsInstance(sl[0], SpectralProfile) + self.assertTrue(sl[0].hasGeometry()) + self.assertTrue(len(sl3) == 2) + + + #sl1.plot() tempDir = tempfile.gettempdir() pathESL = tempfile.mktemp(prefix='speclib.', suffix='.esl') pathCSV = tempfile.mktemp(prefix='speclib.', suffix='.csv') + + #test clipboard IO + QApplication.clipboard().setMimeData(QMimeData()) + self.assertFalse(ClipboardIO.canRead()) + writtenFiles = ClipboardIO.write(sl1) + self.assertEqual(len(writtenFiles), 0) + self.assertTrue(ClipboardIO.canRead()) + sl1b = ClipboardIO.readFrom() + self.assertIsInstance(sl1b, SpectralLibrary) + self.assertEqual(sl1, sl1b) + + #test ENVI Spectral Library try: writtenFiles = sl1.exportProfiles(pathESL) @@ -259,7 +306,7 @@ class TestInit(unittest.TestCase): sl = SpectralLibrary() sl.startEditing() - sl.addAttribute(SpectralProfile.createQgsField(fieldName, '')) + sl.addAttribute(createQgsField(fieldName, '')) sl.commitChanges() self.assertIn(fieldName, sl.fieldNames()) @@ -284,27 +331,23 @@ class TestInit(unittest.TestCase): def test_filterModel(self): w = QFrame() speclib = self.createSpeclib() - speclib dmodel = SpectralLibraryTableModel(speclib, parent=w) fmodel = SpectralLibraryTableFilterModel(dmodel, parent=w) - import example - layer = QgsVectorLayer(example.exampleEvents) - QgsProject.instance().addMapLayer(layer) - cache = QgsVectorLayerCache(layer, 1000) - table = QgsAttributeTableModel(cache) + #https://stackoverflow.com/questions/671340/qsortfilterproxymodel-maptosource-crashes-no-info-why + #!!! use filterModel.index(row, col), NOT filterModel.createIndex(row, col)! + fmodel.sort(0, Qt.DescendingOrder) - dummyCanvas = QgsMapCanvas() - dummyCanvas.setDestinationCrs(SpectralProfile.crs) - dummyCanvas.setExtent(QgsRectangle(-180,-90,180,90)) + idx0f = fmodel.index(0,0) + idx0d = fmodel.mapToSource(idx0f) - fmodel = QgsAttributeTableFilterModel(dummyCanvas, table) - fmodel.sort(0, Qt.DescendingOrder) + self.assertNotEqual(idx0f.row(), idx0d.row()) + + namef = fmodel.data(idx0f, Qt.DisplayRole) + named = dmodel.data(idx0d, Qt.DisplayRole) + self.assertEqual(namef, named) - idx0 = fmodel.createIndex(0,0) - idx0d = fmodel.mapToSource(idx0) - s = "" def test_speclibTableView(self): diff --git a/timeseriesviewer/spectrallibraries.py b/timeseriesviewer/spectrallibraries.py index 8986c11e..6fed71ef 100644 --- a/timeseriesviewer/spectrallibraries.py +++ b/timeseriesviewer/spectrallibraries.py @@ -74,6 +74,33 @@ LUT_IDL2GDAL = {1:gdal.GDT_Byte, 6:gdal.GDT_CFloat32, 9:gdal.GDT_CFloat64} + +def createQgsField(name : str, exampleValue, comment:str=None): + if isinstance(exampleValue, str): + return QgsField(name, QVariant.String, 'varchar', comment=None) + elif isinstance(exampleValue, int): + return QgsField(name, QVariant.Int, 'int', comment=None) + elif isinstance(exampleValue, float): + return QgsField(name, QVariant.Double, 'double', comment=None) + elif isinstance(exampleValue, np.ndarray): + return QgsField(name, QVariant.String, 'varchar', comment=None) + elif isinstance(exampleValue, list): + assert len(exampleValue)> 0, 'need at least one value in provided list' + v = exampleValue[0] + if isinstance(v, int): + subType = QVariant.Int + typeName = 'int' + elif isinstance(v, float): + subType = QVariant.Double + typeName = 'double' + elif isinstance(v, str): + subType = QVariant.String + typeName = 'varchar' + return QgsField(name, QVariant.List, typeName, comment=None, subType=subType) + else: + raise NotImplemented() + + def value2str(value, sep=' '): if isinstance(value, list): value = sep.join([str(v) for v in value]) @@ -104,97 +131,95 @@ class SpectralLibraryTableView(QgsAttributeTableView): def __init__(self, parent=None): super(SpectralLibraryTableView, self).__init__(parent) - def contextMenuEvent(self, event): - menu = QMenu(self) + #self.setSelectionBehavior(QAbstractItemView.SelectItems) + #self.setSelectionMode(QAbstractItemView.SingleSelection) - m = menu.addMenu('Copy...') - a = m.addAction("Cell Values") - a.triggered.connect(lambda :self.onCopy2Clipboard('CELLVALUES', separator=';')) - a = m.addAction("Spectral Values") - a.triggered.connect(lambda: self.onCopy2Clipboard('YVALUES', separator=';')) - a = m.addAction("Spectral Values + Metadata") - a.triggered.connect(lambda: self.onCopy2Clipboard('ALL', separator=';')) + self.willShowContextMenu.connect(self.onWillShowContextMenu) + #self.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) - a = m.addAction("Spectral Values (Excel)") - a.triggered.connect(lambda: self.onCopy2Clipboard('YVALUES', separator='\t')) - a = m.addAction("Spectral Values + Metadata (Excel)") - a.triggered.connect(lambda: self.onCopy2Clipboard('ALL', separator='\t')) + self.mSelectionManager = None - a = menu.addAction('Save to file') - a.triggered.connect(self.onSaveToFile) + def setModel(self, filterModel): - a = menu.addAction('Set Style') - a.triggered.connect(self.onSetStyle) + super(SpectralLibraryTableView, self).setModel(filterModel) - m.addSeparator() - a = menu.addAction('Check') - a.triggered.connect(lambda : self.setCheckState(Qt.Checked)) - a = menu.addAction('Uncheck') - a.triggered.connect(lambda: self.setCheckState(Qt.Unchecked)) + self.mSelectionManager = SpectralLibraryFeatureSelectionManager(self.model().layer()) + self.setFeatureSelectionManager(self.mSelectionManager) + + #def contextMenuEvent(self, event): + def onWillShowContextMenu(self, menu, index): + assert isinstance(menu, QMenu) + assert isinstance(index, QModelIndex) + + featureIDs = self.mSelectionManager.selectedFeatureIds() + + if not isinstance(featureIDs, list): + s = "" + + if len(featureIDs) > 0: + 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...') + a.triggered.connect(lambda b, ids=featureIDs : self.onSaveToFile(ids)) menu.addSeparator() + a = menu.addAction('Style...') + a.triggered.connect(lambda b, ids=featureIDs : self.onSetStyle(ids)) + a = menu.addAction('Show') + a.triggered.connect(lambda : self.setCheckState(Qt.Checked)) + a = menu.addAction('Hide') + a.triggered.connect(lambda: self.setCheckState(Qt.Unchecked)) a = menu.addAction('Remove') a.triggered.connect(lambda : self.model().removeProfiles(self.selectedSpectra())) - menu.popup(QCursor.pos()) + #menu.popup(QCursor.pos()) - def onCopy2Clipboard(self, key, separator='\t'): - assert key in ['CELLVALUES', 'ALL', 'YVALUES'] - txt = None - if key == 'CELLVALUES': - lines = [] - line = [] - row = None - for idx in self.selectionModel().selectedIndexes(): - if row is None: - row = idx.row() - elif row != idx.row(): - lines.append(line) - line = [] - line.append(self.model().data(idx, role=Qt.DisplayRole)) - lines.append(line) - lines = [value2str(l, sep=separator) for l in lines] - QApplication.clipboard().setText('\n'.join(lines)) - else: - sl = SpectralLibrary(profiles=self.selectedSpectra()) - txt = None - if key == 'ALL': - lines = CSVSpectralLibraryIO.asTextLines(sl, separator=separator) - txt = '\n'.join(lines) - elif key == 'YVALUES': - lines = [] - for p in sl: - assert isinstance(p, SpectralProfile) - lines.append(separator.join([str(v) for v in p.yValues()])) - txt = '\n'.join(lines) - if txt: - QApplication.clipboard().setText(txt) - def onSaveToFile(self, *args): - sl = SpectralLibrary(profiles=self.selectedSpectra()) - sl.exportProfiles() + def spectralLibrary(self): + return self.model().layer() + def onCopy2Clipboard(self, fids, mode): + assert mode in ClipboardIO.WritingModes().modes() + speclib = self.spectralLibrary() + assert isinstance(speclib, SpectralLibrary) + speclib = speclib.speclibFromFeatureIDs(fids) + ClipboardIO.write(speclib, mode=mode) + + s = "" - def selectedSpectra(self): - rows = self.selectedRowsIndexes() - m = self.model() - return [m.idx2profile(m.createIndex(r, 0)) for r in rows] + def onSaveToFile(self, fids): + speclib = self.spectralLibrary() + assert isinstance(speclib, SpectralLibrary) + speclib.getFeatures(fids) + speclib.exportProfiles() + + + def selectedFeatureIndices(self): + """ + Returns the zero-column QModelIndex of all selected features + :return: [list-of-QModelIndex] + """ - def onSetStyle(self): + ids = self.mSelectionManager.selectedFeatureIds() fmodel = self.model() - dmodel = self.model() - styleDefault = None + indices = [fmodel.fidToIndex(id) for id in ids] + return [fmodel.index(idx.row(), 0) for idx in indices] - indices = self.selectionModel().selectedIndexes() - if len(indices) == 0: - indices.append(self.selectionModel().currentIndex()) + def onSetStyle(self, featureIDs): + fmodel = self.model() + indices = self.selectedFeatureIndices() if len(indices) > 0: - indices = [fmodel.createIndex(idx.row(), 0) for idx in indices] - styleDefault = model.data(fmodel.mapToSource(indices[0]), role=Qt.DecorationRole) + styleDefault = fmodel.data(indices[0], role=Qt.DecorationRole) if not isinstance(styleDefault, PlotStyle): styleDefault = None @@ -202,17 +227,13 @@ class SpectralLibraryTableView(QgsAttributeTableView): style = PlotStyleDialog.getPlotStyle(plotStyle=styleDefault) if isinstance(style, PlotStyle): for idx in indices: - dmodel.setData(idx, style, Qt.DecorationRole) + fmodel.setData(idx, style, Qt.DecorationRole) def setCheckState(self, checkState): - model = self.model() - - for idx in self.selectedRowsIndexes(): - model.setData(model.createIndex(idx, 0), checkState, Qt.CheckStateRole) + fmodel = self.model() - selectionModel = self.selectionModel() - assert isinstance(selectionModel, QItemSelectionModel) - selectionModel.clearSelection() + for idx in self.selectedFeatureIndices(): + fmodel.setData(idx, checkState, Qt.CheckStateRole) def dropEvent(self, event): @@ -428,18 +449,6 @@ class SpectralProfile(QgsFeature): profile.setSource('{}'.format(ds.GetFileList()[0])) return profile - @staticmethod - def createQgsField(name : str, exampleValue): - if isinstance(exampleValue, str): - return QgsField(name, QVariant.String, 'varchar') - elif isinstance(exampleValue, int): - return QgsField(name, QVariant.Int, 'int') - elif isinstance(exampleValue, float): - return QgsField(name, QVariant.Double, 'double') - elif isinstance(exampleValue, np.ndarray): - return QgsField(name, QVariant.String, 'varchar') - else: - raise NotImplemented() @staticmethod def standardFields(): @@ -454,15 +463,15 @@ class SpectralProfile(QgsFeature): comment Comment for the field subType If the field is a collection, its element's type. When all the elements don't need to have the same type, leave this to QVariant::Invalid. """ - fields.append(SpectralProfile.createQgsField('name', '')) - fields.append(SpectralProfile.createQgsField('px_x', 0)) - fields.append(SpectralProfile.createQgsField('px_y', 0)) - fields.append(SpectralProfile.createQgsField('x_unit', '')) - fields.append(SpectralProfile.createQgsField('y_unit', '')) - fields.append(SpectralProfile.createQgsField('source', '')) - fields.append(SpectralProfile.createQgsField(HIDDEN_ATTRIBUTE_PREFIX + 'xvalues', '')) - fields.append(SpectralProfile.createQgsField(HIDDEN_ATTRIBUTE_PREFIX + 'yvalues', '')) - fields.append(SpectralProfile.createQgsField(HIDDEN_ATTRIBUTE_PREFIX + 'style', '')) + fields.append(createQgsField('name', '')) + fields.append(createQgsField('px_x', 0)) + fields.append(createQgsField('px_y', 0)) + fields.append(createQgsField('x_unit', '')) + fields.append(createQgsField('y_unit', '')) + fields.append(createQgsField('source', '')) + fields.append(createQgsField(HIDDEN_ATTRIBUTE_PREFIX + 'xvalues', '')) + fields.append(createQgsField(HIDDEN_ATTRIBUTE_PREFIX + 'yvalues', '')) + fields.append(createQgsField(HIDDEN_ATTRIBUTE_PREFIX + 'style', '')) """ @@ -477,10 +486,11 @@ class SpectralProfile(QgsFeature): @staticmethod def fromSpecLibFeature(feature): - + assert isinstance(feature, QgsFeature) sp = SpectralProfile(fields=feature.fields()) sp.setId(feature.id()) sp.setAttributes(feature.attributes()) + sp.setGeometry(feature.geometry()) return sp XVALUES_FIELD = HIDDEN_ATTRIBUTE_PREFIX+'xvalues' @@ -605,9 +615,9 @@ class SpectralProfile(QgsFeature): fields = self.fields() values = self.attributes() if key.startswith('__serialized__'): - fields.append(SpectralProfile.createQgsField(key, '')) + fields.append(createQgsField(key, '')) else: - fields.append(SpectralProfile.createQgsField(key, value)) + fields.append(createQgsField(key, value)) values.append(value) self.setFields(fields) self.setAttributes(values) @@ -751,6 +761,131 @@ class AbstractSpectralLibraryIO(object): assert isinstance(speclib, SpectralLibrary) return [] +MIMEDATA_SPECLIB = 'application/hub-spectrallibrary' +MIMEDATA_XQT_WINDOWS_CSV = 'application/x-qt-windows-mime;value="Csv"' +MIMEDATA_TEXT = 'text/html' + +class ClipboardIO(AbstractSpectralLibraryIO): + """ + Reads and write SpectralLibrary from/to system clipboard. + """ + + FORMATS = [MIMEDATA_SPECLIB, MIMEDATA_XQT_WINDOWS_CSV, MIMEDATA_TEXT] + + class WritingModes(object): + + ALL = 'ALL' + ATTRIBUTES = 'ATTRIBUTES' + VALUES = 'VALUES' + + def modes(self): + return [a for a in dir(self) if not callable(getattr(self, a)) and not a.startswith("__")] + + @staticmethod + def canRead(path=None): + clipboard = QApplication.clipboard() + mimeData = clipboard.mimeData() + assert isinstance(mimeData, QMimeData) + for format in mimeData.formats(): + if format in ClipboardIO.FORMATS: + return True + return False + + @staticmethod + def readFrom(path=None): + clipboard = QApplication.clipboard() + mimeData = clipboard.mimeData() + assert isinstance(mimeData, QMimeData) + + if MIMEDATA_SPECLIB in mimeData.formats(): + b = mimeData.data(MIMEDATA_SPECLIB) + speclib = pickle.loads(b) + assert isinstance(speclib, SpectralLibrary) + return speclib + + return SpectralLibrary() + + @staticmethod + def write(speclib, path=None, mode=None, sep=None, dec=None, newline=None): + if mode is None: + mode = ClipboardIO.WritingModes.ALL + assert isinstance(speclib, SpectralLibrary) + + mimeData = QMimeData() + + import locale + lang, enc = locale.getdefaultlocale() + + if not isinstance(sep, str): + if lang.startswith('de_'): + sep = '\t' + else: + sep = ';' + if not isinstance(dec, str): + if lang.startswith('de_'): + dec = ',' + else: + sep = '.' + + if not isinstance(newline, str): + newline = '\r\n' + + + csvlines = [] + fields = speclib.fields() + + attributeIndices = [i for i, name in zip(fields.allAttributesList(), fields.names()) + if not name.startswith(HIDDEN_ATTRIBUTE_PREFIX)] + + skipGeometry = False + skipAttributes = mode == ClipboardIO.WritingModes.VALUES + skipValues = mode == ClipboardIO.WritingModes.ATTRIBUTES + for p in speclib.profiles(): + assert isinstance(p, SpectralProfile) + line = [] + + if not skipGeometry: + x = '' + y = '' + if p.hasGeometry(): + g = p.geometry().constGet() + if isinstance(g, QgsPoint): + x, y = g.x(), g.y() + else: + x = g.asWkt() + + line.extend([x, y]) + + if not skipAttributes: + line.extend([p.attributes()[i] for i in attributeIndices]) + + if not skipValues: + yValues = p.yValues() + if isinstance(yValues, list): + line.extend(yValues) + + formatedLine = [] + excluded = [QVariant(), None] + for value in line: + if value in excluded: + formatedLine.append('') + else: + if not isinstance(value, str): + value = str(value) + value = value.replace('.', dec) + formatedLine.append(value) + csvlines.append(sep.join(formatedLine)) + text = newline.join(csvlines) + + ba = QByteArray() + ba.append(text) + + mimeData.setText(text) + mimeData.setData(MIMEDATA_XQT_WINDOWS_CSV, ba) + mimeData.setData(MIMEDATA_SPECLIB, pickle.dumps(speclib)) + QApplication.clipboard().setMimeData(mimeData) + + return [] class CSVSpectralLibraryIO(AbstractSpectralLibraryIO): @@ -1223,13 +1358,16 @@ class SpectralLibrary(QgsVectorLayer): sigProfilesRemoved = pyqtSignal([list], [list, list]) sigNameChanged = pyqtSignal(str) - def __init__(self, name='SpectralLibrary'): + def __init__(self, name='SpectralLibrary', fields=None): crs = SpectralProfile.crs uri = 'Point?crs={}'.format(crs.authid()) lyrOptions = QgsVectorLayer.LayerOptions(loadDefaultStyle=False, readExtentFromXml=False) super(SpectralLibrary, self).__init__(uri, name, 'memory', lyrOptions) - defaultFields = SpectralProfile.standardFields() + if fields is not None: + defaultFields = fields + else: + defaultFields = SpectralProfile.standardFields() @@ -1300,10 +1438,25 @@ class SpectralLibrary(QgsVectorLayer): self.addFeatures(profiles) if not inEditMode: self.commitChanges() + s = "" def profiles(self): return self[:] + def speclibFromFeatureIDs(self, fids): + if not isinstance(fids, list): + fids = [fids] + for id in fids: + assert isinstance(id, int) + featureRequest = QgsFeatureRequest() + featureRequest.setFilterFids(fids) + features = list(self.getFeatures(featureRequest)) + + sp = SpectralLibrary(fields=self.fields()) + profiles = [SpectralProfile.fromSpecLibFeature(f) for f in features] + sp.addProfiles(profiles) + return sp + def groupBySpectralProperties(self): """ Groups the SpectralProfiles by: @@ -1325,7 +1478,7 @@ class SpectralLibrary(QgsVectorLayer): return CSVSpectralLibraryIO.asTextLines(self, separator=separator) def asPickleDump(self): - return pickle.dumps(self, SpectralLibrary.PICKLE_PROTOCOL) + return pickle.dumps(self) def exportProfiles(self, path=None): @@ -1549,10 +1702,10 @@ class SpectralLibraryTableModel(QgsAttributeTableModel): if not b: speclib.startEditing() - speclib.updateFeature(profile) + result = speclib.updateFeature(profile) if not b: speclib.commitChanges() - return True + return result #f = self.layer().getFeature(profile.id()) #i = f.fieldNameIndex(SpectralProfile.STYLE_FIELD) @@ -1613,7 +1766,7 @@ class SpectralLibraryTableModel(QgsAttributeTableModel): if columnName.startswith(HIDDEN_ATTRIBUTE_PREFIX): return Qt.NoItemFlags else: - flags = super(SpectralLibraryTableModel, self).flags(index) + flags = super(SpectralLibraryTableModel, self).flags(index) | Qt.ItemIsSelectable if index.column() == 0: flags = flags | Qt.ItemIsUserCheckable return flags @@ -1951,8 +2104,32 @@ class SpectralLibraryWidget(QFrame, loadUI('spectrallibrarywidget.ui')): +class SpectralLibraryFeatureSelectionManager(QgsIFeatureSelectionManager): + + + def __init__(self, layer, parent=None): + s ="" + super(SpectralLibraryFeatureSelectionManager, self).__init__(parent) + assert isinstance(layer, QgsVectorLayer) + self.mLayer = layer + + def layer(self): + return self.mLayer + + def deselect(self, ids): + self.mLayer.deselect(ids) + + def select(self, ids): + self.mLayer.select(ids) + + def selectedFeatureCount(self): + return self.mLayer.selectedFeatureCount() + def selectedFeatureIds(self): + return self.mLayer.selectedFeatureIds() + def setSelectedFeatures(self, ids): + self.mLayer.selectByIds(ids) if __name__ == "__main__": @@ -1989,9 +2166,15 @@ if __name__ == "__main__": model = SpectralLibraryTableModel(speclib=speclib, parent=w) fmodel = SpectralLibraryTableFilterModel(model) view = SpectralLibraryTableView(parent=w) - #view = QTableView() + #view = QgsAttributeTableView(parent=w) + # view = QTableView() + # from qgis.gui import QgsVectorLayerSelectionManager + # featureSelectionManager = QgsVectorLayerSelectionManager(speclib) + view.setModel(fmodel) + + # view.setFeatureSelectionManager(featureSelectionManager) config = QgsAttributeTableConfig() config.update(speclib.fields()) @@ -2004,39 +2187,13 @@ if __name__ == "__main__": fmodel.setAttributeTableConfig(config) view.setAttributeTableConfig(config) + #view.setSelectionBehavior(QAbstractItemView.SelectItems) + #view.setSelectionMode(QAbstractItemView.ExtendedSelection) + w.layout().addWidget(view) w.show() - w.resize(QSize(800,200)) - - if False: - - sl = SpectralLibrary.readFrom(r'C:\Users\geo_beja\Repositories\QGIS_Plugins\enmap-box\enmapboxtestdata\SpecLib_BerlinUrbanGradient.sli') - - cb = QComboBox() - m = UnitComboBoxItemModel() - cb.setModel(m) - - spec0 = sl[0] - - m = SpectralLibraryTableViewModel() - m.insertProfiles(spec0) - m.insertProfiles(sl) - - view = QTableView() - view.show() - view.setModel(m) - - W = SpectralLibraryWidget() - W.show() - W.addSpeclib(sl) - m.mSpecLib.addProfile(spec0) - - if False: - w =SpectralLibraryTableView() - #w = SpectralLibraryWidget() - w.mSpeclib.addProfile(spec0) - #w.addSpeclib(sl) - w.show() + w.resize(QSize(800, 200)) app.exec_() + print('Finished') -- GitLab