author Pierre-Yves David <>
Mon, 09 Jun 2008 13:39:44 +0200
changeset 4 6ff5e87d288a
parent 0 7710b138d4eb
permissions -rw-r--r--
change position on __future__ import for compatibility

# Copyright (c) 2004 LOGILAB S.A. (Paris, FRANCE).
# --
# 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.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""This module contains some tools to handle main application and plugins

__revision__ = '$Id:,v 1.12 2006-04-23 13:53:52 nico Exp $'

from os.path import join

import gtk, gobject
from pigg.mvc import Controller
from pigg.form import PyFormModel
from pigg.wgenerator import notebook_generate

from logilab.common.configuration import Configuration, OptionValueError

from oobrother.uiutils.basemixins import WindowMixIn, PluggableFrameMixIn, \
from oobrother.uiutils.trees import init_treeview_columns

from oobrother.sysutils import OOBROTHER_HOME
# from oobrother import get_path

__metaclass__ = type

def format_config_entry(opt_name, opt_dict):
    """format a config entry to a schema line"""
    opt_type = opt_dict['type']
    if opt_type in ('choice', 'multiple_choice'):
        extra_args = (opt_dict['choices'],)
        extra_args = ()
    return (opt_name, opt_type, opt_name.replace('_', ' '),
            extra_args, False, opt_dict.get('default'))

def schema_from_config(config):
    """return a schema as expected by `gtkmv.form.PyFormModel`, built
    from a `logilab.common.configuration.Configuration` instance.
    return [format_config_entry(opt_name, opt_dict)
            for opt_name, opt_dict in config.options]
def notebook_from_config(config, model, ctrl):
    """generates and returns a gtk note book according to the given
    `logilab.common.configuration.Configuration` instance
    nb_def = {}
    for opt_name, opt_dict in config.options:
        if opt_dict.get('type') is None:
        section = opt_dict.get('group',
        attr_def = format_config_entry(opt_name, opt_dict)
        nb_def.setdefault(section, []).append(attr_def)
    return notebook_generate(nb_def.items(), model, ctrl)

def build_config_model(configurables):
    """creates an returns a tree model from a configuration tree"""
    store = gtk.TreeStore(gobject.TYPE_STRING,   # configuration section
                          gobject.TYPE_PYOBJECT, # The configuration object
    for configurable in configurables:
        fill_config_store(store, configurable, None)
    return store

def fill_config_store(store, configurable, tree_iter):
    """recursive build of a tree model for a configuration tree"""
    new_iter = store.append(tree_iter, [, configurable])
    for subconfig in configurable.subconfiguration():
        fill_config_store(store, subconfig, new_iter)

def configuration_models(configurables):
    """return a list of configurable object (ie configuration node with
    a 'cfg' attribute set)
    result = []
    for configurable in configurables:
        if configurable.cfg:
        result += configuration_models(configurable.subconfiguration())
    return result

class ConfigurableNode:
    def __init__(self, name, cfg=None, children=()): = name
        self.cfg = cfg # optionel pluggable config object        
        self._children = children
    def subconfiguration(self):
        """return a list of configuration nodes for subconfiguration
        return self._children

class PluggableConfig(Configuration):
    """extends `logilab.common.configuration.Configuration` to handle
    gui specific stuff (model, ctrl, pluggable widget
    def __init__(self, name, config_file, options):
        if config_file:
            config_file = join(OOBROTHER_HOME, config_file)
        Configuration.__init__(self, config_file, options, name)
        self.wdg = None
        assert options
        assert config_file
        self.model = ConfigurationModel(self)
        except OptionValueError, ex:
            log(LOG_ERR, '%s: %s', (config_file, ex))
        self.ctrl = Controller(self.model)
        self.wdg = notebook_from_config(self, self.model, self.ctrl).wdg

class ConfigurationModel(PyFormModel):
    """a gtkmv model using a `logilab.common.configuration.Configuration`
    instance as backend
    def __init__(self, config, schema=None):
        self.config = config
        if schema is None:
            schema = schema_from_config(config)
        self.schema = schema
        PyFormModel.__init__(self, self.schema, {})

    def update(self):
        """update the model values from the backend values"""
        for attr in self.schema:
            attr = attr[0]
            self.set_value(attr, self.config[attr])
        self._orig_data = self._data.copy()
    def _commit(self):
        """write back the model's content (the form is completed at this point)
        modifs = self.get_modifications()
        if not modifs:
            log(LOG_DEBUG, 'no modification to save to %s' %
        for key, value in modifs.items():
                self.config.global_set_option(key, value)
            except KeyError:
                self.config.set_option(key, value)
        self.config.generate_config(open(self.config.config_file, 'w'))
        log(LOG_INFO, '%s written' % self.config.config_file)

class GlobalConfigurationModel:
    """the global configuration model is used to connect all the models
    related to application's configuration and editable by the
    configuration window.

    It only defines necessary methods from the Model interface.
    def __init__(self, models):
        self._models = models
    def commit(self):
        """commit all models"""
        for model in self._models:
    def rollback(self):
        """rollback all models"""
        for model in self._models:
    def notify_all(self):
        """ask each model to notify its observers"""
        for model in self._models:
    def get_modifications(self):
        """return the modification of each model merged alltogether"""
        modifs = {}
        for model in self._models:
        return modifs