#
#		Python GUI - Windows - Generic
#

import Exceptions
from Properties import overridable_property
from Containers import Container
from Applications import Application, application

class Window(Container):
    """Top-level Container."""
    
    menus = overridable_property('menus', "Menus to be available when this window is active.")
    document = overridable_property('document', "Document with which this window is associated.")
    title = overridable_property('title', "Title of the window.")
    auto_position = overridable_property('auto_position', "Whether to position automatically when first shown.")	
    target = overridable_property('target', "Current target for key events and menu messages.")
    tab_chain = overridable_property('tab_chain', "List of subcomponents in tabbing order.")

    _default_width = 200
    _default_height = 200
    _modal_styles = ('modal_dialog', 'alert')
    _dialog_styles = ('nonmodal_dialog', 'modal_dialog', 'alert')
    
    _menus = []
    _document = None
    _closable = 0
    _auto_position = True
    _tab_chain = None

    def __init__(self, style = 'standard', closable = None, **kwds):
        if closable is None:
            raise Exceptions.InternalError(
                "'closable' parameter unspecified in call to generic Window.__init__")
        Container.__init__(self, **kwds)
        self._dialog_style = style.find('dialog') >= 0
        self._closable = closable
        application()._add_window(self)

    def destroy(self):
        """Detaches the window from document and application and removes it
        from the screen."""
        self.set_document(None)
        application()._remove_window(self)
        Container.destroy(self)

    #
    #		Message handling
    #

    def next_handler(self):
        if self._document:
            return self._document
        else:
            return application()
    
    def dispatch(self, message, *args):
        self.target.handle(message, *args)

    #
    #		Menus
    #
    
    def get_menus(self):
        return self._menus

    def set_menus(self, x):
        self._menus = x

    #
    #		Document association
    #
    
    def get_document(self):
        return self._document
    
    def set_document(self, x):
        if self._document != x:
            if self._document:
                self._document._windows.remove(self)
            self._document = x
            if self._document:
                self._document._windows.append(self)
                self.update_title()

    #
    #		Title
    #
    
    def update_title(self):
        """Update the window's title after a change in its document's title."""
        doc = self._document
        if doc:
            self.set_title(doc.title)
    
    #
    #   Showing and Positioning
    #
    
    def get_auto_position(self):
        return self._auto_position
    
    def set_auto_position(self, v):
        self._auto_position = v
    
    def center(self):
        """Position the window in the centre of the screen."""
        sl, st, sr, sb = self._screen_rect()
        w, h = self.size
        l = (sr - sl - w) / 2
        t = (sb - st - h) / 2
        self.position = (l, t)
    
    def centre(self):
        self.center()

    def show(self):
        if self._auto_position:
            if self._style == 'standard':
                self._stagger()
            else:
                self.center()
            self._auto_position = False
        self._show()
    
    def _stagger(self):
        pass
    
    def _show(self):
        self.visible = True

    #
    #		Menu commands
    #

    def setup_menus(self, m):
        Container.setup_menus(self, m)
        app = application()
        if self._closable:
            if len(app._windows) > 1 or app.zero_windows_allowed():
                m.close_cmd.enabled = 1

    def close_cmd(self):
        """If this window is the only window belonging to a document,
        close the document, else destroy the window."""
        app = application()
        if len(app._windows) <= 1 and not app.zero_windows_allowed():
            #print "GWindow.close_cmd: Quitting the application" ###
            app.quit_cmd()
        else:
            doc = self._document
            if doc and len(doc._windows) <= 1:
                doc.close_cmd()
            else:
                self.destroy()
    
    #
    #   Tabbing
    #
    
    def get_tab_chain(self):
        chain = self._tab_chain
        if chain is None:
            chain = []
            self._build_tab_chain(chain)
            self._tab_chain = chain
        #print "Window.get_tab_chain:", chain ###
        return chain
    
    def _invalidate_tab_chain(self):
        self._tab_chain = None
    
    def _tab_to_next(self):
        self._tab_to(1)
    
    def _tab_to_prev(self):
        self._tab_to(-1)

    def _tab_to(self, direction):
        chain = self.tab_chain
        old_target = self.target
        new_target = None
        if chain:
            try:
                i = chain.index(old_target)
            except ValueError:
                pass
            else:
                i = (i + direction) % len(chain)
                new_target = chain[i]
        if not new_target:
            new_target = self
        if old_target:
            old_target._tab_out()
        new_target._tab_in()

    #
    #   Other
    #
    
    def get_window(self):
        return self

    def first_dispatcher(self):
        return self
