class DSBrowser(QWidget): """browser for datastorage databases Nodes are identified by a string, containing fields separated by '|'. - first filed is a capital letter: 'R'oot, 'P'roject, sensor'G'roup, 'S'ensor and 'C'hart - second field is the database folder - third filed is the path of the node in the database - for charts the fourth field is the chart name (third is path of sensorgroup in this case) """ def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Open...')) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Open a datastorage database')) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL('pressed()'), self.loadDatabase) self.expandButton = QToolButton(self.toolBar) self.expandButton.setText('Expand/Collapse') self.expandButton.setIcon(QIcon(QPixmap(Icons.exp_col))) self.expandButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Expand or collapse the whole tree')) self.toolBarLayout.addWidget(self.expandButton) self.connect(self.expandButton, SIGNAL('pressed()'), self.expandCollapseAll) self.searchInput = QLineEdit(self.toolBar) self.searchInput.setText(QCoreApplication.translate('DataStorageBrowser', 'Enter search text here')) self.searchInput.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Enter search text using wildcards here, press ENTER again to go to next match!')) self.toolBarLayout.addWidget(self.searchInput, 100) self.connect(self.searchInput, SIGNAL('returnPressed()'), self.searchItem) self.helpButton = QToolButton(self.toolBar) self.helpButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Help')) self.helpButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.help))) self.helpButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Show help for DataStorageBrowser')) self.toolBarLayout.addWidget(self.helpButton) self.connect(self.helpButton, SIGNAL('pressed()'), self.showHelp) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setAutoExpandDelay(500) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 60) self.splitter.setStretchFactor(1, 40) self.model = DSModel() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) self.connect(self.treeView, SIGNAL("customContextMenuRequested(QPoint)"), self.showContextMenu) self.selectedNode = None self.selectedMI = None self.searchText = '' self.searchResults = [] self.collExpand = SimuVis4.Misc.Switcher() def loadDatabase(self, dn=None): """load a database""" if not dn: dn = QFileDialog.getExistingDirectory(self, QCoreApplication.translate('DataStorageBrowser', "Select a folder containing a datastorage database"), SimuVis4.Globals.defaultFolder) if not dn.isEmpty(): dn = unicode(dn) SimuVis4.Globals.defaultFolder = dn else: return self.model.addDatabase(dn) self.treeView.expandToDepth(1) self.treeView.resizeColumnToContents(0) def showHelp(self): SimuVis4.HelpBrowser.showHelp('/plugin/DataStorageBrowser/index.html') def showItem(self, mi, pr): """show the item at model index mi""" t, n = self.model.dsNode(mi) txt = "" if t == 'R': # FIXME: no metadata? txt = rootInfo.substitute(name=n.name, title=escape(n.title), folder=n.h5dir, projects=len(n)) + formatMetaData(n) elif t == 'P': txt = projectInfo.substitute(name=n.name, path=escape(n.parent.name), title=escape(n.title), groups=len(n)) + formatMetaData(n) elif t == 'G': txt = groupInfo.substitute(name=n.name, path='/'.join(n.path.split('/')[:-1]), title=escape(n.title), sensors=len(n), charts=len(n.charts)) + formatMetaData(n) elif t == 'S': txt = sensorInfo.substitute(name=n.name, path='/'.join(n.path.split('/')[:-1]), title=escape(n.title), start=n.timegrid.start, stop=n.timegrid.stop, step=n.timegrid.step, length=n.datalen()) + formatMetaData(n) elif t == 'C': txt = chartInfo.substitute(name=n.name, path=n.sensorgroup.path) self.textBrowser.setText(txt) def searchItem(self): """execute the search and highlight the (next) result""" txt = str(self.searchInput.text()) if txt != self.searchText: self.searchText = txt tmp = self.model.findItems(txt, Qt.MatchFixedString | Qt.MatchContains | Qt.MatchWildcard | Qt.MatchRecursive) self.searchList = [i.index() for i in tmp] if self.searchList: mi = self.searchList.pop() self.treeView.setCurrentIndex(mi) self.treeView.expand(mi) self.treeView.scrollTo(mi) else: QMessageBox.information(self, QCoreApplication.translate('DataStorageBrowser', 'No (more) matches!'), QCoreApplication.translate('DataStorageBrowser', 'No (more) matches found! Change you search criteria and try again!')) self.searchText = '' def expandCollapseAll(self): if self.collExpand(): self.treeView.collapseAll() else: self.treeView.expandAll() def itemAction(self, mi): """default action (on doubleclick) for item at model index mi""" t, n = self.model.dsNode(mi) if t == 'R': pass elif t == 'P': pass elif t == 'G': pass elif t == 'S': self.showQwtPlot(n) elif t == 'C': self.showMplChart(n) def showContextMenu(self, pos): """show context menu for item at pos""" mi = self.treeView.indexAt(pos) t, n = self.model.dsNode(mi) self.selectedNode = n self.selectedMI = mi m = QMenu() if t == 'R': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Close'), self.closeDatabase) elif t == 'P': pass elif t == 'G': nCharts = len(n.charts) if nCharts > 0: txt = str(QCoreApplication.translate('DataStorageBrowser', 'Show all Charts (%d)')) % nCharts m.addAction(txt, self.showAllCharts) m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Add Chart'), self.newChart) elif t == 'S': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Plot (Qwt)'), self.showQwtPlot) elif t == 'C': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Show'), self.showMplChart) m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Delete'), self.deleteItem) if t in 'RPGS': m.addSeparator() m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Edit metadata'), self.editMetadata) a = m.exec_(self.treeView.mapToGlobal(pos)) def showMplChart(self, node=None): if node is None: node = self.selectedNode showChartMplWindow(node, maximized=showChartMaximized) def showAllCharts(self, node=None): if node is None: node = self.selectedNode for chart in node.charts.values(): showChartMplWindow(chart, maximized=showChartMaximized) def showQwtPlot(self, node=None): if node is None: node = self.selectedNode showQwtPlotWindow(node, maximized=showChartMaximized) def editMetadata(self, node=None): if node is None: node = self.selectedNode editMetadata(node) def closeDatabase(self, mi=None): if mi is None: mi = self.selectedMI self.model.closeDatabase(mi) def newChart(self, mi=None): """add a chart to sensorgroup at mi using the wizard""" if mi is None: mi = self.selectedMI showNewChartWizard(self.model, mi) def deleteItem(self, mi=None): """delete the item at mi""" if mi is None: mi = self.selectedMI self.model.deleteItem(mi)
class DSBrowser(QWidget): """browser for datastorage databases Nodes are identified by a string, containing fields separated by '|'. - first filed is a capital letter: 'R'oot, 'P'roject, sensor'G'roup, 'S'ensor and 'C'hart - second field is the database folder - third filed is the path of the node in the database - for charts the fourth field is the chart name (third is path of sensorgroup in this case) """ def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate("DataStorageBrowser", "Open...")) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate("DataStorageBrowser", "Open a datastorage database")) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL("pressed()"), self.loadDatabase) self.expandButton = QToolButton(self.toolBar) self.expandButton.setText("Expand/Collapse") self.expandButton.setIcon(QIcon(QPixmap(Icons.exp_col))) self.expandButton.setToolTip( QCoreApplication.translate("DataStorageBrowser", "Expand or collapse the whole tree") ) self.toolBarLayout.addWidget(self.expandButton) self.connect(self.expandButton, SIGNAL("pressed()"), self.expandCollapseAll) self.searchInput = MyLineEdit(self.toolBar) self.searchInput.setText(QCoreApplication.translate("DataStorageBrowser", "Enter search text here")) self.searchInput.setToolTip( QCoreApplication.translate( "DataStorageBrowser", "Enter search text using wildcards here, press ENTER again to go to next match!" ) ) self.toolBarLayout.addWidget(self.searchInput, 100) self.connect(self.searchInput, SIGNAL("returnPressed()"), self.searchItem) self.helpButton = QToolButton(self.toolBar) self.helpButton.setText(QCoreApplication.translate("DataStorageBrowser", "Help")) self.helpButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.help))) self.helpButton.setToolTip(QCoreApplication.translate("DataStorageBrowser", "Show help for DataStorageBrowser")) self.toolBarLayout.addWidget(self.helpButton) self.connect(self.helpButton, SIGNAL("pressed()"), self.showHelp) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setAutoExpandDelay(500) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 60) self.splitter.setStretchFactor(1, 40) self.model = DSModel() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) self.connect(self.treeView, SIGNAL("customContextMenuRequested(QPoint)"), self.showContextMenu) self.selectedNode = None self.selectedMI = None self.searchText = "" self.searchResults = [] self.collExpand = SimuVis4.Misc.Switcher() self.statusBar = SimuVis4.Globals.mainWin.statusBar() def loadDatabase(self, dn=None): """load a database""" if not dn: dn = QFileDialog.getExistingDirectory( self, QCoreApplication.translate("DataStorageBrowser", "Select a folder containing a datastorage database"), SimuVis4.Globals.defaultFolder, ) if not dn.isEmpty(): dn = unicode(dn) SimuVis4.Globals.defaultFolder = dn else: return self.model.addDatabase(dn) self.treeView.collapseAll() self.treeView.expandToDepth(SimuVis4.Globals.config.getint("datastoragebrowser", "expand_tree_depth")) self.treeView.resizeColumnToContents(0) def showHelp(self): SimuVis4.HelpBrowser.showHelp("/plugin/DataStorageBrowser/index.html") def showItem(self, mi, pr): """show the item at model index mi""" t, n = self.model.dsNode(mi) txt = "" if t == "R": txt = rootInfo.substitute( name=n.name, title=escape(n.title), folder=n.h5dir, projects=len(n) ) + formatMetaData(n) elif t == "P": txt = projectInfo.substitute( name=n.name, path=escape(n.parent.name), title=escape(n.title), groups=len(n) ) + formatMetaData(n) elif t == "G": txt = groupInfo.substitute( name=n.name, path="/".join(n.path.split("/")[:-1]), title=escape(n.title), sensors=len(n), charts=len(n.getCharts()), start=formatTime(n.timegrid.start), stop=formatTime(n.timegrid.stop), step=n.timegrid.step, timezone=n.timegrid.timezone, ) + formatMetaData(n) elif t == "S": txt = sensorInfo.substitute( name=n.name, path="/".join(n.path.split("/")[:-1]), title=escape(n.title), start=formatTime(n.timegrid.start), stop=formatTime(n.timegrid.stop), step=n.timegrid.step, length=n.datalen(), timezone=n.timegrid.timezone, ) + formatMetaData(n) elif t == "C": txt = chartInfo.substitute(name=n.name, path=n.sensorgroup.path) self.textBrowser.setText(txt) msg = ": ".join(str(self.model.itemFromIndex(mi).data().toString()).split("|")[1:]) self.statusBar.showMessage(msg, 5000) def searchItem(self): """execute the search and highlight the (next) result""" txt = str(self.searchInput.text()) if txt != self.searchText: self.searchText = txt tmp = self.model.findItems( txt, Qt.MatchFixedString | Qt.MatchContains | Qt.MatchWildcard | Qt.MatchRecursive ) self.searchList = [i.index() for i in tmp] if self.searchList: mi = self.searchList.pop() self.treeView.setCurrentIndex(mi) self.treeView.expand(mi) self.treeView.scrollTo(mi) else: QMessageBox.information( self, QCoreApplication.translate("DataStorageBrowser", "No (more) matches!"), QCoreApplication.translate( "DataStorageBrowser", "No (more) matches found! Change you search text and try again!" ), ) self.searchText = "" def expandCollapseAll(self): if self.collExpand(): self.treeView.collapseAll() else: self.treeView.expandAll() def itemAction(self, mi): """default action (on doubleclick) for item at model index mi""" t, n = self.model.dsNode(mi) if t == "S": if qwtPlotWindowActive(): self.addToQwtPlot(n) else: self.showQwtPlot(n) elif t == "C": self.showChart(n) def showContextMenu(self, pos): """show context menu for item at pos""" mi = self.treeView.indexAt(pos) t, n = self.model.dsNode(mi) self.selectedNode = n self.selectedMI = mi m = QMenu() if t == "R": m.addAction(QCoreApplication.translate("DataStorageBrowser", "Close"), self.closeDatabase) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Reload"), self.reloadDatabase) elif t == "P": m.addAction(QCoreApplication.translate("DataStorageBrowser", "New sensorgroup"), self.newSensorGroup) elif t == "G": nCharts = len(n.getCharts()) if nCharts > 0: txt = str(QCoreApplication.translate("DataStorageBrowser", "Show all charts (%d)")) % nCharts m.addAction(txt, self.showAllCharts) m.addAction( QCoreApplication.translate("DataStorageBrowser", "Save all charts as images"), self.saveAllChartImages, ) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add chart"), self.newChart) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add/update data"), self.importFiles) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Export data"), self.exportSensors) elif t == "S": m.addAction(QCoreApplication.translate("DataStorageBrowser", "New plot (Qwt)"), self.showQwtPlot) if qwtPlotWindowActive(): m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add to plot (Qwt)"), self.addToQwtPlot) elif t == "C": m.addAction(QCoreApplication.translate("DataStorageBrowser", "Show"), self.showChart) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Delete"), self.deleteItem) if t in "RPGS": m.addSeparator() m.addAction(QCoreApplication.translate("DataStorageBrowser", "Edit metadata"), self.editMetadata) a = m.exec_(self.treeView.mapToGlobal(pos)) def newSensorGroup(self, mi=None): if mi is None: mi = self.selectedMI newSensorGroup(self.model, mi) def showChart(self, ch=None): if ch is None: ch = self.selectedNode showChartWindow(ch, maximized=showChartMaximized) def importFiles(self, mi=None): if mi is None: mi = self.selectedMI importFiles(self.model, mi) def showAllCharts(self, sg=None): if sg is None: sg = self.selectedNode showAllChartWindows(sg, maximized=showChartMaximized) def saveAllChartImages(self, sg=None): if sg is None: sg = self.selectedNode saveAllChartImages(sg) def exportSensors(self, sg=None): if sg is None: sg = self.selectedNode exportSensors(sg) def showQwtPlot(self, se=None): if se is None: se = self.selectedNode showQwtPlotWindow(se, maximized=showChartMaximized) def addToQwtPlot(self, se=None): if se is None: se = self.selectedNode addToQwtPlotWindow(se) def editMetadata(self, node=None): if node is None: node = self.selectedNode editMetadata(node) def closeDatabase(self, mi=None): if mi is None: mi = self.selectedMI self.model.closeDatabase(mi) def reloadDatabase(self, mi=None): if mi is None: mi = self.selectedMI dbPath = self.model.dsFolder(mi) self.model.closeDatabase(mi) self.loadDatabase(dbPath) def newChart(self, mi=None): """add a chart to sensorgroup at mi using the wizard""" if mi is None: mi = self.selectedMI showNewChartWizard(self.model, mi, self) def deleteItem(self, mi=None): """delete the item at mi""" if mi is None: mi = self.selectedMI self.model.deleteItem(mi)
class DetailsTreeView(DetailsDBHandler, DetailsDockWidget): def __init__(self, iface, spatial_unit_dock): """ The method initializes the dockwidget. :param iface: QGIS user interface class :type class qgis.utils.iface :param plugin: The STDM plugin :type class :return: None """ from stdm.ui.entity_browser import _EntityDocumentViewerHandler DetailsDockWidget.__init__(self, iface, spatial_unit_dock) DetailsDBHandler.__init__(self) self.spatial_unit_dock = spatial_unit_dock self.view = QTreeView() self.view.setSelectionBehavior( QAbstractItemView.SelectRows ) #self.feature_ids = [] self.layer_table = None self.entity = None self.feature_models = {} self.party_models = {} self.STR_models = {} self.feature_STR_model = {} self.removed_feature = None self.selected_root = None self.model = QStandardItemModel() self.view.setModel(self.model) self.view.setUniformRowHeights(True) self.view.setRootIsDecorated(True) self.view.setAlternatingRowColors(True) self.view.setWordWrap(True) self.view.setHeaderHidden(True) self.view.setEditTriggers( QAbstractItemView.NoEditTriggers ) self.current_profile = current_profile() self.social_tenure = self.current_profile.social_tenure self.spatial_unit = self.social_tenure.spatial_unit self.party = self.social_tenure.party self.view.setMinimumWidth(250) self.doc_viewer_title = QApplication.translate( 'EntityBrowser', 'Document Viewer' ) self.doc_viewer = _EntityDocumentViewerHandler( self.doc_viewer_title, self.iface.mainWindow() ) def set_layer_entity(self): self.layer_table = self.get_layer_source( self.iface.activeLayer() ) if self.layer_table in spatial_tables(): self.entity = self.current_profile.entity_by_name( self.layer_table ) else: self.treeview_error('The layer is not a spatial entity layer. ') def activate_feature_details(self, button_clicked=True): """ Action for showing feature details. :return: """ # Get the active layer. active_layer = self.iface.activeLayer() # TODO fix feature_details_btn is deleted error. if active_layer is not None and \ self.spatial_unit_dock.feature_details_btn.isChecked(): # if feature detail dock is not defined or hidden, create empty dock. if self is None or self.isHidden(): # if the selected layer is not a feature layer, show not # feature layer. (implicitly included in the if statement). if not self.feature_layer(active_layer): self.spatial_unit_dock.feature_details_btn.setChecked(False) return # If the selected layer is feature layer, get data and # display treeview in a dock widget else: select_feature = QApplication.translate( "STDMQGISLoader", "Please select a feature to view their details." ) self.init_dock() self.add_tree_view() self.model.clear() self.treeview_error(select_feature) # enable the select tool self.activate_select_tool() # set entity from active layer in the child class self.set_layer_entity() # set entity for the super class DetailModel self.set_entity(self.entity) # Registery column widget self.set_formatter() #set formatter for social tenure relationship. self.set_formatter(self.social_tenure) self.set_formatter(self.party) # pull data, show treeview active_layer.selectionChanged.connect( self.show_tree ) self.steam_signals(self.entity) # if feature_detail dock is open, toggle close else: self.close_dock( self.spatial_unit_dock.feature_details_btn ) self.feature_details = None # if no active layer, show error message and uncheck the feature tool else: if button_clicked: self.active_layer_check() self.spatial_unit_dock.feature_details_btn.setChecked(False) def add_tree_view(self): """ Adds tree view to the dock widget and sets style. :return: None """ self.tree_scrollArea.setWidget(self.view) def clear_feature_models(self): self.feature_models.clear() def reset_tree_view(self, no_feature=False): #clear feature_ids list, model and highlight self.model.clear() self.clear_sel_highlight() # remove sel_highlight self.disable_buttons(no_feature) if self.removed_feature is None: self.STR_models.clear() self.feature_models.clear() else: self.removed_feature = None features = self.selected_features() # if the selected feature is over 1, # activate multi_select_highlight if not features is None: self.view.clicked.connect( self.multi_select_highlight ) # if there is at least one selected feature if len(features) > 0: self.add_tree_view() #self.feature_ids = features def disable_buttons(self, bool): self.edit_btn.setDisabled(bool) self.delete_btn.setDisabled(bool) def show_tree(self): selected_features = self.selected_features() if len(selected_features) < 1: self.reset_tree_view(True) return if not self.entity is None: self.reset_tree_view() if len(selected_features) < 1: self.disable_buttons(True) return layer_icon = QIcon(':/plugins/stdm/images/icons/layer.gif') roots = self.add_parent_tree( layer_icon, format_name(self.entity.short_name) ) if roots is None: return for id, root in roots.iteritems(): db_model = entity_id_to_model(self.entity, id) self.add_roots(db_model, root, id) def add_parent_tree(self, icon, title): roots = OrderedDict() for feature_id in self.selected_features(): root = QStandardItem(icon, title) root.setData(feature_id) self.set_bold(root) self.model.appendRow(root) roots[feature_id] = root return roots def add_roots(self, model, parent, feature_id): self.feature_models[feature_id] = model if model is None: return self.column_widget_registry(model, self.entity) for i, (col, row) in enumerate(self.formatted_record.iteritems()): child = QStandardItem('{}: {}'.format(col, row)) child.setSelectable(False) parent.appendRow([child]) # Add Social Tenure Relationship steam as a last child if i == len(self.formatted_record)-1: self.add_STR_child(parent, feature_id) self.expand_node(parent) def add_STR_steam(self, parent, STR_id): str_icon = QIcon( ':/plugins/stdm/images/icons/social_tenure.png' ) title = 'Social Tenure Relationship' str_root = QStandardItem(str_icon, title) str_root.setData(STR_id) self.set_bold(str_root) parent.appendRow([str_root]) return str_root def add_no_STR_steam(self, parent): if self.entity.name == self.spatial_unit.name: no_str_icon = QIcon( ':/plugins/stdm/images/icons/remove.png' ) title = 'No STR Defined' no_str_root = QStandardItem(no_str_icon, title) self.set_bold(no_str_root) parent.appendRow([no_str_root]) def add_STR_child(self, parent, feature_id): if len(self.feature_STR_link(feature_id)) < 1: self.add_no_STR_steam(parent) return for record in self.feature_STR_link(feature_id): self.STR_models[record.id] = record str_root = self.add_STR_steam(parent, record.id) # add STR children self.column_widget_registry(record, self.social_tenure) for i, (col, row) in enumerate( self.formatted_record.iteritems() ): STR_child = QStandardItem( '{}: {}'.format(col, row) ) STR_child.setSelectable(False) str_root.appendRow([STR_child]) if i == len(self.formatted_record)-1: self.add_party_child( str_root, record.party_id ) self.feature_STR_model[feature_id] = self.STR_models.keys() def add_party_steam(self, parent, party_id): party_icon = QIcon( ':/plugins/stdm/images/icons/table.png' ) title = format_name(self.party.short_name) party_root = QStandardItem(party_icon, title) party_root.setData(party_id) self.set_bold(party_root) parent.appendRow([party_root]) party_root.setEditable(False) return party_root def add_party_child(self, parent, party_id): db_model = entity_id_to_model(self.party, party_id) self.party_models[party_id] = db_model party_root = self.add_party_steam(parent, party_id) # add STR children self.column_widget_registry(db_model, self.party) for col, row in self.formatted_record.iteritems(): party_child = QStandardItem('{}: {}'.format(col, row)) party_child.setSelectable(False) party_root.appendRow([party_child]) def set_bold(self, standard_item): """ Make a text of Qstandaritem to bold. :param standard_item: Qstandaritem :type: Qstandaritem :return: None """ font = standard_item.font() font.setBold(True) standard_item.setFont(font) def treeview_error(self, message, icon=None): """ Displays error message in feature details treeview. :param title: the title of the treeview. :type: String :param message: The message to be displayed. :type: String :param icon: The icon of the item. :type: Resource string :return: None """ not_feature_ft_msg = QApplication.translate( 'FeatureDetails', message ) if icon== None: root = QStandardItem(not_feature_ft_msg) else: root = QStandardItem(icon, not_feature_ft_msg) self.view.setRootIsDecorated(False) self.model.appendRow(root) self.view.setRootIsDecorated(True) def expand_node(self, parent): """ Make the last tree node expand. :param parent: The parent to expand :type QStandardItem :return:None """ index = self.model.indexFromItem(parent) self.view.expand(index) def multi_select_highlight(self, index): """ Highlights a feature with rubberBald class when selecting features are more than one. :param index: Selected QTreeView item index :type Integer :return: None """ map = self.iface.mapCanvas() try: # Get the selected item text using the index selected_item = self.model.itemFromIndex(index) # Use mutli-select only when more than 1 items are selected. if self.layer.selectedFeatures() < 2: return self.selected_root = selected_item # Split the text to get the key and value. selected_item_text = selected_item.text() selected_value = selected_item.data() # If the first word is feature, expand & highlight. if selected_item_text == format_name(self.spatial_unit.short_name): self.view.expand(index) # expand the item # Clear any existing highlight self.clear_sel_highlight() # Insert highlight # Create expression to target the selected feature expression = QgsExpression( "\"id\"='" + str(selected_value) + "'" ) # Get feature iteration based on the expression ft_iteration = self.layer.getFeatures( QgsFeatureRequest(expression) ) # Retrieve geometry and attributes for feature in ft_iteration: # Fetch geometry geom = feature.geometry() self.sel_highlight = QgsHighlight(map, geom, self.layer) self.sel_highlight.setFillColor(selection_color()) self.sel_highlight.setWidth(4) self.sel_highlight.setColor(QColor(212,95,0, 255)) self.sel_highlight.show() break except AttributeError: # pass attribute error on child items such as party pass except IndexError: pass def steam_signals(self, entity): self.edit_btn.clicked.connect( lambda : self.edit_selected_steam( entity ) ) self.delete_btn.clicked.connect( self.delete_selected_item ) self.view_document_btn.clicked.connect( lambda : self.view_steam_document( entity ) ) def steam_data(self, mode): item = None # if self.view.currentIndex().text() == format_name(self.party): # return None, None # One item is selected and number of feature is also 1 if len(self.layer.selectedFeatures()) == 1 and \ len(self.view.selectedIndexes()) == 1: index = self.view.selectedIndexes()[0] item = self.model.itemFromIndex(index) result = item.data() # One item is selected on the map but not on the treeview elif len(self.layer.selectedFeatures()) == 1 and \ len(self.view.selectedIndexes()) == 0: item = self.model.item(0, 0) result = item.data() # multiple features are selected but one treeview item is selected elif len(self.layer.selectedFeatures()) > 1 and \ len(self.view.selectedIndexes()) == 1: item = self.selected_root result = self.selected_root.data() # multiple features are selected but no treeview item is selected elif len(self.layer.selectedFeatures()) > 1 and \ len(self.view.selectedIndexes()) == 0: result = 'Please, select an item to {}.'.format(mode) else: result = 'Please, select at least one feature to {}.'.format(mode) if result is None: if item is None: item = self.model.item(0, 0) result = item.data() else: result = item.parent().data() return result, item def edit_selected_steam(self, entity): id, item = self.steam_data('edit') feature_edit = True if id is None: return if isinstance(id, str): data_error = QApplication.translate('DetailsTreeView', id) QMessageBox.warning( self.iface.mainWindow(), "Edit Error", data_error ) return if item.text() == 'Social Tenure Relationship': model = self.STR_models[id] feature_edit = False ##TODO add STR wizard edit mode here. elif item.text() == format_name(self.party.short_name): feature_edit = False model = self.party_models[id] editor = EntityEditorDialog( self.party, model, self.iface.mainWindow() ) editor.exec_() else: model = self.feature_models[id] editor = EntityEditorDialog( entity, model, self.iface.mainWindow() ) editor.exec_() #root = self.find_root(entity, id) self.view.expand(item.index()) if feature_edit: self.update_edited_steam(entity, id) else: self.update_edited_steam(self.social_tenure, id) def delete_selected_item(self): str_edit = False id, item = self.steam_data('delete') if isinstance(id, str): data_error = QApplication.translate( 'DetailsTreeView', id ) QMessageBox.warning( self.iface.mainWindow(), 'Delete Error', data_error ) return if item.text() == 'Social Tenure Relationship': str_edit = True db_model = self.STR_models[id] elif item.text() == format_name(self.spatial_unit.short_name) and \ id not in self.feature_STR_model.keys(): db_model = self.feature_models[id] # if spatial unit is linked to STR, don't allow delete elif item.text() == format_name(self.spatial_unit.short_name) and \ id in self.feature_STR_model.keys(): delete_warning = QApplication.translate( 'DetailsTreeView', 'You have to first delete the social tenure \n' 'relationship to delete the {} record.'.format( item.text() ) ) QMessageBox.warning( self.iface.mainWindow(), 'Delete Error', delete_warning ) return # If it is party node, STR exists and don't allow delete. elif item.text() == format_name(self.party.short_name): delete_warning = QApplication.translate( 'DetailsTreeView', 'You have to first delete the social tenure \n' 'relationship to delete the {} record.'.format( item.text() ) ) QMessageBox.warning( self.iface.mainWindow(), 'Delete Error', delete_warning ) return else: return delete_warning = QApplication.translate( 'DetailsTreeView', 'Are you sure you want to delete ' 'the selected record(s)?\n' 'This action cannot be undone.' ) delete_question = QMessageBox.warning( self.iface.mainWindow(), "Delete Warning", delete_warning, QMessageBox.Yes | QMessageBox.No ) if delete_question == QMessageBox.Yes: db_model.delete() if str_edit: del self.STR_models[id] else: self.removed_feature = id del self.feature_models[id] self.updated_removed_steam(str_edit, item) else: return def update_edited_steam(self, entity, feature_id): # remove rows before adding the updated ones. self.layer.setSelectedFeatures( self.feature_models.keys() ) root = self.find_root(entity, feature_id) if root is None: return self.view.selectionModel().select( root.index(), self.view.selectionModel().Select ) self.expand_node(root) self.multi_select_highlight(root.index()) def find_root(self, entity, feature_id): all_roots = self.model.findItems( format_name(entity.short_name) ) root = None for item in all_roots: if item.data() == feature_id: root = item break return root def updated_removed_steam(self, STR_edit, item): if not STR_edit: if len(self.feature_models) > 1: self.refresh_layers() feature_ids = self.feature_models.keys() self.layer.setSelectedFeatures( feature_ids ) else: item.removeRows(0, 2) item.setText('No STR Definded') no_str_icon = QIcon( ':/plugins/stdm/images/icons/remove.png' ) item.setIcon(no_str_icon) def view_steam_document(self, entity): # Slot raised to show the document viewer for the selected entity id, item = self.steam_data('edit') if id is None: return if isinstance(id, str): data_error = QApplication.translate('DetailsTreeView', id) QMessageBox.warning( self.iface.mainWindow(), "Edit Error", data_error ) return if item.text() == 'Social Tenure Relationship': db_model = self.STR_models[id] else: db_model = self.feature_models[id] if not db_model is None: docs = db_model.documents # Notify there are no documents for the selected doc if len(docs) == 0: msg = QApplication.translate( 'EntityBrowser', 'There are no supporting documents ' 'for the selected record.' ) QMessageBox.warning( self, self.doc_viewer_title, msg ) else: self.doc_viewer.load(docs)