# -*- coding: utf-8 -*-
#----------------------------------------------------------------------------
# Name:         auimdi.py
# Purpose:
#
# Author:       Andrea Gavana <andrea.gavana@gmail.com>
#
# Created:
# Version:
# Date:         31 March 2009
# Licence:      wxWindows license
# Tags:         phoenix-port, documented
#----------------------------------------------------------------------------
__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
__date__ = "31 March 2009"


import wx

from . import auibook
from .aui_constants import *

_ = wx.GetTranslation

#-----------------------------------------------------------------------------
# AuiMDIParentFrame
#-----------------------------------------------------------------------------

class AuiMDIParentFrame(wx.Frame):

    def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
                 size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE|wx.VSCROLL|wx.HSCROLL,
                 name="AuiMDIParentFrame"):

        wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
        self.Init()

        self.Bind(wx.EVT_MENU, self.DoHandleMenu, id=wx.ID_ANY)

        # this style can be used to prevent a window from having the standard MDI
        # "Window" menu
        if not style & wx.FRAME_NO_WINDOW_MENU:

            self._pWindowMenu = wx.Menu()
            self._pWindowMenu.Append(wxWINDOWCLOSE,    _("Cl&ose"))
            self._pWindowMenu.Append(wxWINDOWCLOSEALL, _("Close All"))
            self._pWindowMenu.AppendSeparator()
            self._pWindowMenu.Append(wxWINDOWNEXT,     _("&Next"))
            self._pWindowMenu.Append(wxWINDOWPREV,     _("&Previous"))

        self._pClientWindow = self.OnCreateClient()


    def SetArtProvider(self, provider):

        if self._pClientWindow:
            self._pClientWindow.SetArtProvider(provider)


    def GetArtProvider(self):

        if not self._pClientWindow:
            return None

        return self._pClientWindow.GetArtProvider()


    def GetNotebook(self):

        return self._pClientWindow


    def SetWindowMenu(self, pMenu):

        # Replace the window menu from the currently loaded menu bar.
        pMenuBar = self.GetMenuBar()

        if self._pWindowMenu:
            self.RemoveWindowMenu(pMenuBar)
            del self._pWindowMenu
            self._pWindowMenu = None

        if pMenu:
            self._pWindowMenu = pMenu
            self.AddWindowMenu(pMenuBar)


    def GetWindowMenu(self):

        return self._pWindowMenu


    def SetMenuBar(self, pMenuBar):

        # Remove the Window menu from the old menu bar
        self.RemoveWindowMenu(self.GetMenuBar())

        # Add the Window menu to the new menu bar.
        self.AddWindowMenu(pMenuBar)

        wx.Frame.SetMenuBar(self, pMenuBar)


    def SetChildMenuBar(self, pChild):

        if not pChild:

            # No Child, set Our menu bar back.
            if self._pMyMenuBar:
                self.SetMenuBar(self._pMyMenuBar)
            else:
                self.SetMenuBar(self.GetMenuBar())

            # Make sure we know our menu bar is in use
            self._pMyMenuBar = None

        else:

            if pChild.GetMenuBar() == None:
                return

            # Do we need to save the current bar?
            if self._pMyMenuBar == None:
                self._pMyMenuBar = self.GetMenuBar()

            self.SetMenuBar(pChild.GetMenuBar())


    def ProcessEvent(self, event):

        # stops the same event being processed repeatedly
        if self._pLastEvt == event:
            return False

        self._pLastEvt = event

        # let the active child (if any) process the event first.
        res = False
        if self._pActiveChild and event.IsCommandEvent() and \
           event.GetEventObject() != self._pClientWindow and \
           event.GetEventType() not in [wx.wxEVT_ACTIVATE, wx.wxEVT_SET_FOCUS,
                                        wx.wxEVT_KILL_FOCUS, wx.wxEVT_CHILD_FOCUS,
                                        wx.wxEVT_COMMAND_SET_FOCUS, wx.wxEVT_COMMAND_KILL_FOCUS]:

            res = self._pActiveChild.GetEventHandler().ProcessEvent(event)

        if not res:

            # if the event was not handled this frame will handle it,
            # which is why we need the protection code at the beginning
            # of this method
            res = self.GetEventHandler().ProcessEvent(event)

        self._pLastEvt = None

        return res


    def GetActiveChild(self):

        return self._pActiveChild


    def SetActiveChild(self, pChildFrame):

        self._pActiveChild = pChildFrame


    def GetClientWindow(self):

        return self._pClientWindow


    def OnCreateClient(self):

        return AuiMDIClientWindow(self)


    def ActivateNext(self):

        if self._pClientWindow and self._pClientWindow.GetSelection() != wx.NOT_FOUND:

            active = self._pClientWindow.GetSelection() + 1
            if active >= self._pClientWindow.GetPageCount():
                active = 0

            self._pClientWindow.SetSelection(active)


    def ActivatePrevious(self):

        if self._pClientWindow and self._pClientWindow.GetSelection() != wx.NOT_FOUND:

            active = self._pClientWindow.GetSelection() - 1
            if active < 0:
                active = self._pClientWindow.GetPageCount() - 1

            self._pClientWindow.SetSelection(active)


    def Init(self):

        self._pLastEvt = None

        self._pClientWindow = None
        self._pActiveChild = None
        self._pWindowMenu = None
        self._pMyMenuBar = None


    def RemoveWindowMenu(self, pMenuBar):

        if pMenuBar and self._pWindowMenu:

            # Remove old window menu
            pos = pMenuBar.FindMenu(_("&Window"))
            if pos != wx.NOT_FOUND:
                pMenuBar.Remove(pos)


    def AddWindowMenu(self, pMenuBar):

        if pMenuBar and self._pWindowMenu:

            pos = pMenuBar.FindMenu(wx.GetStockLabel(wx.ID_HELP, wx.STOCK_NOFLAGS))
            if pos == wx.NOT_FOUND:
                pMenuBar.Append(self._pWindowMenu, _("&Window"))
            else:
                pMenuBar.Insert(pos, self._pWindowMenu, _("&Window"))


    def DoHandleMenu(self, event):

        evId = event.GetId()

        if evId == wxWINDOWCLOSE:
            if self._pActiveChild:
                self._pActiveChild.Close()

        elif evId == wxWINDOWCLOSEALL:

            while self._pActiveChild:
                if not self._pActiveChild.Close():
                    return # failure

        elif evId == wxWINDOWNEXT:
            self.ActivateNext()

        elif evId == wxWINDOWPREV:
            self.ActivatePrevious()

        else:
            event.Skip()


    def Tile(self, orient=wx.HORIZONTAL):

        client_window = self.GetClientWindow()
        if not client_window:
            raise Exception("Missing MDI Client Window")

        cur_idx = client_window.GetSelection()
        if cur_idx == -1:
            return

        if orient == wx.VERTICAL:

            client_window.Split(cur_idx, wx.LEFT)

        elif orient == wx.HORIZONTAL:

            client_window.Split(cur_idx, wx.TOP)


#-----------------------------------------------------------------------------
# AuiMDIChildFrame
#-----------------------------------------------------------------------------

class AuiMDIChildFrame(wx.Panel):

    def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
                 size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="AuiMDIChildFrame"):

        pClientWindow = parent.GetClientWindow()
        if pClientWindow is None:
            raise Exception("Missing MDI client window.")

        self.Init()

        # see comment in constructor
        if style & wx.MINIMIZE:
            self._activate_on_create = False

        cli_size = pClientWindow.GetClientSize()

        # create the window off-screen to prevent flicker
        wx.Panel.__init__(self, pClientWindow, id, wx.Point(cli_size.x+1, cli_size.y+1),
                            size, wx.NO_BORDER, name=name)

        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.Show(False)
        self.SetMDIParentFrame(parent)

        # this is the currently active child
        parent.SetActiveChild(self)
        self._title = title

        pClientWindow.AddPage(self, title, self._activate_on_create)
        pClientWindow.Refresh()

        self.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight)
        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)


    def Init(self):

        # There are two ways to create an tabbed mdi child fram without
        # making it the active document.  Either Show(False) can be called
        # before Create() (as is customary on some ports with wxFrame-type
        # windows), or wx.MINIMIZE can be passed in the style flags.  Note that
        # AuiMDIChildFrame is not really derived from wxFrame, as MDIChildFrame
        # is, but those are the expected symantics.  No style flag is passed
        # onto the panel underneath.

        self._activate_on_create = True

        self._pMDIParentFrame = None
        self._pMenuBar = None

        self._mdi_currect = None
        self._mdi_newrect = wx.Rect()
        self._icon = None
        self._icon_bundle = None


    def Destroy(self):

        pParentFrame = self.GetMDIParentFrame()
        if not pParentFrame:
            raise Exception("Missing MDI Parent Frame")

        pClientWindow = pParentFrame.GetClientWindow()
        if not pClientWindow:
            raise Exception("Missing MDI Client Window")

        if pParentFrame.GetActiveChild() == self:

            # deactivate ourself
            event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, False, self.GetId())
            event.SetEventObject(self)
            self.GetEventHandler().ProcessEvent(event)

            pParentFrame.SetActiveChild(None)
            pParentFrame.SetChildMenuBar(None)

        for pos in range(pClientWindow.GetPageCount()):
            if pClientWindow.GetPage(pos) == self:
                return pClientWindow.DeletePage(pos)

        return False


    def SetMenuBar(self, menu_bar):

        pOldMenuBar = self._pMenuBar
        self._pMenuBar = menu_bar

        if self._pMenuBar:

            pParentFrame = self.GetMDIParentFrame()
            if not pParentFrame:
                raise Exception("Missing MDI Parent Frame")

            self._pMenuBar.Reparent(pParentFrame)
            if pParentFrame.GetActiveChild() == self:

                # replace current menu bars
                if pOldMenuBar:
                    pParentFrame.SetChildMenuBar(None)

                pParentFrame.SetChildMenuBar(self)


    def GetMenuBar(self):

        return self._pMenuBar


    def SetTitle(self, title):

        self._title = title

        pParentFrame = self.GetMDIParentFrame()
        if not pParentFrame:
            raise Exception("Missing MDI Parent Frame")

        pClientWindow = pParentFrame.GetClientWindow()
        if pClientWindow is not None:

            for pos in range(pClientWindow.GetPageCount()):
                if pClientWindow.GetPage(pos) == self:
                    pClientWindow.SetPageText(pos, self._title)
                    break


    def GetTitle(self):

        return self._title


    def SetIcons(self, icons):

        # get icon with the system icon size
        self.SetIcon(icons.GetIcon(-1))
        self._icon_bundle = icons


    def GetIcons(self):

        return self._icon_bundle


    def SetIcon(self, icon):

        pParentFrame = self.GetMDIParentFrame()
        if not pParentFrame:
            raise Exception("Missing MDI Parent Frame")

        self._icon = icon

        bmp = wx.Bitmap(self._icon)

        pClientWindow = pParentFrame.GetClientWindow()
        if pClientWindow is not None:
            idx = pClientWindow.GetPageIndex(self)
            if idx != -1:
                pClientWindow.SetPageBitmap(idx, bmp)


    def GetIcon(self):

        return self._icon


    def Activate(self):

        pParentFrame = self.GetMDIParentFrame()
        if not pParentFrame:
            raise Exception("Missing MDI Parent Frame")

        pClientWindow = pParentFrame.GetClientWindow()
        if pClientWindow is not None:

            for pos in range(pClientWindow.GetPageCount()):
                if pClientWindow.GetPage(pos) == self:
                    pClientWindow.SetSelection(pos)
                    break


    def OnMenuHighlight(self, event):

        if self._pMDIParentFrame:

            # we don't have any help text for this item,
            # but may be the MDI frame does?
            self._pMDIParentFrame.OnMenuHighlight(event)


    def OnActivate(self, event):

        # do nothing
        pass


    def OnCloseWindow(self, event):

        pParentFrame = self.GetMDIParentFrame()
        if pParentFrame:
            if pParentFrame.GetActiveChild() == self:

                pParentFrame.SetActiveChild(None)
                pParentFrame.SetChildMenuBar(None)

            pClientWindow = pParentFrame.GetClientWindow()
            idx = pClientWindow.GetPageIndex(self)

            if idx != wx.NOT_FOUND:
                pClientWindow.RemovePage(idx)

        self.Destroy()


    def SetMDIParentFrame(self, parentFrame):

        self._pMDIParentFrame = parentFrame


    def GetMDIParentFrame(self):

        return self._pMDIParentFrame


    def CreateStatusBar(self, number=1, style=1, winid=1, name=""):

        return None


    def GetStatusBar(self):

        return None


    def SetStatusText(self, text, number=0):

        pass


    def SetStatusWidths(self, widths_field):

        pass


    # no toolbar bars
    def CreateToolBar(self, style=1, winid=-1, name=""):

        return None


    def GetToolBar(self):

        return None


    # no maximize etc
    def Maximize(self, maximize=True):

        pass


    def Restore(self):

        pass


    def Iconize(self, iconize=True):

        pass


    def IsMaximized(self):

        return True


    def IsIconized(self):

        return False


    def ShowFullScreen(self, show=True, style=0):

        return False


    def IsFullScreen(self):

        return False


    def IsTopLevel(self):

        return False


    # renamed from Show().
    def ActivateOnCreate(self, activate_on_create):

        self._activate_on_create = activate_on_create
        return True


    def Show(self, show=True):

        wx.Panel.Show(self, show)


    def ApplyMDIChildFrameRect(self):

        if self._mdi_currect != self._mdi_newrect:
            self.SetSize(*self._mdi_newrect)
            self._mdi_currect = wx.Rect(*self._mdi_newrect)


#-----------------------------------------------------------------------------
# AuiMDIClientWindow
#-----------------------------------------------------------------------------

class AuiMDIClientWindow(auibook.AuiNotebook):

    def __init__(self, parent, agwStyle=0):

        auibook.AuiNotebook.__init__(self, parent, wx.ID_ANY, wx.Point(0, 0), wx.Size(100, 100),
                                     agwStyle=AUI_NB_DEFAULT_STYLE|wx.NO_BORDER)

        caption_icon_size = wx.Size(wx.SystemSettings.GetMetric(wx.SYS_SMALLICON_X),
                                    wx.SystemSettings.GetMetric(wx.SYS_SMALLICON_Y))
        self.SetUniformBitmapSize(caption_icon_size)

        bkcolour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_APPWORKSPACE)
        self.SetOwnBackgroundColour(bkcolour)

        self._mgr.GetArtProvider().SetColour(AUI_DOCKART_BACKGROUND_COLOUR, bkcolour)

        self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnPageClose)
        self.Bind(wx.EVT_SIZE, self.OnSize)


    def SetSelection(self, nPage):

        return auibook.AuiNotebook.SetSelection(self, nPage)


    def PageChanged(self, old_selection, new_selection):

        # don't do anything if the page doesn't actually change
        if old_selection == new_selection:
            return

        # notify old active child that it has been deactivated
        if old_selection != -1 and old_selection < self.GetPageCount():

            old_child = self.GetPage(old_selection)
            if not old_child:
                raise Exception("AuiMDIClientWindow.PageChanged - null page pointer")

            event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, False, old_child.GetId())
            event.SetEventObject(old_child)
            old_child.GetEventHandler().ProcessEvent(event)

        # notify new active child that it has been activated
        if new_selection != -1:

            active_child = self.GetPage(new_selection)
            if not active_child:
                raise Exception("AuiMDIClientWindow.PageChanged - null page pointer")

            event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, True, active_child.GetId())
            event.SetEventObject(active_child)
            active_child.GetEventHandler().ProcessEvent(event)

            if active_child.GetMDIParentFrame():
                active_child.GetMDIParentFrame().SetActiveChild(active_child)
                active_child.GetMDIParentFrame().SetChildMenuBar(active_child)


    def OnPageClose(self, event):

        wnd = self.GetPage(event.GetSelection())
        wnd.Close()

        # regardless of the result of wnd.Close(), we've
        # already taken care of the close operations, so
        # suppress further processing
        event.Veto()


    def OnPageChanged(self, event):

        self.PageChanged(event.GetOldSelection(), event.GetSelection())


    def OnSize(self, event):

        auibook.AuiNotebook.OnSize(self, event)

        for pos in range(self.GetPageCount()):
            self.GetPage(pos).ApplyMDIChildFrameRect()
