""" MVP.py

Module that provides a Model-View-Presenter framework for use with Straw
"""
__copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
__license__ = """
Straw 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.

Straw 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. """


import pygtk
pygtk.require('2.0')
from gtk import glade
import Event


__doc__ = "A MVP framework. Contains base classes for views and presenters."

class View(object):
    """Base class for widget-based view objects."""
    def __init__(self, widget, model = None, presenter = None):
        self._widget = widget
        self._model = model
        self._presenter = presenter

        if model is not None:
            self._model_set()
        if presenter is not None:
            self._presenter_set()

        self._initialize()
        self._connect_signals(widget)

    def _connect_signals(self, widget):
        raise NotImplemented

    def _initialize(self):
        """Called from the constructor after the instance variables have
        been set and the corresponding initialization functions have been
        called, but before connecting gtk signals."""
        pass

    def _model_set(self):
        """Called when the model is set."""
        pass

    def _presenter_set(self):
        """Called when the presenter is set."""
        pass

    def get_model(self):
        return self._model

    def set_model(self, model):
        self._model = model
        if model:
            # don't call model_set if model is None. This prevents objects
            # relying on model_set to fail (or gtk throwing a warning when
            # model is not a gtk.TreeModel).
            self._model_set()
    model = property(get_model, set_model, None, doc="The model object.")

    def get_presenter(self):
        return self._presenter

    def set_presenter(self, presenter):
        self._presenter = presenter
        self._presenter_set()
    presenter = property(get_presenter, set_presenter, None,
                         "The presenter object.")

class WidgetView(View):
    def __init__(self, widget, model=None, presenter=None):
        View.__init__(self, widget, model, presenter)

    def _connect_signals(self, widget):
        xml = glade.get_widget_tree(widget)
        nameFuncMap = {}
        for key in dir(self.__class__):
            if key[:4] == '_on_':
                nameFuncMap[key[1:]] = getattr(self, key)
        xml.signal_autoconnect(nameFuncMap)

class GladeView(View):
    def __init__(self, widget, model=None, presenter=None):
        View.__init__(self, widget, model, presenter)

    def _connect_signals(self, widget):
        nameFuncMap = {}
        for key in dir(self.__class__):
            if key[:4] == '_on_':
                nameFuncMap[key[1:]] = getattr(self, key)
        widget.signal_autoconnect(nameFuncMap)

class BasicPresenter(object, Event.SignalEmitter):
    """Base class for basic (non-composite) presenters."""
    def __init__(self, model = None, view = None):
        Event.SignalEmitter.__init__(self)

        self._model = model
        self._view = view

        if model is not None:
            self._model_set()
        if view is not None:
            view.model = model
            view.presenter = self
            self._view_set()

        self._initialize()

    def _initialize(self):
        pass

    def _model_set(self):
        pass

    def _view_set(self):
        pass

    def get_view(self):
        return self._view

    def set_view(self, view):
        self._view = view
        view.presenter = self
        view.model = self._model
        self._view_set()

    view = property(get_view, set_view, None,
                    """The view component. Setting this als sets the view
                    object's presenter and model attributes.""")

    def get_model(self):
        return self._model

    def set_model(self, model):
        self._model = model
        if self._view is not None:
            self._view.model = model
        self._model_set()

    model = property(get_model, set_model, None,
                     """The model component. Setting this also sets the view
                     object's (if defined) model attribute.""")
