123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- """
- ***************************************************************************
- ConfigDialog.py
- ---------------------
- Date : August 2012
- Copyright : (C) 2012 by Victor Olaya
- Email : volayaf at gmail dot com
- ***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************
- """
- __author__ = 'Victor Olaya'
- __date__ = 'August 2012'
- __copyright__ = '(C) 2012, Victor Olaya'
- import os
- import warnings
- from qgis.PyQt import uic
- from qgis.PyQt.QtCore import Qt, QEvent
- from qgis.PyQt.QtWidgets import (QFileDialog,
- QStyle,
- QMessageBox,
- QStyledItemDelegate,
- QLineEdit,
- QWidget,
- QToolButton,
- QHBoxLayout,
- QComboBox,
- QPushButton,
- QApplication)
- from qgis.PyQt.QtGui import (QIcon,
- QStandardItemModel,
- QStandardItem,
- QCursor)
- from qgis.gui import (QgsDoubleSpinBox,
- QgsSpinBox,
- QgsOptionsPageWidget,
- QgsOptionsDialogHighlightWidget)
- from qgis.core import NULL, QgsApplication, QgsSettings
- from qgis.utils import OverrideCursor
- from processing.core.ProcessingConfig import (ProcessingConfig,
- settingsWatcher,
- Setting)
- from processing.core.Processing import Processing
- from processing.gui.DirectorySelectorDialog import DirectorySelectorDialog
- from processing.gui.menus import defaultMenuEntries, menusSettingsGroup
- pluginPath = os.path.split(os.path.dirname(__file__))[0]
- with warnings.catch_warnings():
- warnings.filterwarnings("ignore", category=DeprecationWarning)
- WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgConfig.ui'))
- class ConfigOptionsPage(QgsOptionsPageWidget):
- def __init__(self, parent):
- super().__init__(parent)
- self.config_widget = ConfigDialog(False)
- layout = QHBoxLayout()
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setMargin(0)
- self.setLayout(layout)
- layout.addWidget(self.config_widget)
- self.setObjectName('processingOptions')
- self.highlightWidget = ProcessingTreeHighlight(self.config_widget)
- self.registerHighlightWidget(self.highlightWidget)
- def apply(self):
- self.config_widget.accept()
- def helpKey(self):
- return 'processing/index.html'
- class ProcessingTreeHighlight(QgsOptionsDialogHighlightWidget):
- def __init__(self, config_dialog):
- super().__init__(config_dialog.tree)
- self.config_dialog = config_dialog
- def highlightText(self, text):
- return self.config_dialog.textChanged(text)
- def searchText(self, text):
- return self.config_dialog.textChanged(text)
- def reset(self):
- self.config_dialog.textChanged('')
- class ConfigDialog(BASE, WIDGET):
- def __init__(self, showSearch=True):
- super().__init__(None)
- self.setupUi(self)
- self.groupIcon = QgsApplication.getThemeIcon('mIconFolder.svg')
- 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, False if text else True)
- 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 group not 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 SettingItem(QStandardItem):
- def __init__(self, setting):
- QStandardItem.__init__(self)
- self.setting = setting
- self.setData(setting, Qt.UserRole)
- if isinstance(setting.value, bool):
- self.setCheckable(True)
- self.setEditable(False)
- if setting.value:
- self.setCheckState(Qt.Checked)
- else:
- self.setCheckState(Qt.Unchecked)
- else:
- self.setData(setting.value, Qt.EditRole)
- class SettingDelegate(QStyledItemDelegate):
- def __init__(self, parent=None):
- QStyledItemDelegate.__init__(self, parent)
- def createEditor(self, parent, options, index):
- setting = index.model().data(index, Qt.UserRole)
- if setting.valuetype == Setting.FOLDER:
- return FileDirectorySelector(parent, placeholder=setting.placeholder)
- elif setting.valuetype == Setting.FILE:
- return FileDirectorySelector(parent, True, setting.placeholder)
- elif setting.valuetype == Setting.SELECTION:
- combo = QComboBox(parent)
- combo.addItems(setting.options)
- return combo
- elif setting.valuetype == Setting.MULTIPLE_FOLDERS:
- return MultipleDirectorySelector(parent, setting.placeholder)
- else:
- value = self.convertValue(index.model().data(index, Qt.EditRole))
- if isinstance(value, int):
- spnBox = QgsSpinBox(parent)
- spnBox.setRange(-999999999, 999999999)
- return spnBox
- elif isinstance(value, float):
- spnBox = QgsDoubleSpinBox(parent)
- spnBox.setRange(-999999999.999999, 999999999.999999)
- spnBox.setDecimals(6)
- return spnBox
- elif isinstance(value, str):
- lineEdit = QLineEdit(parent)
- lineEdit.setPlaceholderText(setting.placeholder)
- return lineEdit
- def setEditorData(self, editor, index):
- value = self.convertValue(index.model().data(index, Qt.EditRole))
- setting = index.model().data(index, Qt.UserRole)
- if setting.valuetype == Setting.SELECTION:
- editor.setCurrentIndex(editor.findText(value))
- elif setting.valuetype in (Setting.FLOAT, Setting.INT):
- editor.setValue(value)
- else:
- editor.setText(value)
- def setModelData(self, editor, model, index):
- value = self.convertValue(index.model().data(index, Qt.EditRole))
- setting = index.model().data(index, Qt.UserRole)
- if setting.valuetype == Setting.SELECTION:
- model.setData(index, editor.currentText(), Qt.EditRole)
- else:
- if isinstance(value, str):
- model.setData(index, editor.text(), Qt.EditRole)
- else:
- model.setData(index, editor.value(), Qt.EditRole)
- def sizeHint(self, option, index):
- return QgsSpinBox().sizeHint()
- def eventFilter(self, editor, event):
- if event.type() == QEvent.FocusOut and hasattr(editor, 'canFocusOut'):
- if not editor.canFocusOut:
- return False
- return QStyledItemDelegate.eventFilter(self, editor, event)
- def convertValue(self, value):
- if value is None or value == NULL:
- return ""
- try:
- return int(value)
- except:
- try:
- return float(value)
- except:
- return str(value)
- class FileDirectorySelector(QWidget):
- def __init__(self, parent=None, selectFile=False, placeholder=""):
- QWidget.__init__(self, parent)
- # create gui
- self.btnSelect = QToolButton()
- self.btnSelect.setText('…')
- self.lineEdit = QLineEdit()
- self.lineEdit.setPlaceholderText(placeholder)
- self.hbl = QHBoxLayout()
- self.hbl.setMargin(0)
- self.hbl.setSpacing(0)
- self.hbl.addWidget(self.lineEdit)
- self.hbl.addWidget(self.btnSelect)
- self.setLayout(self.hbl)
- self.canFocusOut = False
- self.selectFile = selectFile
- self.setFocusPolicy(Qt.StrongFocus)
- self.btnSelect.clicked.connect(self.select)
- def select(self):
- lastDir = ''
- if not self.selectFile:
- selectedPath = QFileDialog.getExistingDirectory(None,
- self.tr('Select directory'), lastDir,
- QFileDialog.ShowDirsOnly)
- else:
- selectedPath, selected_filter = QFileDialog.getOpenFileName(None,
- self.tr('Select file'), lastDir, self.tr('All files (*)')
- )
- if not selectedPath:
- return
- self.lineEdit.setText(selectedPath)
- self.canFocusOut = True
- def text(self):
- return self.lineEdit.text()
- def setText(self, value):
- self.lineEdit.setText(value)
- class MultipleDirectorySelector(QWidget):
- def __init__(self, parent=None, placeholder=""):
- QWidget.__init__(self, parent)
- # create gui
- self.btnSelect = QToolButton()
- self.btnSelect.setText('…')
- self.lineEdit = QLineEdit()
- self.lineEdit.setPlaceholderText(placeholder)
- self.hbl = QHBoxLayout()
- self.hbl.setMargin(0)
- self.hbl.setSpacing(0)
- self.hbl.addWidget(self.lineEdit)
- self.hbl.addWidget(self.btnSelect)
- self.setLayout(self.hbl)
- self.canFocusOut = False
- self.setFocusPolicy(Qt.StrongFocus)
- self.btnSelect.clicked.connect(self.select)
- def select(self):
- text = self.lineEdit.text()
- if text != '':
- items = text.split(';')
- else:
- items = []
- dlg = DirectorySelectorDialog(None, items)
- if dlg.exec_():
- text = dlg.value()
- self.lineEdit.setText(text)
- self.canFocusOut = True
- def text(self):
- return self.lineEdit.text()
- def setText(self, value):
- self.lineEdit.setText(value)
|