class Qgeric: def __init__(self, iface): locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( os.path.dirname(__file__), 'i18n', 'qgeric_{}.qm'.format(locale)) self.translator = None if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) self.iface = iface self.sb = self.iface.mainWindow().statusBar() self.tool = None self.results = [] self.actions = [] self.menu = '&Qgeric' self.toolbar = self.iface.addToolBar('Qgeric') self.toolbar.setObjectName('Qgeric') self.loadingWindow = QProgressDialog(self.tr('Selecting...'),self.tr('Pass'),0,100) self.loadingWindow.setAutoClose(False) self.loadingWindow.close() self.themeColor = QColor(60,151,255, 128) def unload(self): for action in self.actions: self.iface.removePluginVectorMenu('&Qgeric', action) self.iface.removeToolBarIcon(action) del self.toolbar def tr(self, message): return QCoreApplication.translate('Qgeric', message) def add_action( self, icon_path, text, callback, enabled_flag=True, checkable=False, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, menu=None, parent=None): icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) action.setCheckable(checkable) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if menu is not None: action.setMenu(menu) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToVectorMenu( self.menu, action) self.actions.append(action) return action def initGui(self): icon_path = ':/plugins/qgeric/resources/icon_AT.png' self.add_action( icon_path, text=self.tr('Display selection\'s results'), callback=self.showAttributesTable, parent=self.iface.mainWindow() ) self.toolbar.addSeparator() icon_path = ':/plugins/qgeric/resources/icon_SelPt.png' self.add_action( icon_path, text=self.tr('Point request tool'), checkable=True, callback=self.pointSelection, parent=self.iface.mainWindow() ) icon_path = ':/plugins/qgeric/resources/icon_SelR.png' self.add_action( icon_path, text=self.tr('Rectangle request tool'), checkable=True, callback=self.rectangleSelection, parent=self.iface.mainWindow() ) icon_path = ':/plugins/qgeric/resources/icon_SelC.png' self.add_action( icon_path, text=self.tr('Circle request tool'), checkable=True, callback=self.circleSelection, parent=self.iface.mainWindow() ) icon_path = ':/plugins/qgeric/resources/icon_SelP.png' self.add_action( icon_path, text=self.tr('Polygon request tool'), checkable=True, callback=self.polygonSelection, parent=self.iface.mainWindow() ) bufferMenu = QMenu() polygonBufferAction = QAction(QIcon(':/plugins/qgeric/resources/icon_SelTP.png'), self.tr('Polygon buffer request tool on the selected layer'), bufferMenu) polygonBufferAction.triggered.connect(self.polygonBufferSelection) bufferMenu.addAction(polygonBufferAction) icon_path = ':/plugins/qgeric/resources/icon_SelT.png' self.add_action( icon_path, text=self.tr('Buffer request tool on the selected layer'), checkable=True, menu=bufferMenu, callback=self.bufferSelection, parent=self.iface.mainWindow() ) def showAttributesTable(self): tab = AttributesTable(self.iface) layers = QgsProject().instance().mapLayers().values() for layer in layers: if layer.type() == QgsMapLayer.VectorLayer and QgsProject.instance().layerTreeRoot().findLayer(layer.id()).isVisible(): fields_name = [field.name() for field in layer.fields()] fields_type = [field.type() for field in layer.fields()] cells = layer.selectedFeatures() if len(cells) != 0: tab.addLayer(layer, fields_name, fields_type, cells) tab.loadingWindow.close() tab.show() tab.activateWindow(); tab.showNormal(); self.results.append(tab) def closeAttributesTable(self, tab): self.results.remove(tab) def pointSelection(self): if self.tool: self.tool.reset() self.request = 'intersects' self.tool = selectPoint(self.iface, self.themeColor) self.tool.setAction(self.actions[1]) self.tool.selectionDone.connect(self.returnedBounds) self.iface.mapCanvas().setMapTool(self.tool) self.sb.showMessage(self.tr('Left click to place a point.')) def rectangleSelection(self): if self.tool: self.tool.reset() self.request = 'intersects' self.tool = selectRect(self.iface, self.themeColor, 1) self.tool.setAction(self.actions[2]) self.tool.selectionDone.connect(self.returnedBounds) self.iface.mapCanvas().setMapTool(self.tool) self.sb.showMessage(self.tr('Maintain the left click to draw a rectangle.')) def circleSelection(self): if self.tool: self.tool.reset() self.request = 'intersects' self.tool = selectCircle(self.iface, self.themeColor, 1, 40) # last parameter = number of vertices self.tool.setAction(self.actions[3]) self.tool.selectionDone.connect(self.returnedBounds) self.iface.mapCanvas().setMapTool(self.tool) self.sb.showMessage(self.tr('Maintain the left click to draw a circle. Simple Left click to give a perimeter.')) def polygonSelection(self): if self.tool: self.tool.reset() self.request = 'intersects' self.tool = selectPolygon(self.iface, self.themeColor, 1) self.tool.setAction(self.actions[4]) self.tool.selectionDone.connect(self.returnedBounds) self.iface.mapCanvas().setMapTool(self.tool) self.sb.showMessage(self.tr('Left click to place points. Right click to confirm.')) def bufferSelection(self): if self.tool: self.tool.reset() self.request = 'buffer' self.tool = selectPoint(self.iface, self.themeColor) self.actions[5].setIcon(QIcon(':/plugins/qgeric/resources/icon_SelT.png')) self.actions[5].setText(self.tr('Buffer request tool on the selected layer')) self.actions[5].triggered.disconnect() self.actions[5].triggered.connect(self.bufferSelection) self.actions[5].menu().actions()[0].setIcon(QIcon(':/plugins/qgeric/resources/icon_SelTP.png')) self.actions[5].menu().actions()[0].setText(self.tr('Polygon buffer request tool on the selected layer')) self.actions[5].menu().actions()[0].triggered.disconnect() self.actions[5].menu().actions()[0].triggered.connect(self.polygonBufferSelection) self.tool.setAction(self.actions[5]) self.tool.selectionDone.connect(self.returnedBounds) self.iface.mapCanvas().setMapTool(self.tool) self.sb.showMessage(self.tr('Select a vector layer in the Layer Tree, then left click on an attribute of this layer on the map.')) def polygonBufferSelection(self): if self.tool: self.tool.reset() self.request = 'buffer' self.tool = selectPolygon(self.iface, self.themeColor, 1) self.actions[5].setIcon(QIcon(':/plugins/qgeric/resources/icon_SelTP.png')) self.actions[5].setText(self.tr('Polygon buffer request tool on the selected layer')) self.actions[5].triggered.disconnect() self.actions[5].triggered.connect(self.polygonBufferSelection) self.actions[5].menu().actions()[0].setIcon(QIcon(':/plugins/qgeric/resources/icon_SelT.png')) self.actions[5].menu().actions()[0].setText(self.tr('Buffer request tool on the selected layer')) self.actions[5].menu().actions()[0].triggered.disconnect() self.actions[5].menu().actions()[0].triggered.connect(self.bufferSelection) self.tool.setAction(self.actions[5]) self.tool.selectionDone.connect(self.returnedBounds) self.iface.mapCanvas().setMapTool(self.tool) self.sb.showMessage(self.tr('Left click to place points. Right click to confirm.')) def geomTransform(self, geom, crs_orig, crs_dest): g = QgsGeometry(geom) crsTransform = QgsCoordinateTransform(crs_orig, crs_dest, QgsProject().instance()) g.transform(crsTransform) return g def returnedBounds(self): rb = self.tool.rb warning = True ok = True active = False errBuffer_noAtt = False errBuffer_Vertices = False buffer_geom = None buffer_geom_crs = None # we check if there's at least one visible layer for layer in QgsProject().instance().mapLayers().values(): if QgsProject.instance().layerTreeRoot().findLayer(layer.id()).isVisible(): warning = False active = True break # buffer creation on the current layer if self.request == 'buffer': layer = self.iface.layerTreeView().currentLayer() if layer is not None and layer.type() == QgsMapLayer.VectorLayer and QgsProject.instance().layerTreeRoot().findLayer(layer.id()).isVisible(): # rubberband reprojection g = self.geomTransform(rb.asGeometry(), self.iface.mapCanvas().mapSettings().destinationCrs(), layer.crs()) features = layer.getFeatures(QgsFeatureRequest(g.boundingBox())) rbGeom = [] for feature in features: geom = feature.geometry() if g.intersects(geom): rbGeom.append(QgsGeometry(feature.geometry())) if len(rbGeom) > 0: union_geoms = rbGeom[0] for geometry in rbGeom: if union_geoms.combine(geometry) is not None: union_geoms = union_geoms.combine(geometry) rb.setToGeometry(union_geoms, layer) perim, ok = QInputDialog.getDouble(self.iface.mainWindow(), self.tr('Perimeter'), self.tr('Give a perimeter in m:')+'\n'+self.tr('(works only with metric crs)'), min=0) buffer_geom_crs = layer.crs() buffer_geom = union_geoms.buffer(perim, 40) rb.setToGeometry(buffer_geom, QgsVectorLayer("Polygon?crs="+layer.crs().authid(),"","memory")) if buffer_geom.length == 0 : warning = True errBuffer_Vertices = True else: warning = True errBuffer_noAtt = True else: warning = True if len(QgsProject().instance().mapLayers().values()) > 0 and warning == False and ok: self.loadingWindow.show() self.loadingWindow.activateWindow(); self.loadingWindow.showNormal(); for layer in QgsProject().instance().mapLayers().values(): if layer.type() == QgsMapLayer.VectorLayer and QgsProject.instance().layerTreeRoot().findLayer(layer.id()).isVisible(): if self.request == 'buffer' and self.iface.layerTreeView().currentLayer() == layer: layer.selectByIds([]) continue self.loadingWindow.reset() self.loadingWindow.setWindowTitle(self.tr('Selecting...')) self.loadingWindow.setLabelText(layer.name()) # rubberband reprojection if self.request == 'buffer': if buffer_geom_crs.authid() != layer.crs().authid(): g = self.geomTransform(buffer_geom, buffer_geom_crs, layer.crs()) else: g = self.geomTransform(buffer_geom, buffer_geom_crs, layer.crs()) else: g = self.geomTransform(rb.asGeometry(), self.iface.mapCanvas().mapSettings().destinationCrs(), layer.crs()) feat_id = [] features = layer.getFeatures(QgsFeatureRequest(g.boundingBox())) count = layer.getFeatures(QgsFeatureRequest(g.boundingBox())) nbfeatures = 0 for feature in count: nbfeatures+=1 # Select attributes intersecting with the rubberband index = 0 for feature in features: geom = feature.geometry() try: if g.intersects(geom): feat_id.append(feature.id()) except: # There's an error but it intersects print('error with '+layer.name()+' on '+str(feature.id())) feat_id.append(feature.id()) index += 1 self.loadingWindow.setValue(int((float(index)/nbfeatures)*100)) if self.loadingWindow.wasCanceled(): self.loadingWindow.reset() break QApplication.processEvents() layer.selectByIds(feat_id) self.loadingWindow.close() self.showAttributesTable() else: # Display a warning in the message bar depending of the error if active == False: self.iface.messageBar().pushWarning(self.tr('Warning'), self.tr('There is no active layer !')) elif ok == False: pass elif errBuffer_noAtt: self.iface.messageBar().pushWarning(self.tr('Warning'), self.tr('You didn\'t click on a layer\'s attribute !')) elif errBuffer_Vertices: self.iface.messageBar().pushWarning(self.tr('Warning'), self.tr('You must give a non-null value for a point\'s or line\'s perimeter !')) else: self.iface.messageBar().pushWarning(self.tr('Warning'), self.tr('There is no selected layer, or it is not vector nor visible !'))
class AttributesTable(QWidget): def __init__(self, iface): QWidget.__init__(self) self.setWindowTitle(self.tr('Search results')) self.resize(480,320) self.setMinimumSize(320,240) self.center() # Results export button self.btn_saveTab = QAction(QIcon(':/plugins/qgeric/resources/icon_save.png'), self.tr('Save this tab\'s results'), self) self.btn_saveTab.triggered.connect(lambda : self.saveAttributes(True)) self.btn_saveAllTabs = QAction(QIcon(':/plugins/qgeric/resources/icon_saveAll.png'), self.tr('Save all results'), self) self.btn_saveAllTabs.triggered.connect(lambda : self.saveAttributes(False)) self.btn_export = QAction(QIcon(':/plugins/qgeric/resources/icon_export.png'), self.tr('Export the selection as a memory layer'), self) self.btn_export.triggered.connect(self.exportLayer) self.btn_zoom = QAction(QIcon(':/plugins/qgeric/resources/icon_Zoom.png'), self.tr('Zoom to selected attributes'), self) self.btn_zoom.triggered.connect(self.zoomToFeature) self.btn_selectGeom = QAction(QIcon(':/plugins/qgeric/resources/icon_HlG.png'), self.tr('Highlight feature\'s geometry'), self) self.btn_selectGeom.triggered.connect(self.selectGeomChanged) self.btn_rename = QAction(QIcon(':/plugins/qgeric/resources/icon_Settings.png'), self.tr('Settings'), self) self.btn_rename.triggered.connect(self.renameWindow) self.tabWidget = QTabWidget() # Tab container self.tabWidget.setTabsClosable(True) self.tabWidget.currentChanged.connect(self.highlight_features) self.tabWidget.tabCloseRequested.connect(self.closeTab) self.loadingWindow = QProgressDialog() self.loadingWindow.setWindowTitle(self.tr('Loading...')) self.loadingWindow.setRange(0,100) self.loadingWindow.setAutoClose(False) self.loadingWindow.setCancelButton(None) self.canvas = iface.mapCanvas() self.canvas.extentsChanged.connect(self.highlight_features) self.highlight = [] self.highlight_rows = [] toolbar = QToolBar() toolbar.addAction(self.btn_saveTab) toolbar.addAction(self.btn_saveAllTabs) toolbar.addAction(self.btn_export) toolbar.addSeparator() toolbar.addAction(self.btn_zoom) toolbar.addSeparator() toolbar.addAction(self.btn_selectGeom) toolbar.addAction(self.btn_rename) vbox = QVBoxLayout() vbox.setContentsMargins(0,0,0,0) vbox.addWidget(toolbar) vbox.addWidget(self.tabWidget) self.setLayout(vbox) self.mb = iface.messageBar() self.selectGeom = False # False for point, True for geometry def renameWindow(self): title, ok = QInputDialog.getText(self, self.tr('Rename window'), self.tr('Enter a new title:')) if ok: self.setWindowTitle(title) def closeTab(self, index): self.tabWidget.widget(index).deleteLater() self.tabWidget.removeTab(index) def selectGeomChanged(self): if self.selectGeom: self.selectGeom = False self.btn_selectGeom.setText(self.tr('Highlight feature\'s geometry')) self.btn_selectGeom.setIcon(QIcon(':/plugins/qgeric/resources/icon_HlG.png')) else: self.selectGeom = True self.btn_selectGeom.setText(self.tr('Highlight feature\'s centroid')) self.btn_selectGeom.setIcon(QIcon(':/plugins/qgeric/resources/icon_HlC.png')) self.highlight_features() def exportLayer(self): if self.tabWidget.count() != 0: index = self.tabWidget.currentIndex() table = self.tabWidget.widget(index).findChildren(QTableWidget)[0] items = table.selectedItems() if len(items) > 0: type = '' if items[0].feature.geometry().type() == QgsWkbTypes.PointGeometry: type = 'Point' elif items[0].feature.geometry().type() == QgsWkbTypes.LineGeometry: type = 'LineString' else: type = 'Polygon' features = [] for item in items: if item.feature not in features: features.append(item.feature) name = '' ok = True while not name.strip() and ok == True: name, ok = QInputDialog.getText(self, self.tr('Layer name'), self.tr('Give a name to the layer:')) if ok: layer = QgsVectorLayer(type+"?crs="+table.crs.authid(),name,"memory") layer.startEditing() layer.dataProvider().addAttributes(features[0].fields().toList()) layer.dataProvider().addFeatures(features) layer.commitChanges() QgsProject.instance().addMapLayer(layer) else: self.mb.pushWarning(self.tr('Warning'), self.tr('There is no selected feature !')) def highlight_features(self): for item in self.highlight: self.canvas.scene().removeItem(item) del self.highlight[:] del self.highlight_rows[:] index = self.tabWidget.currentIndex() tab = self.tabWidget.widget(index) if self.tabWidget.count() != 0: table = self.tabWidget.widget(index).findChildren(QTableWidget)[0] nb = 0 area = 0 length = 0 items = table.selectedItems() for item in items: if item.row() not in self.highlight_rows: if self.selectGeom: highlight = QgsHighlight(self.canvas, item.feature.geometry(), self.tabWidget.widget(index).layer) else: highlight = QgsHighlight(self.canvas, item.feature.geometry().centroid(), self.tabWidget.widget(index).layer) highlight.setColor(QColor(255,0,0)) self.highlight.append(highlight) self.highlight_rows.append(item.row()) g = QgsGeometry(item.feature.geometry()) g.transform(QgsCoordinateTransform(tab.layer.crs(), QgsCoordinateReferenceSystem(2154), QgsProject.instance())) # geometry reprojection to get meters nb += 1 area += g.area() length += g.length() if tab.layer.geometryType()==QgsWkbTypes.PolygonGeometry: tab.sb.showMessage(self.tr('Selected features')+': '+str(nb)+' '+self.tr('Area')+': '+"%.2f"%area+' m'+u'²') elif tab.layer.geometryType()==QgsWkbTypes.LineGeometry: tab.sb.showMessage(self.tr('Selected features')+': '+str(nb)+' '+self.tr('Length')+': '+"%.2f"%length+' m') else: tab.sb.showMessage(self.tr('Selected features')+': '+str(nb)) def tr(self, message): return QCoreApplication.translate('Qgeric', message) def zoomToFeature(self): index = self.tabWidget.currentIndex() table = self.tabWidget.widget(index).findChildren(QTableWidget)[0] items = table.selectedItems() feat_id = [] for item in items: feat_id.append(item.feature.id()) if len(feat_id) >= 1: if len(feat_id) == 1: self.canvas.setExtent(items[0].feature.geometry().buffer(5, 0).boundingBox()) # in case of a single point, it will still zoom to it else: self.canvas.zoomToFeatureIds(self.tabWidget.widget(self.tabWidget.currentIndex()).layer, feat_id) self.canvas.refresh() # Add a new tab def addLayer(self, layer, headers, types, features): tab = QWidget() tab.layer = layer p1_vertical = QVBoxLayout(tab) p1_vertical.setContentsMargins(0,0,0,0) table = QTableWidget() table.itemSelectionChanged.connect(self.highlight_features) table.title = layer.name() table.crs = layer.crs() table.setColumnCount(len(headers)) if len(features) > 0: table.setRowCount(len(features)) nbrow = len(features) self.loadingWindow.show() self.loadingWindow.setLabelText(table.title) self.loadingWindow.activateWindow() self.loadingWindow.showNormal() # Table population m = 0 for feature in features: n = 0 for cell in feature.attributes(): item = QTableWidgetItem() item.setData(Qt.DisplayRole, cell) item.setFlags(item.flags() ^ Qt.ItemIsEditable) item.feature = feature table.setItem(m, n, item) n += 1 m += 1 self.loadingWindow.setValue(int((float(m)/nbrow)*100)) QApplication.processEvents() else: table.setRowCount(0) table.setHorizontalHeaderLabels(headers) table.horizontalHeader().setSectionsMovable(True) table.types = types table.filter_op = [] table.filters = [] for i in range(0, len(headers)): table.filters.append('') table.filter_op.append(0) header = table.horizontalHeader() header.setContextMenuPolicy(Qt.CustomContextMenu) header.customContextMenuRequested.connect(partial(self.filterMenu, table)) table.setSortingEnabled(True) p1_vertical.addWidget(table) # Status bar to display informations (ie: area) tab.sb = QStatusBar() p1_vertical.addWidget(tab.sb) title = table.title # We reduce the title's length to 20 characters if len(title)>20: title = title[:20]+'...' # We add the number of elements to the tab's title. title += ' ('+str(len(features))+')' self.tabWidget.addTab(tab, title) # Add the tab to the conatiner self.tabWidget.setTabToolTip(self.tabWidget.indexOf(tab), table.title) # Display a tooltip with the layer's full name def filterMenu(self, table, pos): index = table.columnAt(pos.x()) menu = QMenu() filter_operation = QComboBox() if table.types[index] in [10]: filter_operation.addItems([self.tr('Contains'),self.tr('Equals')]) else: filter_operation.addItems(['=','>','<']) filter_operation.setCurrentIndex(table.filter_op[index]) action_filter_operation = QWidgetAction(self) action_filter_operation.setDefaultWidget(filter_operation) if table.types[index] in [14]: if not isinstance(table.filters[index], QDate): filter_value = QDateEdit() else: filter_value = QDateEdit(table.filters[index]) elif table.types[index] in [15]: if not isinstance(table.filters[index], QTime): filter_value = QTimeEdit() else: filter_value = QTimeEdit(table.filters[index]) elif table.types[index] in [16]: if not isinstance(table.filters[index], QDateTime): filter_value = QDateTimeEdit() else: filter_value = QDateTimeEdit(table.filters[index]) else: filter_value = QLineEdit(table.filters[index]) action_filter_value = QWidgetAction(self) action_filter_value.setDefaultWidget(filter_value) menu.addAction(action_filter_operation) menu.addAction(action_filter_value) action_filter_apply = QAction(self.tr('Apply'), self) action_filter_apply.triggered.connect(partial(self.applyFilter, table, index, filter_value, filter_operation)) action_filter_cancel = QAction(self.tr('Cancel'), self) action_filter_cancel.triggered.connect(partial(self.applyFilter, table, index, None, filter_operation)) menu.addAction(action_filter_apply) menu.addAction(action_filter_cancel) menu.exec_(QtGui.QCursor.pos()) def applyFilter(self, table, index, filter_value, filter_operation): if filter_value == None: table.filters[index] = None else: if isinstance(filter_value, QDateEdit): table.filters[index] = filter_value.date() elif isinstance(filter_value, QTimeEdit): table.filters[index] = filter_value.time() elif isinstance(filter_value, QDateTimeEdit): table.filters[index] = filter_value.dateTime() else: table.filters[index] = filter_value.text() table.filter_op[index] = filter_operation.currentIndex() nb_elts = 0 for i in range(0, table.rowCount()): table.setRowHidden(i, False) nb_elts += 1 hidden_rows = [] for nb_col in range(0, table.columnCount()): filtered = False header = table.horizontalHeaderItem(nb_col).text() valid = False if table.filters[nb_col] is not None: if type(table.filters[nb_col]) in [QDate, QTime, QDateTime]: valid = True else: if table.filters[nb_col].strip(): valid = True if valid: filtered = True items = None if table.types[nb_col] in [10]:# If it's a string filter_type = None if table.filter_op[nb_col] == 0: # Contain filter_type = Qt.MatchContains if table.filter_op[nb_col] == 1: # Equal filter_type = Qt.MatchFixedString items = table.findItems(table.filters[nb_col], filter_type) elif table.types[nb_col] in [14, 15, 16]: # If it's a date/time items = [] for nb_row in range(0, table.rowCount()): item = table.item(nb_row, nb_col) if table.filter_op[nb_col] == 0: # = if item.data(QTableWidgetItem.Type) == table.filters[nb_col]: items.append(item) if table.filter_op[nb_col] == 1: # > if item.data(QTableWidgetItem.Type) > table.filters[nb_col]: items.append(item) if table.filter_op[nb_col] == 2: # < if item.data(QTableWidgetItem.Type) < table.filters[nb_col]: items.append(item) else: # If it's a number items = [] for nb_row in range(0, table.rowCount()): item = table.item(nb_row, nb_col) if item.text().strip(): if table.filter_op[nb_col] == 0: # = if float(item.text()) == float(table.filters[nb_col]): items.append(item) if table.filter_op[nb_col] == 1: # > if float(item.text()) > float(table.filters[nb_col]): items.append(item) if table.filter_op[nb_col] == 2: # < if float(item.text()) < float(table.filters[nb_col]): items.append(item) rows = [] for item in items: if item.column() == nb_col: rows.append(item.row()) for i in range(0, table.rowCount()): if i not in rows: if i not in hidden_rows: nb_elts -= 1 table.setRowHidden(i, True) hidden_rows.append(i) if filtered: if header[len(header)-1] != '*': table.setHorizontalHeaderItem(nb_col, QTableWidgetItem(header+'*')) else: if header[len(header)-1] == '*': header = header[:-1] table.setHorizontalHeaderItem(nb_col, QTableWidgetItem(header)) title = self.tabWidget.tabText(self.tabWidget.currentIndex()) for i in reversed(range(len(title))): if title[i] == ' ': break title = title[:-1] title += '('+str(nb_elts)+')' self.tabWidget.setTabText(self.tabWidget.currentIndex(), title) # Save tables in OpenDocument format # Use odswriter library def saveAttributes(self, active): file = QFileDialog.getSaveFileName(self, self.tr('Save in...'),'', self.tr('OpenDocument Spreadsheet (*.ods)')) if file[0]: try: with ods.writer(open(file[0],"wb")) as odsfile: tabs = None if active: tabs = self.tabWidget.currentWidget().findChildren(QTableWidget) else: tabs = self.tabWidget.findChildren(QTableWidget) for table in reversed(tabs): sheet = odsfile.new_sheet(table.title[:20]+'...') # For each tab in the container, a new sheet is created sheet.writerow([table.title]) # As the tab's title's lenght is limited, the full name of the layer is written in the first row nb_row = table.rowCount() nb_col = table.columnCount() # Fetching and writing of the table's header header = [] for i in range(0,nb_col): header.append(table.horizontalHeaderItem(i).text()) sheet.writerow(header) # Fetching and writing of the table's items for i in range(0,nb_row): row = [] for j in range(0,nb_col): row.append(table.item(i,j).text()) if not table.isRowHidden(i): sheet.writerow(row) return True except IOError: QMessageBox.critical(self, self.tr('Error'), self.tr('The file can\'t be written.')+'\n'+self.tr('Maybe you don\'t have the rights or are trying to overwrite an opened file.')) return False def center(self): screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) def clear(self): self.tabWidget.clear() for table in self.tabWidget.findChildren(QTableWidget): table.setParent(None) def closeEvent(self, e): result = QMessageBox.question(self, self.tr("Saving ?"), self.tr("Would you like to save results before exit ?"), buttons = QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if result == QMessageBox.Yes: if self.saveAttributes(False): self.clear() e.accept() else: e.ignore() elif result == QMessageBox.No: self.clear() e.accept() else: e.ignore()