Source code for jukeboxcore.addons.configer.configer

import os
import fnmatch

from PySide import QtGui

from jukeboxcore.log import get_logger
log = get_logger(__name__)
from jukeboxcore import iniconf
from jukeboxcore.constants import PLUGIN_CONFIG_DIR
from jukeboxcore.errors import ConfigError
from jukeboxcore.plugins import JB_CoreStandaloneGuiPlugin
from jukeboxcore.gui.configeditor import ConfigObjModel, InifilesModel
from jukeboxcore.gui.main import JB_MainWindow
from configer_ui import Ui_configer_mwin


[docs]class ConfigerWin(JB_MainWindow, Ui_configer_mwin): """A Configeditor window The window uses the configer.ui for it's Layout. It has a main editor treeview to edit the ConfigObjs. Next to it is a listview to select the configs. There are also two buttons. One is for saving, the other for reseting a value to its default. the get_configs method is used to gather all the config files in the userfolder and finding the corresponding configspec in any of the plugin folders. """ def __init__(self, parent=None): """Constructs a new ConfigerWin :param parent: Optional - the parent of the window - default is None :type parent: QWidget :returns: None :rtype: None :raises: None This will also load all configs and display the first one. """ super(ConfigerWin, self).__init__(parent) self.setupUi(self) self.confobjmodel = None self.inimodel = InifilesModel(self.get_configs()) self.files_lv.setModel(self.inimodel) self.sm = self.files_lv.selectionModel() #.currentChanged.connect(self.set_inifile) self.sm.currentChanged.connect(self.set_inifile) self.reset_pb.clicked.connect(self.reset_current_row) self.save_pb.clicked.connect(self.save_current_config)
[docs] def reset_current_row(self, *args, **kwargs): """Reset the selected rows value to its default value :returns: None :rtype: None :raises: None """ i = self.configobj_treev.currentIndex() m = self.configobj_treev.model() m.restore_default(i)
[docs] def get_configs(self): """Load all config files and return the configobjs :returns: a list of configobjs :raises: None It always loads the coreconfig. Then it looks for all configs inside the PLUGIN_CONFIG_DIR. It will find the corresponding spec of the plugins. If there is a spec, but no ini, it will also be loaded! """ # all loaded configs are stored in confs confs = [] # always load core config. it is not part of the plugin configs try: confs.append(iniconf.get_core_config()) except ConfigError, e: log.error("Could not load Core config! Reason was: %s" % e) # get config specs that lie in the plugin path # we have to watch the order we gather the specs # plugins can override each other, so can config specs # it depends on the order of the JUKEBOX_PLUGIN_PATH specs = {} pathenv = os.environ.get('JUKEBOX_PLUGIN_PATH', '') paths = pathenv.split(';') for p in reversed(paths): if p: files = self.find_inifiles(p) for ini in files: base = os.path.basename(ini) specs[base] = ini configs = {} files = self.find_inifiles(PLUGIN_CONFIG_DIR) for ini in files: base = os.path.basename(ini) configs[base] = ini # find matching pairs of configs and specs # and load them for k in configs: spec = specs.pop(k, None) conf = configs[k] try: confs.append(iniconf.load_config(conf, spec)) except ConfigError, e: log.error("Could not load config %s, Reason was: %s" % (k ,e)) # the remaining configspecs can be used to create # empty configs for k in specs: spec = specs[k] conf = os.path.join(PLUGIN_CONFIG_DIR, k) try: confs.append(iniconf.load_config(conf, spec)) except ConfigError, e: log.error("Could not load config %s, Reason was: %s" % (k ,e)) return confs
[docs] def find_inifiles(self, path): """Return all ini-files in the directory of path and below :param path: a path to a directory :type path: str :returns: list of configfiles :rtype: list of str :raises: None """ matches = [] for root, dirnames, filenames in os.walk(path): for filename in fnmatch.filter(filenames, '*.ini'): matches.append(os.path.join(root, filename)) return matches
[docs] def set_inifile(self, current, previous): """Set the configobj to the current index of the files_lv This is a slot for the currentChanged signal :param current: the modelindex of a inifilesmodel that should be set for the configobj_treev :type current: QModelIndex :param previous: the previous selected index :type previous: QModelIndex :returns: None :raises: None """ c = self.inimodel.data(current, self.inimodel.confobjRole) self.confobjmodel = ConfigObjModel(c) self.configobj_treev.setModel(self.confobjmodel) self.configobj_treev.expandAll() self.confobjmodel.dataChanged.connect(self.iniedited)
[docs] def iniedited(self, *args, **kwargs): """Set the current index of inimodel to modified :returns: None :rtype: None :raises: None """ self.inimodel.set_index_edited(self.files_lv.currentIndex(), True)
[docs] def closeEvent(self, event): """Handles closing of the window. If configs were edited, ask user to continue. :param event: the close event :type event: QCloseEvent :returns: None :rtype: None :raises: None """ if self.inimodel.get_edited(): r = self.doc_modified_prompt() if r == QtGui.QMessageBox.Yes: event.accept() else: event.ignore() else: event.accept()
[docs] def doc_modified_prompt(self, ): """Create a message box, that asks the user to continue although files have been modified :returns: value of the standard button of qmessagebox that has been pressed. Either Yes or Cancel. :rtype: QtGui.QMessageBox.StandardButton :raises: None """ msgbox = QtGui.QMessageBox() msgbox.setWindowTitle("Discard changes?") msgbox.setText("Documents have been modified.") msgbox.setInformativeText("Do you really want to exit? Changes will be lost!") msgbox.setStandardButtons(msgbox.Yes | msgbox.Cancel) msgbox.setDefaultButton(msgbox.Cancel) msgbox.exec_() return msgbox.result()
[docs] def invalid_prompt(self, ): """Create a message box, that asks the user to continue although files are invalid :returns: value of the standard button of qmessagebox that has been pressed. Either Yes or Cancel. :rtype: QtGui.QMessageBox.StandardButton :raises: None """ msgbox = QtGui.QMessageBox() msgbox.setWindowTitle("Invalid Config!") msgbox.setText("Invalid Configs!") msgbox.setInformativeText("Do you really want to continue? Invalid values will be replaced by their default!") msgbox.setStandardButtons(msgbox.Yes | msgbox.Cancel) msgbox.setDefaultButton(msgbox.Cancel) msgbox.exec_() return msgbox.result()
[docs] def save_current_config(self, ): """Saves the currently displayed config :returns: None :rtype: None :raises: None This resets the edited status of the file to False. Also asks the user to continue if config is invalid. """ # check if all configs validate correctly btn = None for row in range(self.inimodel.rowCount()): i = self.inimodel.index(row, 0) r = self.inimodel.validate(i) if r is not True: btn = self.invalid_prompt() break if btn == QtGui.QMessageBox.Cancel: return current = self.files_lv.currentIndex() c = self.inimodel.data(current, self.inimodel.confobjRole) c.write() self.inimodel.set_index_edited(current, False)
[docs]class Configer(JB_CoreStandaloneGuiPlugin): """A plugin that can run a ConfigEditor This can be used as a standalone plugin. Before you call run, make sure that there is a running QApplication running. See :mod:`jukeboxcore.gui.main` for helpful functions. """ author = "David Zuber" copyright = "2014" version = "0.1" description = "A tool for editing config files"
[docs] def init(self, ): """Do nothing on init! Call run() if you want to start the configeditor :returns: None :rtype: None :raises: None """ pass
[docs] def uninit(self, ): """Do nothing on uninit! :returns: None :rtype: None :raises: None """ pass
[docs] def run(self, parent=None): """Start the configeditor :returns: None :rtype: None :raises: None """ self.cw = ConfigerWin(parent=parent) self.cw.show()