def __init__(self, parent=None): """Constructor.""" super(BDTopoImporterDialog, self).__init__(parent) # Set up the user interface from Designer through FORM_CLASS. # After self.setupUi() you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) # load db connections self.dbselect = QgsProviderConnectionComboBox('postgres', self) self.horizontalLayout_4.addWidget(self.dbselect) self.schemaselect = QgsDatabaseSchemaComboBox('postgres', self.dbselect.currentConnection(), self) self.dbselect.connectionChanged.connect(self.schemaselect.setConnectionName) self.horizontalLayout_5.addWidget(self.schemaselect) # load layer list data_path = os.path.join(os.path.dirname(__file__), 'data.json') with open(data_path, 'r') as f: json_data = json.load(f) layer_data = json_data['themes'] model = QStandardItemModel() root = model.invisibleRootItem() for theme in layer_data: item = QStandardItem(theme['title']) item.setData(theme['pathname']) root.appendRow(item) for layer in theme['layers']: layeritem = QStandardItem(layer['name']) layeritem.setCheckable(True) # layeritem.setCheckState(Qt.Checked) layeritem.setData(layer['filename']) item.appendRow(layeritem) self.treeView_layers.setModel(model) self.treeView_layers.expandAll() # extract parameter dialog self.settings_dlg = ExtractorSettingsDialog(self) # file access buttons self.pushButton_folder_select.clicked.connect(self.onFolderSelectClicked) self.pushButton_file_select.clicked.connect(self.onFileSelectClicked) # check/uncheck all buttons self.pushButton_checkall.clicked.connect(self.onCheckAllClicked) self.pushButton_uncheckall.clicked.connect(self.onUncheckAllClicked) # settings button self.toolButton_extract_parameters.clicked.connect(self.onExtractParametersClicked)
class ConfigDialog(BASE, WIDGET): def __init__(self): super(ConfigDialog, self).__init__(None) self.setupUi(self) self.groupIcon = QIcon() self.groupIcon.addPixmap( self.style().standardPixmap(QStyle.SP_DirClosedIcon), QIcon.Normal, QIcon.Off) self.groupIcon.addPixmap( self.style().standardPixmap(QStyle.SP_DirOpenIcon), QIcon.Normal, QIcon.On) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText(self.tr('Search...')) self.model = QStandardItemModel() self.tree.setModel(self.model) self.delegate = SettingDelegate() self.tree.setItemDelegateForColumn(1, self.delegate) self.searchBox.textChanged.connect(self.textChanged) self.fillTree() self.saveMenus = False self.tree.expanded.connect(self.itemExpanded) def textChanged(self): text = str(self.searchBox.text().lower()) self._filterItem(self.model.invisibleRootItem(), text) if text: self.tree.expandAll() else: self.tree.collapseAll() def _filterItem(self, item, text): if item.hasChildren(): show = False for i in range(item.rowCount()): child = item.child(i) showChild = self._filterItem(child, text) show = (showChild or show) self.tree.setRowHidden(item.row(), item.index().parent(), not show) return show elif isinstance(item, QStandardItem): hide = bool(text) and (text not in item.text().lower()) self.tree.setRowHidden(item.row(), item.index().parent(), hide) return not hide def fillTree(self): self.fillTreeUsingProviders() def fillTreeUsingProviders(self): self.items = {} self.model.clear() self.model.setHorizontalHeaderLabels( [self.tr('Setting'), self.tr('Value')]) settings = ProcessingConfig.getSettings() rootItem = self.model.invisibleRootItem() """ Filter 'General', 'Models' and 'Scripts' items """ priorityKeys = [ self.tr('General'), self.tr('Models'), self.tr('Scripts') ] for group in priorityKeys: groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [groupItem, emptyItem]) # add menu item only if it has any search matches for setting in settings[group]: if setting.hidden or setting.name.startswith("MENU_"): continue labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) """ Filter 'Providers' items """ providersItem = QStandardItem(self.tr('Providers')) icon = QgsApplication.getThemeIcon("/processingAlgorithm.svg") providersItem.setIcon(icon) providersItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [providersItem, emptyItem]) for group in list(settings.keys()): if group in priorityKeys or group == menusSettingsGroup: continue groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) for setting in settings[group]: if setting.hidden: continue labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) emptyItem = QStandardItem() emptyItem.setEditable(False) providersItem.appendRow([groupItem, emptyItem]) """ Filter 'Menus' items """ self.menusItem = QStandardItem(self.tr('Menus')) icon = QIcon(os.path.join(pluginPath, 'images', 'menu.png')) self.menusItem.setIcon(icon) self.menusItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [self.menusItem, emptyItem]) button = QPushButton(self.tr('Reset to defaults')) button.clicked.connect(self.resetMenusToDefaults) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(button) layout.addStretch() widget = QWidget() widget.setLayout(layout) self.tree.setIndexWidget(emptyItem.index(), widget) for provider in QgsApplication.processingRegistry().providers(): providerDescription = provider.name() groupItem = QStandardItem(providerDescription) icon = provider.icon() groupItem.setIcon(icon) groupItem.setEditable(False) for alg in provider.algorithms(): algItem = QStandardItem(alg.displayName()) algItem.setIcon(icon) algItem.setEditable(False) try: settingMenu = ProcessingConfig.settings["MENU_" + alg.id()] settingButton = ProcessingConfig.settings["BUTTON_" + alg.id()] settingIcon = ProcessingConfig.settings["ICON_" + alg.id()] except: continue self.items[settingMenu] = SettingItem(settingMenu) self.items[settingButton] = SettingItem(settingButton) self.items[settingIcon] = SettingItem(settingIcon) menuLabelItem = QStandardItem("Menu path") menuLabelItem.setEditable(False) buttonLabelItem = QStandardItem("Add button in toolbar") buttonLabelItem.setEditable(False) iconLabelItem = QStandardItem("Icon") iconLabelItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) algItem.insertRow(0, [menuLabelItem, self.items[settingMenu]]) algItem.insertRow(0, [buttonLabelItem, self.items[settingButton]]) algItem.insertRow(0, [iconLabelItem, self.items[settingIcon]]) groupItem.insertRow(0, [algItem, emptyItem]) emptyItem = QStandardItem() emptyItem.setEditable(False) self.menusItem.appendRow([groupItem, emptyItem]) self.tree.sortByColumn(0, Qt.AscendingOrder) self.adjustColumns() def resetMenusToDefaults(self): for provider in QgsApplication.processingRegistry().providers(): for alg in provider.algorithms(): d = defaultMenuEntries.get(alg.id(), "") setting = ProcessingConfig.settings["MENU_" + alg.id()] item = self.items[setting] item.setData(d, Qt.EditRole) self.saveMenus = True def accept(self): qsettings = QgsSettings() for setting in list(self.items.keys()): if setting.group != menusSettingsGroup or self.saveMenus: if isinstance(setting.value, bool): setting.setValue( self.items[setting].checkState() == Qt.Checked) else: try: setting.setValue(str(self.items[setting].text())) except ValueError as e: QMessageBox.warning( self, self.tr('Wrong value'), self.tr('Wrong value for parameter "{0}":\n\n{1}'). format(setting.description, str(e))) return setting.save(qsettings) QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) for p in QgsApplication.processingRegistry().providers(): p.refreshAlgorithms() QApplication.restoreOverrideCursor() settingsWatcher.settingsChanged.emit() def itemExpanded(self, idx): if idx == self.menusItem.index(): self.saveMenus = True self.adjustColumns() def adjustColumns(self): self.tree.resizeColumnToContents(0) self.tree.resizeColumnToContents(1)
class ConfigDialog(BASE, WIDGET): def __init__(self, showSearch=True): super(ConfigDialog, self).__init__(None) self.setupUi(self) self.groupIcon = QIcon() self.groupIcon.addPixmap(self.style().standardPixmap( QStyle.SP_DirClosedIcon), QIcon.Normal, QIcon.Off) self.groupIcon.addPixmap(self.style().standardPixmap( QStyle.SP_DirOpenIcon), QIcon.Normal, QIcon.On) self.model = QStandardItemModel() self.tree.setModel(self.model) self.delegate = SettingDelegate() self.tree.setItemDelegateForColumn(1, self.delegate) if showSearch: if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText(QApplication.translate('ConfigDialog', 'Search…')) self.searchBox.textChanged.connect(self.textChanged) else: self.searchBox.hide() self.fillTree() self.saveMenus = False self.tree.expanded.connect(self.itemExpanded) self.auto_adjust_columns = True def textChanged(self, text=None): if text is not None: text = str(text.lower()) else: text = str(self.searchBox.text().lower()) found = self._filterItem(self.model.invisibleRootItem(), text) self.auto_adjust_columns = False if text: self.tree.expandAll() else: self.tree.collapseAll() self.adjustColumns() self.auto_adjust_columns = True if text: return found else: self.tree.collapseAll() return False def _filterItem(self, item, text, forceShow=False): if item.hasChildren(): show = forceShow or isinstance(item, QStandardItem) and bool(text) and (text in item.text().lower()) for i in range(item.rowCount()): child = item.child(i) show = self._filterItem(child, text, forceShow) or show self.tree.setRowHidden(item.row(), item.index().parent(), not show) return show elif isinstance(item, QStandardItem): show = forceShow or bool(text) and (text in item.text().lower()) self.tree.setRowHidden(item.row(), item.index().parent(), not show) return show def fillTree(self): self.fillTreeUsingProviders() def fillTreeUsingProviders(self): self.items = {} self.model.clear() self.model.setHorizontalHeaderLabels([self.tr('Setting'), self.tr('Value')]) settings = ProcessingConfig.getSettings() rootItem = self.model.invisibleRootItem() """ Filter 'General', 'Models' and 'Scripts' items """ priorityKeys = [self.tr('General'), self.tr('Models'), self.tr('Scripts')] for group in priorityKeys: groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [groupItem, emptyItem]) if not group in settings: continue # add menu item only if it has any search matches for setting in settings[group]: if setting.hidden or setting.name.startswith("MENU_"): continue labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) """ Filter 'Providers' items """ providersItem = QStandardItem(self.tr('Providers')) icon = QgsApplication.getThemeIcon("/processingAlgorithm.svg") providersItem.setIcon(icon) providersItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [providersItem, emptyItem]) for group in list(settings.keys()): if group in priorityKeys or group == menusSettingsGroup: continue groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) for setting in settings[group]: if setting.hidden: continue labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) emptyItem = QStandardItem() emptyItem.setEditable(False) providersItem.appendRow([groupItem, emptyItem]) """ Filter 'Menus' items """ self.menusItem = QStandardItem(self.tr('Menus')) icon = QIcon(os.path.join(pluginPath, 'images', 'menu.png')) self.menusItem.setIcon(icon) self.menusItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [self.menusItem, emptyItem]) button = QPushButton(self.tr('Reset to defaults')) button.clicked.connect(self.resetMenusToDefaults) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(button) layout.addStretch() widget = QWidget() widget.setLayout(layout) self.tree.setIndexWidget(emptyItem.index(), widget) for provider in QgsApplication.processingRegistry().providers(): providerDescription = provider.name() groupItem = QStandardItem(providerDescription) icon = provider.icon() groupItem.setIcon(icon) groupItem.setEditable(False) for alg in provider.algorithms(): algItem = QStandardItem(alg.displayName()) algItem.setIcon(icon) algItem.setEditable(False) try: settingMenu = ProcessingConfig.settings["MENU_" + alg.id()] settingButton = ProcessingConfig.settings["BUTTON_" + alg.id()] settingIcon = ProcessingConfig.settings["ICON_" + alg.id()] except: continue self.items[settingMenu] = SettingItem(settingMenu) self.items[settingButton] = SettingItem(settingButton) self.items[settingIcon] = SettingItem(settingIcon) menuLabelItem = QStandardItem("Menu path") menuLabelItem.setEditable(False) buttonLabelItem = QStandardItem("Add button in toolbar") buttonLabelItem.setEditable(False) iconLabelItem = QStandardItem("Icon") iconLabelItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) algItem.insertRow(0, [menuLabelItem, self.items[settingMenu]]) algItem.insertRow(0, [buttonLabelItem, self.items[settingButton]]) algItem.insertRow(0, [iconLabelItem, self.items[settingIcon]]) groupItem.insertRow(0, [algItem, emptyItem]) emptyItem = QStandardItem() emptyItem.setEditable(False) self.menusItem.appendRow([groupItem, emptyItem]) self.tree.sortByColumn(0, Qt.AscendingOrder) self.adjustColumns() def resetMenusToDefaults(self): for provider in QgsApplication.processingRegistry().providers(): for alg in provider.algorithms(): d = defaultMenuEntries.get(alg.id(), "") setting = ProcessingConfig.settings["MENU_" + alg.id()] item = self.items[setting] item.setData(d, Qt.EditRole) self.saveMenus = True def accept(self): qsettings = QgsSettings() for setting in list(self.items.keys()): if setting.group != menusSettingsGroup or self.saveMenus: if isinstance(setting.value, bool): setting.setValue(self.items[setting].checkState() == Qt.Checked) else: try: setting.setValue(str(self.items[setting].text())) except ValueError as e: QMessageBox.warning(self, self.tr('Wrong value'), self.tr('Wrong value for parameter "{0}":\n\n{1}').format(setting.description, str(e))) return setting.save(qsettings) with OverrideCursor(Qt.WaitCursor): for p in QgsApplication.processingRegistry().providers(): p.refreshAlgorithms() settingsWatcher.settingsChanged.emit() def itemExpanded(self, idx): if idx == self.menusItem.index(): self.saveMenus = True if self.auto_adjust_columns: self.adjustColumns() def adjustColumns(self): self.tree.resizeColumnToContents(0) self.tree.resizeColumnToContents(1)
class ConfigDialog(BASE, WIDGET): def __init__(self, toolbox): super(ConfigDialog, self).__init__(None) self.setupUi(self) self.toolbox = toolbox self.groupIcon = QIcon() self.groupIcon.addPixmap(self.style().standardPixmap( QStyle.SP_DirClosedIcon), QIcon.Normal, QIcon.Off) self.groupIcon.addPixmap(self.style().standardPixmap( QStyle.SP_DirOpenIcon), QIcon.Normal, QIcon.On) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText(self.tr('Search...')) self.model = QStandardItemModel() self.tree.setModel(self.model) self.delegate = SettingDelegate() self.tree.setItemDelegateForColumn(1, self.delegate) self.searchBox.textChanged.connect(self.textChanged) self.fillTree() self.tree.expanded.connect(self.adjustColumns) def textChanged(self): text = str(self.searchBox.text().lower()) self._filterItem(self.model.invisibleRootItem(), text) if text: self.tree.expandAll() else: self.tree.collapseAll() def _filterItem(self, item, text): if item.hasChildren(): show = False for i in range(item.rowCount()): child = item.child(i) showChild = self._filterItem(child, text) show = (showChild or show) self.tree.setRowHidden(item.row(), item.index().parent(), not show) return show elif isinstance(item, QStandardItem): hide = bool(text) and (text not in item.text().lower()) self.tree.setRowHidden(item.row(), item.index().parent(), hide) return not hide def fillTree(self): self.fillTreeUsingProviders() def fillTreeUsingProviders(self): self.items = {} self.model.clear() self.model.setHorizontalHeaderLabels([self.tr('Setting'), self.tr('Value')]) settings = ProcessingConfig.getSettings() rootItem = self.model.invisibleRootItem() """ Filter 'General', 'Models' and 'Scripts' items """ priorityKeys = [self.tr('General'), self.tr('Models'), self.tr('Scripts')] for group in priorityKeys: groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [groupItem, emptyItem]) # add menu item only if it has any search matches for setting in settings[group]: if setting.hidden or setting.name.startswith("MENU_"): continue labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) """ Filter 'Providers' items """ providersItem = QStandardItem(self.tr('Providers')) icon = QIcon(os.path.join(pluginPath, 'images', 'alg.png')) providersItem.setIcon(icon) providersItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [providersItem, emptyItem]) for group in list(settings.keys()): if group in priorityKeys or group == menusSettingsGroup: continue groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) for setting in settings[group]: if setting.hidden: continue labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) emptyItem = QStandardItem() emptyItem.setEditable(False) providersItem.appendRow([groupItem, emptyItem]) """ Filter 'Menus' items """ menusItem = QStandardItem(self.tr('Menus')) icon = QIcon(os.path.join(pluginPath, 'images', 'menu.png')) menusItem.setIcon(icon) menusItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [menusItem, emptyItem]) button = QPushButton(self.tr('Reset to defaults')) button.clicked.connect(self.resetMenusToDefaults) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(button) layout.addStretch() widget = QWidget() widget.setLayout(layout) self.tree.setIndexWidget(emptyItem.index(), widget) providers = Processing.providers for provider in providers: providerDescription = provider.getDescription() groupItem = QStandardItem(providerDescription) icon = provider.getIcon() groupItem.setIcon(icon) groupItem.setEditable(False) for alg in provider.algs: algItem = QStandardItem(alg.i18n_name or alg.name) algItem.setIcon(icon) algItem.setEditable(False) try: settingMenu = ProcessingConfig.settings["MENU_" + alg.commandLineName()] settingButton = ProcessingConfig.settings["BUTTON_" + alg.commandLineName()] settingIcon = ProcessingConfig.settings["ICON_" + alg.commandLineName()] except: continue self.items[settingMenu] = SettingItem(settingMenu) self.items[settingButton] = SettingItem(settingButton) self.items[settingIcon] = SettingItem(settingIcon) menuLabelItem = QStandardItem("Menu path") menuLabelItem.setEditable(False) buttonLabelItem = QStandardItem("Add button in toolbar") buttonLabelItem.setEditable(False) iconLabelItem = QStandardItem("Icon") iconLabelItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) algItem.insertRow(0, [menuLabelItem, self.items[settingMenu]]) algItem.insertRow(0, [buttonLabelItem, self.items[settingButton]]) algItem.insertRow(0, [iconLabelItem, self.items[settingIcon]]) groupItem.insertRow(0, [algItem, emptyItem]) emptyItem = QStandardItem() emptyItem.setEditable(False) menusItem.appendRow([groupItem, emptyItem]) self.tree.sortByColumn(0, Qt.AscendingOrder) self.adjustColumns() def resetMenusToDefaults(self): providers = Processing.providers for provider in providers: for alg in provider.algs: d = defaultMenuEntries.get(alg.commandLineName(), "") setting = ProcessingConfig.settings["MENU_" + alg.commandLineName()] item = self.items[setting] item.setData(d, Qt.EditRole) def accept(self): for setting in list(self.items.keys()): if isinstance(setting.value, bool): setting.setValue(self.items[setting].checkState() == Qt.Checked) else: try: setting.setValue(str(self.items[setting].text())) except ValueError as e: QMessageBox.warning(self, self.tr('Wrong value'), self.tr('Wrong value for parameter "%s":\n\n%s' % (setting.description, str(e)))) return setting.save() Processing.updateAlgsList() settingsWatcher.settingsChanged.emit() QDialog.accept(self) def adjustColumns(self): self.tree.resizeColumnToContents(0) self.tree.resizeColumnToContents(1)
class ConfigDialog(BASE, WIDGET): def __init__(self, toolbox): super(ConfigDialog, self).__init__(None) self.setupUi(self) self.toolbox = toolbox self.groupIcon = QIcon() self.groupIcon.addPixmap( self.style().standardPixmap(QStyle.SP_DirClosedIcon), QIcon.Normal, QIcon.Off) self.groupIcon.addPixmap( self.style().standardPixmap(QStyle.SP_DirOpenIcon), QIcon.Normal, QIcon.On) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText(self.tr('Search...')) self.model = QStandardItemModel() self.tree.setModel(self.model) self.delegate = SettingDelegate() self.tree.setItemDelegateForColumn(1, self.delegate) self.searchBox.textChanged.connect(self.textChanged) self.fillTree() self.tree.expanded.connect(self.adjustColumns) def textChanged(self): text = unicode(self.searchBox.text().lower()) self._filterItem(self.model.invisibleRootItem(), text) if text: self.tree.expandAll() else: self.tree.collapseAll() def _filterItem(self, item, text): if item.hasChildren(): show = False for i in xrange(item.rowCount()): child = item.child(i) showChild = self._filterItem(child, text) show = (showChild or show) self.tree.setRowHidden(item.row(), item.index().parent(), not show) return show elif isinstance(item, QStandardItem): hide = bool(text) and (text not in item.text().lower()) self.tree.setRowHidden(item.row(), item.index().parent(), hide) return not hide def fillTree(self): self.fillTreeUsingProviders() def fillTreeUsingProviders(self): self.items = {} self.model.clear() self.model.setHorizontalHeaderLabels( [self.tr('Setting'), self.tr('Value')]) settings = ProcessingConfig.getSettings() rootItem = self.model.invisibleRootItem() """ Filter 'General', 'Models' and 'Scripts' items """ priorityKeys = [ self.tr('General'), self.tr('Models'), self.tr('Scripts') ] for group in priorityKeys: groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [groupItem, emptyItem]) # add menu item only if it has any search matches for setting in settings[group]: if setting.hidden or setting.name.startswith("MENU_"): continue labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) """ Filter 'Providers' items """ providersItem = QStandardItem(self.tr('Providers')) icon = QIcon(os.path.join(pluginPath, 'images', 'alg.png')) providersItem.setIcon(icon) providersItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [providersItem, emptyItem]) for group in settings.keys(): if group in priorityKeys or group == menusSettingsGroup: continue groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) for setting in settings[group]: if setting.hidden: continue labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) emptyItem = QStandardItem() emptyItem.setEditable(False) providersItem.appendRow([groupItem, emptyItem]) """ Filter 'Menus' items """ menusItem = QStandardItem(self.tr('Menus (requires restart)')) icon = QIcon(os.path.join(pluginPath, 'images', 'menu.png')) menusItem.setIcon(icon) menusItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [menusItem, emptyItem]) providers = Processing.providers for provider in providers: providerDescription = provider.getDescription() groupItem = QStandardItem(providerDescription) icon = provider.getIcon() groupItem.setIcon(icon) groupItem.setEditable(False) for alg in provider.algs: algItem = QStandardItem(alg.i18n_name or alg.name) algItem.setIcon(icon) algItem.setEditable(False) try: settingMenu = ProcessingConfig.settings[ "MENU_" + alg.commandLineName()] settingButton = ProcessingConfig.settings[ "BUTTON_" + alg.commandLineName()] settingIcon = ProcessingConfig.settings[ "ICON_" + alg.commandLineName()] except: continue self.items[settingMenu] = SettingItem(settingMenu) self.items[settingButton] = SettingItem(settingButton) self.items[settingIcon] = SettingItem(settingIcon) menuLabelItem = QStandardItem("Menu path") menuLabelItem.setEditable(False) buttonLabelItem = QStandardItem("Add button in toolbar") buttonLabelItem.setEditable(False) iconLabelItem = QStandardItem("Icon") iconLabelItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) algItem.insertRow(0, [menuLabelItem, self.items[settingMenu]]) algItem.insertRow(0, [buttonLabelItem, self.items[settingButton]]) algItem.insertRow(0, [iconLabelItem, self.items[settingIcon]]) groupItem.insertRow(0, [algItem, emptyItem]) emptyItem = QStandardItem() emptyItem.setEditable(False) menusItem.appendRow([groupItem, emptyItem]) self.tree.sortByColumn(0, Qt.AscendingOrder) self.adjustColumns() def accept(self): for setting in self.items.keys(): if isinstance(setting.value, bool): setting.setValue( self.items[setting].checkState() == Qt.Checked) else: try: setting.setValue(unicode(self.items[setting].text())) except ValueError as e: QMessageBox.warning( self, self.tr('Wrong value'), self.tr('Wrong value for parameter "%s":\n\n%s' % (setting.description, unicode(e)))) return setting.save() Processing.updateAlgsList() settingsWatcher.settingsChanged.emit() updateMenus() QDialog.accept(self) def adjustColumns(self): self.tree.resizeColumnToContents(0) self.tree.resizeColumnToContents(1)
class QVDistrictesBarris(QObject): __distBarrisCSV = r'Dades\DIST_BARRIS.csv' __zones = r'Dades\Zones.gpkg' def __init__(self): super().__init__() self.labels = [] self.registre = {} # Model self.model = QStandardItemModel() self.llegirZonesGPKG() #self.llegirDistrictesBarrisCSV() # View self.view = QTreeView() self.view.setContextMenuPolicy(Qt.ActionsContextMenu) self.actExpand = QAction("Expandeix/Contreu Tot", self) self.actExpand.setStatusTip("Expand") self.actExpand.triggered.connect(self.expand_all) self.view.addAction(self.actExpand) self.view.setModel(self.model) self.iniView() def expand_all(self): """Expandir o contraer todo el arbol, dependiendo de si detecta que esta extendido o contraido """ if self.view.isExpanded(self.model.index(0, 0, QModelIndex())): self.view.collapseAll() else: self.view.expandAll() def iniView(self): self.view.setHeaderHidden(True) for i in range(self.model.columnCount()): if i == 0: self.view.setColumnHidden(i, False) self.view.resizeColumnToContents(i) self.view.resizeColumnToContents(i) else: self.view.setColumnHidden(i, True) self.view.setEditTriggers(QTreeView.NoEditTriggers) self.expand_all() def llegirZonesGPKG(self): try: QvFuncions.setReadOnlyFile(self.__zones) pathDistrictes = self.__zones + '|layername=districtes' layerDistrictes = QgsVectorLayer(pathDistrictes, 'ogr') pathBarris = self.__zones + '|layername=barris' layerBarris = QgsVectorLayer(pathBarris, 'ogr') rowsDistrictes = layerDistrictes.getFeatures() llistaDistrictes = [] for rowD in rowsDistrictes: #print(rowD.attributes()) #zona = "" num_districte = rowD.attributes()[1] nom_districte = rowD.attributes()[2] num_barri = "" nom_barri = "" geometria = rowD.geometry().boundingBox() x_min = str(geometria.xMinimum()) y_min = str(geometria.yMinimum()) x_max = str(geometria.xMaximum()) y_max = str(geometria.yMaximum()) item = [ num_districte, nom_districte, num_barri, nom_barri, x_min, y_min, x_max, y_max ] llistaDistrictes.append(item) def ordenaPerNumDistricte(elem): return elem[0] llistaDistrictes.sort(key=ordenaPerNumDistricte) #print(llistaDistrictes) rowsBarris = layerBarris.getFeatures() llistaBarris = [] for rowB in rowsBarris: #print(rowB.attributes()) #zona = "" num_districte = rowB.attributes()[3] nom_districte = llistaDistrictes[int(num_districte) - 1][1] num_barri = rowB.attributes()[1] nom_barri = rowB.attributes()[2] geometria = rowB.geometry().boundingBox() x_min = str(geometria.xMinimum()) y_min = str(geometria.yMinimum()) x_max = str(geometria.xMaximum()) y_max = str(geometria.yMaximum()) item = [ num_districte, nom_districte, num_barri, nom_barri, x_min, y_min, x_max, y_max ] llistaBarris.append(item) def ordenaPerNumBarri(elem): return elem[2] llistaBarris.sort(key=ordenaPerNumBarri) #print(llistaBarris) self.labels = [ "ZONA", "DISTRICTE", "NOM_DISTRICTE", "BARRI", "NOM_BARRI", "X_MIN", "Y_MIN", "X_MAX", "Y_MAX" ] root = self.model.invisibleRootItem() self.model.setColumnCount(len(self.labels)) self.model.setHorizontalHeaderLabels(self.labels) #Afegir Barcelona com a arrel de l'arbre bcn_dades = [ "00", "Barcelona", "00", "Barcelona", "419710.0553820258", "4573818.80776309", "436533.35", "4591775.02" ] bcn = [QStandardItem("Barcelona")] for item in bcn_dades: bcn.append(QStandardItem(item)) root.appendRow(bcn) ultimaDistr = -1 itDist = 0 for b in llistaBarris: if ultimaDistr != int(b[0]): #Afegir següent districte dist = [QStandardItem(llistaDistrictes[itDist][1])] for i in range(0, len(llistaDistrictes[itDist])): dist.append(QStandardItem(llistaDistrictes[itDist][i])) bcn[0].appendRow(dist) itDist = itDist + 1 #Afegir següent Barri barri = [QStandardItem(b[3])] for item in b: barri.append(QStandardItem(item)) dist[0].appendRow(barri) ultimaDistr = int(b[0]) return True except: print("Error en construcció de l'arbre de zones") return False # def llegirDistrictesBarrisCSV(self): # try: # first = True # with open(self.__distBarrisCSV, newline='') as csvFile: # reader = csv.DictReader(csvFile, delimiter=';') # root = self.model.invisibleRootItem() # for row in reader: # if first: # Primer registro # self.labels = ['ZONA'] # for item in row: # self.labels.append(item) # self.model.setColumnCount(len(self.labels)) # self.model.setHorizontalHeaderLabels(self.labels) # first = False # if row['BARRI'] == '': # Registro de distrito # dist = [QStandardItem(row['NOM_DISTRICTE'])] # for item in row.values(): # dist.append(QStandardItem(item)) # root.appendRow(dist) # else: # Registro de barrio # barri = [QStandardItem(row['NOM_BARRI'])] # for item in row.values(): # barri.append(QStandardItem(item)) # dist[0].appendRow(barri) # return True # except: # print('QDistrictesBarris.llegirDistrictesBarrisCSV(): ', sys.exc_info()[0], sys.exc_info()[1]) # return False def llegirRegistre(self): try: click = self.view.currentIndex() #Controlarem si s'ha canviat d'índex o no if hasattr(self, 'ultimIndex') and self.ultimIndex == click: return self.registre self.ultimIndex = click self.registre = {} for i in range(self.model.columnCount()): index = click.sibling(click.row(), i) item = self.model.itemFromIndex(index) self.registre[self.labels[i]] = item.text() self.registre['RANG'] = QgsRectangle(float(self.registre['X_MIN']), \ float(self.registre['Y_MIN']), \ float(self.registre['X_MAX']), \ float(self.registre['Y_MAX'])) except: print('QDistrictesBarris.llegirRegistre(): ', sys.exc_info()[0], sys.exc_info()[1]) finally: return self.registre def llegirRang(self): return self.llegirRegistre()['RANG'] def esDistricte(self): return self.llegirRegistre()['BARRI'] == '' def esBarri(self): return not self.esDistricte() def llegirNom(self): if self.esDistricte(): distr = self.llegirRegistre()["NOM_DISTRICTE"] distr_d = distr + "_d" return distr_d else: barri = self.llegirRegistre()["NOM_BARRI"] if barri == "Barcelona": return barri else: barri_b = barri + "_b" return barri_b def llegirID(self): if self.esDistricte(): return self.llegirRegistre()['DISTRICTE'] return self.llegirRegistre()['BARRI']
class QRAVEMetaWidget(QDockWidget, Ui_QRAVEMetaWidgetBase): def __init__(self, parent=None): """Constructor.""" super(QRAVEMetaWidget, self).__init__(parent) self.setupUi(self) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.customContextMenuRequested.connect(self.open_menu) self.treeView.doubleClicked.connect(self.default_tree_action) self.settings = Settings() self.model = QStandardItemModel() self.treeView.setModel(self.model) self.meta = None self.menu = QMenu() # Initialize our classes self.hide() @pyqtSlot(str, str, dict, bool) def load(self, label: str, meta_type: str, meta: dict, show: bool = False): # re-initialize our model self.model.clear() self.meta = meta root_item = self.model.invisibleRootItem() self.model.setColumnCount(2) self.model.setHorizontalHeaderLabels(['Meta Name', 'Meta Value']) if meta_type == MetaType.PROJECT: self.treeView.setHeaderHidden(False) self.setWindowTitle('Project MetaData: {}'.format(label)) self.treeView.setEnabled(True) if meta is not None and len(meta.keys()) > 0: if 'project' in meta and len(meta['project'].keys()) > 0: proj_meta = QStandardItem('Project Meta') proj_meta_font = proj_meta.font() proj_meta_font.setBold(True) proj_meta.setFont(proj_meta_font) for k, v in meta['project'].items(): proj_meta.appendRow( [QStandardItem(k), QStandardItem(v)]) root_item.appendRow(proj_meta) if 'warehouse' in meta and len(meta['warehouse'].keys()) > 0: wh_meta = QStandardItem('Warehouse Meta') wh_meta_font = proj_meta.font() wh_meta_font.setBold(True) wh_meta.setFont(wh_meta_font) for k, v in meta['warehouse'].items(): wh_meta.appendRow([QStandardItem(k), QStandardItem(v)]) root_item.appendRow(wh_meta) elif meta_type == MetaType.FOLDER: self.setWindowTitle('Folder: {}'.format(label)) self.treeView.setHeaderHidden(True) self.treeView.setEnabled(False) self.model.setColumnCount(1) self.model.setHorizontalHeaderLabels(['Meta Name']) no_item = QStandardItem('Folders have no MetaData') no_item.setTextAlignment(Qt.AlignCenter) no_f = no_item.font() no_f.setItalic(True) no_item.setFont(no_f) root_item.appendRow(no_item) elif meta_type == MetaType.LAYER: self.setWindowTitle('Layer MetaData: {}'.format(label)) self.treeView.setEnabled(True) self.treeView.setHeaderHidden(False) if meta is not None and len(meta.keys()) > 0: for k, v in meta.items(): root_item.appendRow([QStandardItem(k), QStandardItem(v)]) else: self.treeView.setHeaderHidden(True) self.treeView.setEnabled(False) self.model.setColumnCount(1) self.model.setHorizontalHeaderLabels(['Meta Name']) no_item = QStandardItem('This layer has no MetaData') no_item.setTextAlignment(Qt.AlignCenter) no_f = no_item.font() no_f.setItalic(True) no_item.setFont(no_f) root_item.appendRow(no_item) elif meta_type == MetaType.NONE: self.treeView.setHeaderHidden(True) self.treeView.setEnabled(False) self.model.setColumnCount(1) self.setWindowTitle('Riverscapes MetaData: {}'.format(label)) no_item = QStandardItem('This item cannot have metadata') no_item.setTextAlignment(Qt.AlignCenter) no_f = no_item.font() no_f.setItalic(True) no_item.setFont(no_f) root_item.appendRow(no_item) return # self.tree.header().setDefaultSectionSize(180) # self._populateTree(self.tree, ) # Finally expand all levels self.treeView.expandAll() if show is True: self.show() def closeEvent(self, event): self.hide() def default_tree_action(self, index): item = self.model.itemFromIndex(index) data = item.data(Qt.UserRole) def open_menu(self, position): indexes = self.treeView.selectedIndexes() if len(indexes) < 1 or self.meta is None or len(self.meta.keys()) == 0: return # No multiselect so there is only ever one item item_name = self.model.itemFromIndex(indexes[0]) item_val = self.model.itemFromIndex( indexes[1]) if len(indexes) > 0 else None self.menu.clear() if item_val is not None: row_text = {item_name.text(): item_val.text()} self.menu.addAction('Copy Name to Clipboard', lambda: self.copy(item_name.text())) self.menu.addAction('Copy Value to Clipboard', lambda: self.copy(item_val.text())) self.menu.addAction( 'Copy Row to Clipboard (json)', lambda: self.copy( json.dumps(row_text, indent=4, sort_keys=True))) self.menu.addAction( 'Copy All to Clipboard (json)', lambda: self.copy(json.dumps(self.meta, indent=4, sort_keys=True))) self.menu.exec_(self.treeView.viewport().mapToGlobal(position)) def copy(self, data: str): cb = QGuiApplication.clipboard() cb.clear(mode=cb.Clipboard) cb.setText(data, mode=cb.Clipboard)
class QRiSDockWidget(QtWidgets.QDockWidget, FORM_CLASS): closingPlugin = pyqtSignal() def __init__(self, parent=None): """Constructor.""" super(QRiSDockWidget, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://doc.qt.io/qt-5/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.settings = Settings() self.qris_project = None self.menu = ContextMenu() self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.customContextMenuRequested.connect(self.open_menu) # self.treeView.doubleClicked.connect(self.default_tree_action) # self.treeView.clicked.connect(self.item_change) # self.treeView.expanded.connect(self.expand_tree_item) self.model = QStandardItemModel() self.treeView.setModel(self.model) # Take this out of init so that nodes can be added as new data is added and imported; def build_tree_view(self, qris_project, new_item=None): """Builds items in the tree view based on dictionary values that are part of the project""" self.qris_project = qris_project self.model.clear() self.tree_state = {} rootNode = self.model.invisibleRootItem() # set the project root project_node = QStandardItem(self.qris_project.project_name) project_node.setIcon(QIcon(':/plugins/qris_toolbar/icon.png')) project_node.setData('project_root', item_code['item_type']) rootNode.appendRow(project_node) self.treeView.setExpanded(project_node.index(), True) # Add project extent layers to tree extent_folder = QStandardItem("Project Extents") extent_folder.setIcon(QIcon(':/plugins/qris_toolbar/test_folder.png')) extent_folder.setData('extent_folder', item_code['item_type']) project_node.appendRow(extent_folder) for extent in self.qris_project.project_extents.values(): extent_node = QStandardItem(extent.display_name) extent_node.setIcon( QIcon(':/plugins/qris_toolbar/test_project_extent.png')) extent_node.setData('extent_node', item_code['item_type']) extent_node.setData(extent, item_code['INSTANCE']) extent_folder.appendRow(extent_node) # Add project layers node layers_folder = QStandardItem("Project Layers") layers_folder.setIcon(QIcon(':/plugins/qris_toolbar/test_folder.png')) layers_folder.setData('layers_folder', item_code['item_type']) project_node.appendRow(layers_folder) # TODO extend this for geometry types and raster layers for layer in self.qris_project.project_vector_layers.values(): layer_node = QStandardItem(layer.display_name) # TODO change icon by type layer_node.setIcon(QIcon(':/plugins/qris_toolbar/test_layers.png')) layer_node.setData('layer_node', item_code['item_type']) layer_node.setData(layer, item_code['INSTANCE']) layers_folder.appendRow(layer_node) # # Add riverscape surfaces node # # TODO go through and add layers to the tree # riverscape_surfaces_node = QStandardItem("Riverscape Surfaces") # riverscape_surfaces_node.setIcon(QIcon(':/plugins/qris_toolbar/BrowseFolder.png')) # riverscape_surfaces_node.setData('riverscape_surfaces_folder', item_code['item_type']) # riverscape_surfaces_node.setData('group', item_code['item_layer']) # project_node.appendRow(riverscape_surfaces_node) # # Add riverscape segments node # # TODO go through and add layers to the tree # riverscape_segments_node = QStandardItem("Riverscape Segments") # riverscape_segments_node.setIcon(QIcon(':/plugins/qris_toolbar/BrowseFolder.png')) # riverscape_segments_node.setData('riverscape_segments_folder', item_code['item_type']) # riverscape_segments_node.setData('group', item_code['item_layer']) # project_node.appendRow(riverscape_segments_node) # # Add detrended rasters to tree # detrended_rasters = QStandardItem("Detrended Rasters") # detrended_rasters.setIcon(QIcon(':/plugins/qris_toolbar/BrowseFolder.png')) # detrended_rasters.setData("DetrendedRastersFolder", item_code['item_type']) # detrended_rasters.setData('group', item_code['item_layer']) # project_node.appendRow(detrended_rasters) # for raster in self.qris_project.detrended_rasters.values(): # detrended_raster = QStandardItem(raster.name) # detrended_raster.setIcon(QIcon(':/plugins/qris_toolbar/qris_raster.png')) # detrended_raster.setData('DetrendedRaster', item_code['item_type']) # detrended_raster.setData(raster, item_code['INSTANCE']) # detrended_raster.setData('raster_layer', item_code['item_layer']) # detrended_rasters.appendRow(detrended_raster) # if len(raster.surfaces.values()) > 0: # item_surfaces = QStandardItem("Surfaces") # item_surfaces.setIcon(QIcon(':/plugins/qris_toolbar/BrowseFolder.png')) # item_surfaces.setData('group', item_code['item_layer']) # detrended_raster.appendRow(item_surfaces) # for surface in raster.surfaces.values(): # item_surface = QStandardItem(surface.name) # item_surface.setIcon(QIcon(':/plugins/qris_toolbar/layers/Polygon.png')) # item_surface.setData('DetrendedRasterSurface', item_code['item_type']) # item_surface.setData('surface_layer', item_code['item_layer']) # item_surface.setData(surface, item_code['INSTANCE']) # item_surfaces.appendRow(item_surface) # # Add assessments to tree # assessments_parent_node = QStandardItem("Riverscape Assessments") # assessments_parent_node.setIcon(QIcon(':/plugins/qris_toolbar/BrowseFolder.png')) # assessments_parent_node.setData('assessments_folder', item_code['item_type']) # assessments_parent_node.setData('group', item_code['item_layer']) # project_node.appendRow(assessments_parent_node) # if self.qris_project.project_assessments: # self.qris_project.assessments_path = os.path.join(self.qris_project.project_path, "Assessments.gpkg") # assessments_layer = QgsVectorLayer(self.qris_project.assessments_path + "|layername=assessments", "assessments", "ogr") # for assessment_feature in assessments_layer.getFeatures(): # assessment_node = QStandardItem(assessment_feature.attribute('assessment_date').toString('yyyy-MM-dd')) # assessment_node.setIcon(QIcon(':/plugins/qris_toolbar/BrowseFolder.png')) # assessment_node.setData('dam_assessment', item_code['item_type']) # assessment_node.setData('group', item_code['item_layer']) # assessment_node.setData(assessment_feature.attribute('fid'), item_code['feature_id']) # assessments_parent_node.appendRow(assessment_node) # assessments_parent_node.sortChildren(Qt.AscendingOrder) # Add designs to tree design_folder = QStandardItem("Low-Tech Designs") design_folder.setIcon(QIcon(':/plugins/qris_toolbar/test_folder.png')) design_folder.setData('design_folder', item_code['item_type']) project_node.appendRow(design_folder) self.treeView.setExpanded(design_folder.index(), True) design_geopackage_path = self.qris_project.project_designs.geopackage_path( self.qris_project.project_path) designs_path = design_geopackage_path + '|layername=designs' if os.path.exists(design_geopackage_path): designs_layer = QgsVectorLayer(designs_path, "designs", "ogr") for design_feature in designs_layer.getFeatures(): # If these data types stick this should be refactored into a create node function design_node = QStandardItem(design_feature.attribute('name')) design_node.setIcon( QIcon(':/plugins/qris_toolbar/test_design.png')) design_node.setData('design', item_code['item_type']) design_node.setData(design_feature.attribute('fid'), item_code['feature_id']) design_folder.appendRow(design_node) # TODO add the structure, footprint, and zoi to the tree under each design # TODO This just doesn't work very well design_folder.sortChildren(Qt.AscendingOrder) # populate structure types structure_type_folder = QStandardItem("Structure Types") structure_type_folder.setIcon( QIcon(':/plugins/qris_toolbar/test_settings.png')) structure_type_folder.setData('structure_type_folder', item_code['item_type']) design_folder.appendRow(structure_type_folder) structure_type_path = design_geopackage_path + '|layername=structure_types' structure_type_layer = QgsVectorLayer(structure_type_path, "structure_types", "ogr") for structure_type in structure_type_layer.getFeatures(): structure_type_node = QStandardItem( structure_type.attribute('name')) # TODO change the icon structure_type_node.setIcon( QIcon(':/plugins/qris_toolbar/test_structure.png')) structure_type_node.setData('structure_type', item_code['item_type']) structure_type_node.setData(structure_type.attribute('fid'), item_code['feature_id']) structure_type_folder.appendRow(structure_type_node) # populate design phases types phase_folder = QStandardItem("Implementation Phases") # TODO change icon phase_folder.setIcon(QIcon(':/plugins/qris_toolbar/test_settings.png')) phase_folder.setData('phase_folder', item_code['item_type']) design_folder.appendRow(phase_folder) phase_path = design_geopackage_path + '|layername=phases' phase_layer = QgsVectorLayer(phase_path, "phases", "ogr") for phase in phase_layer.getFeatures(): phase_node = QStandardItem(phase.attribute('name')) # TODO change the icon phase_node.setIcon(QIcon(':/plugins/qris_toolbar/test_phase.png')) phase_node.setData('phase', item_code['item_type']) phase_node.setData(phase.attribute('fid'), item_code['feature_id']) phase_folder.appendRow(phase_node) # populate zoi types zoi_type_folder = QStandardItem("ZOI Types") zoi_type_folder.setIcon( QIcon(':/plugins/qris_toolbar/test_settings.png')) zoi_type_folder.setData('zoi_type_folder', item_code['item_type']) design_folder.appendRow(zoi_type_folder) zoi_type_path = design_geopackage_path + '|layername=zoi_types' zoi_type_layer = QgsVectorLayer(zoi_type_path, "zoi_types", "ogr") for zoi_type in zoi_type_layer.getFeatures(): zoi_type_node = QStandardItem(zoi_type.attribute('name')) # TODO change the icon zoi_type_node.setIcon( QIcon(':/plugins/qris_toolbar/test_influence.png')) zoi_type_node.setData('zoi_type', item_code['item_type']) zoi_type_node.setData(zoi_type.attribute('fid'), item_code['feature_id']) zoi_type_folder.appendRow(zoi_type_node) # Add a placed for photos # photos_folder = QStandardItem("Project Photos") # photos_folder.setIcon(QIcon(':/plugins/qris_toolbar/BrowseFolder.png')) # photos_folder.setData('photos_folder', item_code['item_type']) # project_node.appendRow(photos_folder) # TODO for now we are expanding the map however need to remember expanded state or add new nodes as we add data # self.treeView.expandAll() # Check if new item is in the tree, if it is pass it to the add_to_map function # Adds a test comment if new_item is not None and new_item != '': selected_item = self._find_item_in_model(new_item) if selected_item is not None: add_to_map(self.qris_project, self.model, selected_item) def _find_item_in_model(self, name): """Looks in the tree for an item name passed from the dataChange method.""" # TODO may want to pass this is a try except block and give an informative error message selected_item = self.model.findItems(name, Qt.MatchRecursive)[0] return selected_item def get_item_expanded_state(self): """Recursively records a list of the expanded state for items in the tree""" def closeEvent(self, event): self.qris_project = None self.closingPlugin.emit() event.accept() def open_menu(self, position): """Connects signals as context menus to items in the tree""" self.menu.clear() indexes = self.treeView.selectedIndexes() if len(indexes) < 1: return # No multiselect so there is only ever one item idx = indexes[0] if not idx.isValid(): return model_item = self.model.itemFromIndex(indexes[0]) item_type = model_item.data(item_code['item_type']) if item_type == 'project_root': self.menu.addAction('EXPAND_ALL', lambda: self.expand_tree()) self.menu.addAction('COLLAPSE_ALL', lambda: self.collapse_tree()) self.menu.addAction( 'REFRESH_TREE', lambda: self.build_tree_view(self.qris_project, None)) elif item_type == "extent_folder": self.menu.addAction('ADD_PROJECT_EXTENT_LAYER', lambda: self.import_project_extent_layer()) self.menu.addAction('CREATE_BLANK_PROJECT_EXTENT_LAYER', lambda: self.create_blank_project_extent()) elif item_type == "layers_folder": self.menu.addAction('IMPORT_PROJECT_LAYER', lambda: self.import_project_layer()) elif item_type == "layer_node": self.menu.addAction( 'ADD_TO_MAP', lambda: add_to_map(self.qris_project, self.model, model_item)) elif item_type in ['extent_node', 'Project_Extent']: # self.menu.addAction('UPDATE_PROJECT_EXTENT', lambda: self.update_project_extent(model_item)) # self.menu.addAction('DELETE_PROJECT_EXTENT', lambda: self.delete_project_extent(model_item)) self.menu.addAction( 'ADD_TO_MAP', lambda: add_to_map(self.qris_project, self.model, model_item)) elif item_type == "design_folder": self.menu.addAction('ADD_DESIGN', lambda: self.add_design()) elif item_type == "design": self.menu.addAction( 'ADD_TO_MAP_OR_UPDATE_SYMBOLOGY', lambda: add_to_map(self.qris_project, self.model, model_item)) elif item_type == "structure_type_folder": self.menu.addAction('ADD_STRUCTURE_TYPE', lambda: self.add_structure_type()) elif item_type == "zoi_type_folder": self.menu.addAction('ADD_ZOI_TYPE', lambda: self.add_zoi_type()) elif item_type == "phase_folder": self.menu.addAction('ADD_PHASE', lambda: self.add_phase()) else: self.menu.clear() self.menu.exec_(self.treeView.viewport().mapToGlobal(position)) def expand_tree(self): self.treeView.expandAll() return def collapse_tree(self): self.treeView.collapseAll() return def add_assessment(self): """Initiates adding a new assessment""" self.assessment_dialog = AssessmentDlg(self.qris_project) self.assessment_dialog.dateEdit_assessment_date.setDate( QDate.currentDate()) self.assessment_dialog.dataChange.connect(self.build_tree_view) self.assessment_dialog.show() def add_design(self): """Initiates adding a new design""" self.design_dialog = DesignDlg(self.qris_project) # TODO remove this stuff about date self.design_dialog.dataChange.connect(self.build_tree_view) self.design_dialog.show() def add_structure_type(self): """Initiates adding a structure type and the structure type dialog""" # TODO First check if the path to the database exists design_geopackage_path = self.qris_project.project_designs.geopackage_path( self.qris_project.project_path) if os.path.exists(design_geopackage_path): self.structure_type_dialog = StructureTypeDlg(self.qris_project) self.structure_type_dialog.dataChange.connect(self.build_tree_view) self.structure_type_dialog.show() else: # TODO move the creation of the design data model so that this isn't necessary QMessageBox.information( self, "Structure Types", "Please create a new project design before adding structure types" ) def add_zoi_type(self): """Initiates adding a zoi type and the zoi type dialog""" # TODO First check if the path to the database exists design_geopackage_path = self.qris_project.project_designs.geopackage_path( self.qris_project.project_path) if os.path.exists(design_geopackage_path): self.zoi_type_dialog = ZoiTypeDlg(self.qris_project) self.zoi_type_dialog.dataChange.connect(self.build_tree_view) self.zoi_type_dialog.show() else: # TODO move the creation of the design data model so that this isn't necessary QMessageBox.information( self, "Structure Types", "Please create a new project design before adding a new influence type" ) def add_phase(self): """Initiates adding a new phase within the phase dialog""" # TODO First check if the path to the database exists design_geopackage_path = self.qris_project.project_designs.geopackage_path( self.qris_project.project_path) if os.path.exists(design_geopackage_path): self.phase_dialog = PhaseDlg(self.qris_project) self.phase_dialog.dataChange.connect(self.build_tree_view) self.phase_dialog.show() else: # TODO move the creation of the design data model so that this isn't necessary QMessageBox.information( self, "Structure Types", "Please create a new project design before adding phases") # This will kick off importing photos def import_photos(self): pass def add_detrended_raster(self): # last_browse_path = self.settings.getValue('lastBrowsePath') # last_dir = os.path.dirname(last_browse_path) if last_browse_path is not None else None dialog_return = QFileDialog.getOpenFileName( None, "Add Detrended Raster to QRiS project", None, self.tr("Raster Data Sources (*.tif)")) if dialog_return is not None and dialog_return[ 0] != "" and os.path.isfile(dialog_return[0]): self.addDetrendedDlg = AddDetrendedRasterDlg( None, dialog_return[0], self.qris_project) self.addDetrendedDlg.dataChange.connect(self.build_tree_view) self.addDetrendedDlg.exec() def import_project_extent_layer(self): """launches the dialog that supports import of a project extent layer polygon""" select_layer = QgsDataSourceSelectDialog() select_layer.exec() uri = select_layer.uri() if uri is not None and uri.isValid() and uri.wkbType == 3: self.project_extent_dialog = ProjectExtentDlg( uri, self.qris_project) self.project_extent_dialog.dataChange.connect(self.build_tree_view) self.project_extent_dialog.exec_() else: QMessageBox.critical(self, "Invalid Layer", "Please select a valid polygon layer") def create_blank_project_extent(self): """Adds a blank project extent that will be edited by the user""" self.project_extent_dialog = ProjectExtentDlg(None, self.qris_project) self.project_extent_dialog.dataChange.connect(self.build_tree_view) self.project_extent_dialog.exec_() def update_project_extent(self): """Renames the project extent layer""" pass # def delete_project_extent(self, selected_item): # """Deletes a project extent layer""" # display_name = selected_item.data(item_code['INSTANCE']).display_name # feature_name = selected_item.data(item_code['INSTANCE']).feature_name # geopackage_path = selected_item.data(item_code['INSTANCE']).geopackage_path(self.qris_project.project_path) # delete_ok = QMessageBox.question(self, f"Delete extent", f"Are you f*****g sure you wanna delete the extent layer: {display_name}") # if delete_ok == QMessageBox.Yes: # # remove from the map if it's there # # TODO consider doing this based on the path # for layer in QgsProject.instance().mapLayers().values(): # if layer.name() == display_name: # QgsProject.instance().removeMapLayers([layer.id()]) # iface.mapCanvas().refresh() # # TODO be sure to test whether the table exists first # gdal_delete = gdal.OpenEx(geopackage_path, gdal.OF_UPDATE, allowed_drivers=['GPKG']) # error = gdal_delete.DeleteLayer(feature_name) # gdal_delete.ExecuteSQL('VACUUM') # # TODO remove this from the Extents dictionary that will also remove from promect xml # del(self.qris_project.project_extents[feature_name]) # # refresh the project xml # self.qris_project.write_project_xml() # # refresh the tree # self.build_tree_view(self.qris_project, None) # else: # QMessageBox.information(self, "Delete extent", "No layers were deleted") def import_project_layer(self): """launches a dialog that supports import of project layers that can be clipped to a project extent""" select_layer = QgsDataSourceSelectDialog() select_layer.exec() uri = select_layer.uri() if uri is not None and uri.isValid(): # and uri.wkbType == 3: self.project_layer_dialog = ProjectLayerDlg(uri, self.qris_project) self.project_layer_dialog.dataChange.connect(self.build_tree_view) self.project_layer_dialog.exec_() else: QMessageBox.critical(self, "Invalid Layer", "Please select a valid gis layer") def explore_elevations(self, selected_item): raster = selected_item.data(item_code['INSTANCE']) self.elevation_widget = ElevationDockWidget(raster, self.qris_project) self.settings.iface.addDockWidget(Qt.LeftDockWidgetArea, self.elevation_widget) self.elevation_widget.dataChange.connect(self.build_tree_view) self.elevation_widget.show()
class QRAVEDockWidget(QDockWidget, Ui_QRAVEDockWidgetBase): closingPlugin = pyqtSignal() dataChange = pyqtSignal() showMeta = pyqtSignal() metaChange = pyqtSignal(str, str, dict, bool) def __init__(self, parent=None): """Constructor.""" super(QRAVEDockWidget, self).__init__(parent) self.setupUi(self) self.menu = ContextMenu() self.qproject = QgsProject.instance() self.qproject.cleared.connect(self.close_all) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.customContextMenuRequested.connect(self.open_menu) self.treeView.doubleClicked.connect(self.default_tree_action) self.treeView.clicked.connect(self.item_change) self.treeView.expanded.connect(self.expand_tree_item) self.settings = Settings() self.model = QStandardItemModel() self.loaded_projects: List(Project) = [] # Initialize our classes self.basemaps = BaseMaps() self.treeView.setModel(self.model) self.dataChange.connect(self.reload_tree) self.reload_tree() def expand_tree_item(self, idx: QModelIndex): item = self.model.itemFromIndex(idx) item_data = item.data(Qt.UserRole) if item_data and item_data.data and isinstance(item_data.data, QRaveBaseMap): item_data.data.load_layers() def _get_project(self, xml_path): try: return next(iter(self.loaded_projects)) except Exception: return None @pyqtSlot() def reload_tree(self): # re-initialize our model and reload the projects from file # Try not to do this too often if you can self.model.clear() self.loaded_projects = [] qrave_projects = self.get_project_settings() for project_path in qrave_projects: project = Project(project_path) project.load() if project is not None and project.exists is True and project.qproject is not None: self.model.appendRow(project.qproject) self.expand_children_recursive(self.model.indexFromItem(project.qproject)) self.loaded_projects.append(project) # Load the tree objects self.basemaps.load() # Now load the basemaps region = self.settings.getValue('basemapRegion') if self.settings.getValue('basemapsInclude') is True \ and region is not None and len(region) > 0 \ and region in self.basemaps.regions.keys(): self.model.appendRow(self.basemaps.regions[region]) self.expand_children_recursive(self.model.indexFromItem(self.basemaps.regions[region])) def get_project_settings(self): try: qrave_projects_raw, type_conversion_ok = self.qproject.readEntry( CONSTANTS['settingsCategory'], 'qrave_projects' ) if type_conversion_ok is False: qrave_projects = [] else: qrave_projects = json.loads(qrave_projects_raw) if qrave_projects is None or not isinstance(qrave_projects, list): qrave_projects = [] except Exception as e: self.settings.log('Error loading project settings: {}'.format(e), Qgis.Warning) qrave_projects = [] filtered = [pf for pf in qrave_projects if os.path.isfile(pf)] filtered.reverse() # We Treat this like a stack where the last project in goes on the top. # Element 0 should be the top item return filtered def set_project_settings(self, projects: List[str]): self.qproject.writeEntry(CONSTANTS['settingsCategory'], 'qrave_projects', json.dumps(projects)) @pyqtSlot() def add_project(self, xml_path: str): qrave_projects = self.get_project_settings() # If this project is not already in if xml_path not in qrave_projects: qrave_projects.append(xml_path) self.set_project_settings(qrave_projects) self.reload_tree() new_project = self._get_project(xml_path) # If this is a fresh load and the setting is set we load the default view load_default_setting = self.settings.getValue('loadDefaultView') if load_default_setting is True \ and new_project.default_view is not None \ and new_project.default_view in new_project.views: self.add_children_to_map(new_project.qproject, new_project.views[new_project.default_view]) def closeEvent(self, event): """ When the user clicks the "X" in the dockwidget titlebar """ self.hide() self.qproject.removeEntry(CONSTANTS['settingsCategory'], 'enabled') self.closingPlugin.emit() event.accept() def expand_children_recursive(self, idx: QModelIndex = None, force=False): """Expand all the children of a QTreeView node. Do it recursively TODO: Recursion might not be the best for large trees here. Args: idx (QModelIndex, optional): [description]. Defaults to None. force: ignore the "collapsed" business logic attribute """ if idx is None: idx = self.treeView.rootIndex() for idy in range(self.model.rowCount(idx)): child = self.model.index(idy, 0, idx) self.expand_children_recursive(child, force) item = self.model.itemFromIndex(idx) item_data = item.data(Qt.UserRole) if item is not None else None # NOTE: This is pretty verbose on purpose # This thing needs to have data or it defaults to being expanded if item_data is None or item_data.data is None: collapsed = False # Collapsed is an attribute set in the business logic # Never expand the QRaveBaseMap object becsause there's a network call involved elif isinstance(item_data.data, QRaveBaseMap) \ or (isinstance(item_data.data, dict) and 'collapsed' in item_data.data and item_data.data['collapsed'] == 'true'): collapsed = True else: collapsed = False if not self.treeView.isExpanded(idx) and not collapsed: self.treeView.setExpanded(idx, True) def default_tree_action(self, idx: QModelIndex): if not idx.isValid(): return item = self.model.itemFromIndex(idx) item_data: ProjectTreeData = item.data(Qt.UserRole) # This is the default action for all add-able layers including basemaps if isinstance(item_data.data, QRaveMapLayer): if item_data.data.layer_type in [QRaveMapLayer.LayerTypes.FILE, QRaveMapLayer.LayerTypes.REPORT]: self.file_system_open(item_data.data.layer_uri) else: QRaveMapLayer.add_layer_to_map(item) # Expand is the default option for wms because we might need to load the layers elif isinstance(item_data.data, QRaveBaseMap): if item_data.data.tile_type == 'wms': pass # All the XYZ layers can be added normally. else: QRaveMapLayer.add_layer_to_map(item) elif item_data.type in [QRaveTreeTypes.PROJECT_ROOT]: self.change_meta(item, item_data, True) # For folder-y types we want Expand and contract is already implemented as a default elif item_data.type in [ QRaveTreeTypes.PROJECT_FOLDER, QRaveTreeTypes.PROJECT_REPEATER_FOLDER, QRaveTreeTypes.PROJECT_VIEW_FOLDER, QRaveTreeTypes.BASEMAP_ROOT, QRaveTreeTypes.BASEMAP_SUPER_FOLDER, QRaveTreeTypes.BASEMAP_SUB_FOLDER ]: # print("Default Folder Action") pass elif item_data.type == QRaveTreeTypes.PROJECT_VIEW: print("Default View Action") self.add_view_to_map(item_data) def item_change(self, pos): """Triggered when the user selects a new item in the tree Args:pos pos ([type]): [description] """ indexes = self.treeView.selectedIndexes() # No multiselect so there is only ever one item item = self.model.itemFromIndex(indexes[0]) data_item: ProjectTreeData = item.data(Qt.UserRole) if len(indexes) < 1 or data_item.project is None or not data_item.project.exists: return # Update the metadata if we need to self.change_meta(item, data_item) def change_meta(self, item: QStandardItem, item_data: ProjectTreeData, show=False): """Update the MetaData dock widget with new information Args: item (QStandardItem): [description] data ([type]): [description] show (bool, optional): [description]. Defaults to False. """ data = item_data.data if isinstance(data, QRaveMapLayer): meta = data.meta if data.meta is not None else {} self.metaChange.emit(item.text(), MetaType.LAYER, meta, show) elif isinstance(data, QRaveBaseMap): self.metaChange.emit(item.text(), MetaType.NONE, {}, show) elif item_data.type == QRaveTreeTypes.PROJECT_ROOT: self.metaChange.emit(item.text(), MetaType.PROJECT, { 'project': item_data.project.meta, 'warehouse': item_data.project.warehouse_meta }, show) elif item_data.type in [ QRaveTreeTypes.PROJECT_FOLDER, QRaveTreeTypes.PROJECT_REPEATER_FOLDER, QRaveTreeTypes.PROJECT_VIEW_FOLDER, QRaveTreeTypes.BASEMAP_ROOT, QRaveTreeTypes.BASEMAP_SUPER_FOLDER, QRaveTreeTypes.BASEMAP_SUB_FOLDER ]: self.metaChange.emit(item.text(), MetaType.FOLDER, data or {}, show) elif isinstance(data, dict): # this is just the generic case for any kind of metadata self.metaChange.emit(item.text(), MetaType.NONE, data or {}, show) else: # Do not update the metadata if we have nothing to show self.metaChange.emit(item.text(), MetaType.NONE, {}, show) def get_warehouse_url(self, wh_meta: Dict[str, str]): if wh_meta is not None: if 'program' in wh_meta and 'id' in wh_meta: return '/'.join([CONSTANTS['warehouseUrl'], wh_meta['program'], wh_meta['id']]) elif '_rs_wh_id' in wh_meta and '_rs_wh_program' in wh_meta: return '/'.join([CONSTANTS['warehouseUrl'], wh_meta['_rs_wh_program'], wh_meta['_rs_wh_id']]) return None def project_warehouse_view(self, project: Project): """Open this project in the warehouse if the warehouse meta entries exist """ url = self.get_warehouse_url(project.warehouse_meta) if url is not None: QDesktopServices.openUrl(QUrl(url)) def layer_warehouse_view(self, data: QRaveMapLayer): """Open this project in the warehouse if the warehouse meta entries exist """ url = self.get_warehouse_url(data.meta) if url is not None: QDesktopServices.openUrl(QUrl(url)) def close_all(self): for p in range(len(self.loaded_projects)): self.close_project(self.loaded_projects[0]) def close_project(self, project: Project): """ Close the project """ try: qrave_projects_raw, type_conversion_ok = self.qproject.readEntry( CONSTANTS['settingsCategory'], 'qrave_projects' ) qrave_projects = json.loads(qrave_projects_raw) if not type_conversion_ok or qrave_projects is None: qrave_projects = [] except Exception as e: self.settings.log('Error closing project: {}'.format(e), Qgis.Warning) qrave_projects = [] # Filter out the project we want to close and reload the tree qrave_projects = [x.project_xml_path for x in self.loaded_projects if x != project] # Write the settings back to the project self.qproject.writeEntry(CONSTANTS['settingsCategory'], 'qrave_projects', json.dumps(qrave_projects)) self.loaded_projects = qrave_projects self.reload_tree() def file_system_open(self, fpath: str): """Open a file on the operating system using the default action Args: fpath (str): [description] """ qurl = QUrl.fromLocalFile(fpath) QDesktopServices.openUrl(QUrl(qurl)) def file_system_locate(self, fpath: str): """This the OS-agnostic "show in Finder" or "show in explorer" equivalent It should open the folder of the item in question Args: fpath (str): [description] """ final_path = os.path.dirname(fpath) while not os.path.isdir(final_path): final_path = os.path.dirname(final_path) qurl = QUrl.fromLocalFile(final_path) QDesktopServices.openUrl(qurl) def toggleSubtree(self, item: QStandardItem = None, expand=True): def _recurse(curritem): idx = self.model.indexFromItem(item) if expand is not self.treeView.isExpanded(idx): self.treeView.setExpanded(idx, expand) for row in range(curritem.rowCount()): _recurse(curritem.child(row)) if item is None: if expand is True: self.treeView.expandAll() else: self.treeView.collapseAll() else: _recurse(item) def add_view_to_map(self, item_data: ProjectTreeData): """Add a view and all its layers to the map Args: item (QStandardItem): [description] """ self.add_children_to_map(item_data.project.qproject, item_data.data) def add_children_to_map(self, item: QStandardItem, bl_ids: List[str] = None): """Iteratively add all children to the map Args: item (QStandardItem): [description] bl_ids (List[str], optional): List of ids to filter by so we don't load everything. this is used for loading views """ for child in self._get_children(item): # Is this something we can add to the map? project_tree_data = child.data(Qt.UserRole) if project_tree_data is not None and isinstance(project_tree_data.data, QRaveMapLayer): data = project_tree_data.data loadme = False # If this layer matches the businesslogic id filter if bl_ids is not None and len(bl_ids) > 0: if 'id' in data.bl_attr and data.bl_attr['id'] in bl_ids: loadme = True else: loadme = True if loadme is True: data.add_layer_to_map(child) def _get_children(self, root_item: QStandardItem): """Recursion is going to kill us here so do an iterative solution instead https://stackoverflow.com/questions/41949370/collect-all-items-in-qtreeview-recursively Yields: [type]: [description] """ stack = [root_item] while stack: parent = stack.pop(0) for row in range(parent.rowCount()): for column in range(parent.columnCount()): child = parent.child(row, column) yield child if child.hasChildren(): stack.append(child) def _get_parents(self, start_item: QStandardItem): stack = [] placeholder = start_item.parent() while placeholder is not None and placeholder != self.model.invisibleRootItem(): stack.append(placeholder) placeholder = start_item.parent() return stack.reverse() def open_menu(self, position): indexes = self.treeView.selectedIndexes() if len(indexes) < 1: return # No multiselect so there is only ever one item idx = indexes[0] if not idx.isValid(): return item = self.model.itemFromIndex(indexes[0]) project_tree_data = item.data(Qt.UserRole) # ProjectTreeData object data = project_tree_data.data # Could be a QRaveBaseMap, a QRaveMapLayer or just some random data # This is the layer context menu if isinstance(data, QRaveMapLayer): if data.layer_type == QRaveMapLayer.LayerTypes.WEBTILE: self.basemap_context_menu(idx, item, project_tree_data) elif data.layer_type in [QRaveMapLayer.LayerTypes.FILE, QRaveMapLayer.LayerTypes.REPORT]: self.file_layer_context_menu(idx, item, project_tree_data) else: self.map_layer_context_menu(idx, item, project_tree_data) elif isinstance(data, QRaveBaseMap): # A WMS QARaveBaseMap is just a container for layers if data.tile_type == 'wms': self.folder_dumb_context_menu(idx, item, project_tree_data) # Every other kind of basemap is an add-able layer else: self.basemap_context_menu(idx, item, project_tree_data) elif project_tree_data.type == QRaveTreeTypes.PROJECT_ROOT: self.project_context_menu(idx, item, project_tree_data) elif project_tree_data.type in [ QRaveTreeTypes.PROJECT_VIEW_FOLDER, QRaveTreeTypes.BASEMAP_ROOT, QRaveTreeTypes.BASEMAP_SUPER_FOLDER ]: self.folder_dumb_context_menu(idx, item, project_tree_data) elif project_tree_data.type in [ QRaveTreeTypes.PROJECT_FOLDER, QRaveTreeTypes.PROJECT_REPEATER_FOLDER, QRaveTreeTypes.BASEMAP_SUB_FOLDER ]: self.folder_context_menu(idx, item, project_tree_data) elif project_tree_data.type == QRaveTreeTypes.PROJECT_VIEW: self.view_context_menu(idx, item, project_tree_data) self.menu.exec_(self.treeView.viewport().mapToGlobal(position)) def map_layer_context_menu(self, idx: QModelIndex, item: QStandardItem, item_data: ProjectTreeData): self.menu.clear() self.menu.addAction('ADD_TO_MAP', lambda: QRaveMapLayer.add_layer_to_map(item), enabled=item_data.data.exists) self.menu.addAction('VIEW_LAYER_META', lambda: self.change_meta(item, item_data, True)) if bool(self.get_warehouse_url(item_data.data.meta)): self.menu.addAction('VIEW_WEB_SOURCE', lambda: self.layer_warehouse_view(item_data)) self.menu.addAction('BROWSE_FOLDER', lambda: self.file_system_locate(item_data.data.layer_uri)) def file_layer_context_menu(self, idx: QModelIndex, item: QStandardItem, item_data: ProjectTreeData): self.menu.clear() self.menu.addAction('OPEN_FILE', lambda: self.file_system_open(item_data.data.layer_uri)) self.menu.addAction('BROWSE_FOLDER', lambda: self.file_system_locate(item_data.data.layer_uri)) # Basemap context items def basemap_context_menu(self, idx: QModelIndex, item: QStandardItem, data: ProjectTreeData): self.menu.clear() self.menu.addAction('ADD_TO_MAP', lambda: QRaveMapLayer.add_layer_to_map(item)) # Folder-level context menu def folder_context_menu(self, idx: QModelIndex, item: QStandardItem, data: ProjectTreeData): self.menu.clear() self.menu.addAction('ADD_ALL_TO_MAP', lambda: self.add_children_to_map(item)) self.menu.addSeparator() self.menu.addAction('COLLAPSE_ALL', lambda: self.toggleSubtree(item, False)) self.menu.addAction('EXPAND_ALL', lambda: self.toggleSubtree(item, True)) # Some folders don't have the 'ADD_ALL_TO_MAP' functionality enabled def folder_dumb_context_menu(self, idx: QModelIndex, item: QStandardItem, data: ProjectTreeData): self.menu.clear() self.menu.addAction('COLLAPSE_ALL', lambda: self.toggleSubtree(item, False)) self.menu.addAction('EXPAND_ALL', lambda: self.toggleSubtree(item, True)) # View context items def view_context_menu(self, idx: QModelIndex, item: QStandardItem, item_data: ProjectTreeData): self.menu.clear() self.menu.addAction('ADD_ALL_TO_MAP', lambda: self.add_view_to_map(item_data)) # Project-level context menu def project_context_menu(self, idx: QModelIndex, item: QStandardItem, data: ProjectTreeData): self.menu.clear() self.menu.addAction('COLLAPSE_ALL', lambda: self.toggleSubtree(None, False)) self.menu.addAction('EXPAND_ALL', lambda: self.toggleSubtree(None, True)) self.menu.addSeparator() self.menu.addAction('BROWSE_PROJECT_FOLDER', lambda: self.file_system_locate(data.project.project_xml_path)) self.menu.addAction('VIEW_PROJECT_META', lambda: self.change_meta(item, data, True)) self.menu.addAction('WAREHOUSE_VIEW', lambda: self.project_warehouse_view(data.project), enabled=bool(self.get_warehouse_url(data.project.warehouse_meta))) self.menu.addAction('ADD_ALL_TO_MAP', lambda: self.add_children_to_map(item)) self.menu.addSeparator() self.menu.addAction('REFRESH_PROJECT_HIERARCHY', self.reload_tree) self.menu.addAction('CUSTOMIZE_PROJECT_HIERARCHY', enabled=False) self.menu.addSeparator() self.menu.addAction('CLOSE_PROJECT', lambda: self.close_project(data.project), enabled=bool(data.project))