dolphin/Externals/wxWidgets3/src/generic/mdig.cpp

643 lines
17 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/generic/mdig.cpp
// Purpose: Generic MDI (Multiple Document Interface) classes
// Author: Hans Van Leemputten
// Modified by: 2008-10-31 Vadim Zeitlin: derive from the base classes
// Created: 29/07/2002
// Copyright: (c) 2002 Hans Van Leemputten
// (c) 2008 Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_MDI
#ifndef WX_PRECOMP
#include "wx/menu.h"
#include "wx/intl.h"
#include "wx/log.h"
#endif //WX_PRECOMP
#include "wx/mdi.h"
#include "wx/generic/mdig.h"
#include "wx/notebook.h"
#include "wx/scopeguard.h"
#include "wx/stockitem.h"
enum MDI_MENU_ID
{
wxWINDOWCLOSE = 4001,
wxWINDOWCLOSEALL,
wxWINDOWNEXT,
wxWINDOWPREV
};
//-----------------------------------------------------------------------------
// wxGenericMDIParentFrame
//-----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIParentFrame, wxFrame)
BEGIN_EVENT_TABLE(wxGenericMDIParentFrame, wxFrame)
EVT_CLOSE(wxGenericMDIParentFrame::OnClose)
#if wxUSE_MENUS
EVT_MENU(wxID_ANY, wxGenericMDIParentFrame::OnWindowMenu)
#endif
END_EVENT_TABLE()
void wxGenericMDIParentFrame::Init()
{
#if wxUSE_MENUS
m_pMyMenuBar = NULL;
#endif // wxUSE_MENUS
}
wxGenericMDIParentFrame::~wxGenericMDIParentFrame()
{
// Make sure the client window is destructed before the menu bars are!
wxDELETE(m_clientWindow);
#if wxUSE_MENUS
wxDELETE(m_pMyMenuBar);
RemoveWindowMenu(GetMenuBar());
#endif // wxUSE_MENUS
}
bool wxGenericMDIParentFrame::Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
// this style can be used to prevent a window from having the standard MDI
// "Window" menu
if ( !(style & wxFRAME_NO_WINDOW_MENU) )
{
#if wxUSE_MENUS
m_windowMenu = new wxMenu;
m_windowMenu->Append(wxWINDOWCLOSE, _("Cl&ose"));
m_windowMenu->Append(wxWINDOWCLOSEALL, _("Close All"));
m_windowMenu->AppendSeparator();
m_windowMenu->Append(wxWINDOWNEXT, _("&Next"));
m_windowMenu->Append(wxWINDOWPREV, _("&Previous"));
#endif // wxUSE_MENUS
}
// the scrolling styles don't make sense neither for us nor for our client
// window (to which they're supposed to apply)
style &= ~(wxHSCROLL | wxVSCROLL);
if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
return false;
wxGenericMDIClientWindow * const client = OnCreateGenericClient();
if ( !client->CreateGenericClient(this) )
return false;
m_clientWindow = client;
return true;
}
wxGenericMDIClientWindow *wxGenericMDIParentFrame::OnCreateGenericClient()
{
return new wxGenericMDIClientWindow;
}
bool wxGenericMDIParentFrame::CloseAll()
{
wxGenericMDIClientWindow * const client = GetGenericClientWindow();
if ( !client )
return true; // none of the windows left
wxBookCtrlBase * const book = client->GetBookCtrl();
while ( book->GetPageCount() )
{
wxGenericMDIChildFrame * const child = client->GetChild(0);
if ( !child->Close() )
{
// it refused to close, don't close the remaining ones neither
return false;
}
}
return true;
}
#if wxUSE_MENUS
void wxGenericMDIParentFrame::SetWindowMenu(wxMenu* pMenu)
{
// Replace the window menu from the currently loaded menu bar.
wxMenuBar *pMenuBar = GetMenuBar();
if (m_windowMenu)
{
RemoveWindowMenu(pMenuBar);
wxDELETE(m_windowMenu);
}
if (pMenu)
{
m_windowMenu = pMenu;
AddWindowMenu(pMenuBar);
}
}
void wxGenericMDIParentFrame::SetMenuBar(wxMenuBar *pMenuBar)
{
// Remove the Window menu from the old menu bar
RemoveWindowMenu(GetMenuBar());
// Add the Window menu to the new menu bar.
AddWindowMenu(pMenuBar);
wxFrame::SetMenuBar(pMenuBar);
}
#endif // wxUSE_MENUS
void wxGenericMDIParentFrame::WXSetChildMenuBar(wxGenericMDIChildFrame *pChild)
{
#if wxUSE_MENUS
if (pChild == NULL)
{
// No Child, set Our menu bar back.
SetMenuBar(m_pMyMenuBar);
// Make sure we know our menu bar is in use
m_pMyMenuBar = NULL;
}
else
{
if (pChild->GetMenuBar() == NULL)
return;
// Do we need to save the current bar?
if (m_pMyMenuBar == NULL)
m_pMyMenuBar = GetMenuBar();
SetMenuBar(pChild->GetMenuBar());
}
#endif // wxUSE_MENUS
}
wxGenericMDIClientWindow *
wxGenericMDIParentFrame::GetGenericClientWindow() const
{
return static_cast<wxGenericMDIClientWindow *>(m_clientWindow);
}
wxBookCtrlBase *wxGenericMDIParentFrame::GetBookCtrl() const
{
wxGenericMDIClientWindow * const client = GetGenericClientWindow();
return client ? client->GetBookCtrl() : NULL;
}
void wxGenericMDIParentFrame::AdvanceActive(bool forward)
{
wxBookCtrlBase * const book = GetBookCtrl();
if ( book )
book->AdvanceSelection(forward);
}
void wxGenericMDIParentFrame::WXUpdateChildTitle(wxGenericMDIChildFrame *child)
{
wxGenericMDIClientWindow * const client = GetGenericClientWindow();
const int pos = client->FindChild(child);
if ( pos == wxNOT_FOUND )
return;
client->GetBookCtrl()->SetPageText(pos, child->GetTitle());
}
void wxGenericMDIParentFrame::WXActivateChild(wxGenericMDIChildFrame *child)
{
wxGenericMDIClientWindow * const client = GetGenericClientWindow();
const int pos = client->FindChild(child);
if ( pos == wxNOT_FOUND )
return;
client->GetBookCtrl()->SetSelection(pos);
}
void wxGenericMDIParentFrame::WXRemoveChild(wxGenericMDIChildFrame *child)
{
const bool removingActive = WXIsActiveChild(child);
if ( removingActive )
{
SetActiveChild(NULL);
WXSetChildMenuBar(NULL);
}
wxGenericMDIClientWindow * const client = GetGenericClientWindow();
wxCHECK_RET( client, "should have client window" );
wxBookCtrlBase * const book = client->GetBookCtrl();
// Remove page if still there
int pos = client->FindChild(child);
if ( pos != wxNOT_FOUND )
{
if ( book->RemovePage(pos) )
book->Refresh();
}
if ( removingActive )
{
// Set the new selection to a remaining page
const size_t count = book->GetPageCount();
if ( count > (size_t)pos )
{
book->SetSelection(pos);
}
else
{
if ( count > 0 )
book->SetSelection(count - 1);
}
}
}
bool
wxGenericMDIParentFrame::WXIsActiveChild(wxGenericMDIChildFrame *child) const
{
return static_cast<wxMDIChildFrameBase *>(GetActiveChild()) == child;
}
#if wxUSE_MENUS
void wxGenericMDIParentFrame::RemoveWindowMenu(wxMenuBar *pMenuBar)
{
if (pMenuBar && m_windowMenu)
{
// Remove old window menu
int pos = pMenuBar->FindMenu(_("&Window"));
if (pos != wxNOT_FOUND)
{
wxASSERT(m_windowMenu == pMenuBar->GetMenu(pos)); // DBG:: We're going to delete the wrong menu!!!
pMenuBar->Remove(pos);
}
}
}
void wxGenericMDIParentFrame::AddWindowMenu(wxMenuBar *pMenuBar)
{
if (pMenuBar && m_windowMenu)
{
int pos = pMenuBar->FindMenu(wxGetStockLabel(wxID_HELP,false));
if (pos == wxNOT_FOUND)
{
pMenuBar->Append(m_windowMenu, _("&Window"));
}
else
{
pMenuBar->Insert(pos, m_windowMenu, _("&Window"));
}
}
}
void wxGenericMDIParentFrame::OnWindowMenu(wxCommandEvent &event)
{
switch ( event.GetId() )
{
case wxWINDOWCLOSE:
if ( m_currentChild )
m_currentChild->Close();
break;
case wxWINDOWCLOSEALL:
CloseAll();
break;
case wxWINDOWNEXT:
ActivateNext();
break;
case wxWINDOWPREV:
ActivatePrevious();
break;
default:
event.Skip();
}
}
#endif // wxUSE_MENUS
void wxGenericMDIParentFrame::OnClose(wxCloseEvent& event)
{
if ( !CloseAll() )
event.Veto();
else
event.Skip();
}
bool wxGenericMDIParentFrame::ProcessEvent(wxEvent& event)
{
if ( m_currentChild )
{
// the menu events should be given to the child as we show its menu bar
// as our own
const wxEventType eventType = event.GetEventType();
if ( eventType == wxEVT_MENU ||
eventType == wxEVT_UPDATE_UI )
{
// set the flag indicating that this event was forwarded to the
// child from the parent and so shouldn't be propagated upwards if
// not processed to avoid infinite loop
m_childHandler = m_currentChild;
wxON_BLOCK_EXIT_NULL(m_childHandler);
if ( m_currentChild->ProcessWindowEvent(event) )
return true;
}
}
return wxMDIParentFrameBase::ProcessEvent(event);
}
// ----------------------------------------------------------------------------
// wxGenericMDIChildFrame
// ----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIChildFrame, wxFrame)
BEGIN_EVENT_TABLE(wxGenericMDIChildFrame, wxFrame)
EVT_MENU_HIGHLIGHT_ALL(wxGenericMDIChildFrame::OnMenuHighlight)
EVT_CLOSE(wxGenericMDIChildFrame::OnClose)
END_EVENT_TABLE()
void wxGenericMDIChildFrame::Init()
{
#if wxUSE_MENUS
m_pMenuBar = NULL;
#endif // wxUSE_MENUS
#if !wxUSE_GENERIC_MDI_AS_NATIVE
m_mdiParentGeneric = NULL;
#endif
}
wxGenericMDIChildFrame::~wxGenericMDIChildFrame()
{
wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
// it could happen that we don't have a valid parent if we hadn't been ever
// really created -- but in this case there is nothing else to do neither
if ( parent )
parent->WXRemoveChild(this);
#if wxUSE_MENUS
delete m_pMenuBar;
#endif // wxUSE_MENUS
}
bool wxGenericMDIChildFrame::Create(wxGenericMDIParentFrame *parent,
wxWindowID id,
const wxString& title,
const wxPoint& WXUNUSED(pos),
const wxSize& size,
long WXUNUSED(style),
const wxString& name)
{
// unfortunately we can't use the base class m_mdiParent field unless
// wxGenericMDIParentFrame is wxMDIParentFrame
#if wxUSE_GENERIC_MDI_AS_NATIVE
m_mdiParent = parent;
#else // generic != native
// leave m_mdiParent NULL, we don't have it
m_mdiParentGeneric = parent;
#endif
wxBookCtrlBase * const book = parent->GetBookCtrl();
wxASSERT_MSG( book, "Missing MDI client window." );
// note that we ignore the styles, none of the usual TLW styles apply to
// this (child) window
if ( !wxWindow::Create(book, id, wxDefaultPosition, size, 0, name) )
return false;
m_title = title;
book->AddPage(this, title, true);
return true;
}
#if wxUSE_MENUS
void wxGenericMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
{
wxMenuBar *pOldMenuBar = m_pMenuBar;
m_pMenuBar = menu_bar;
if (m_pMenuBar)
{
wxGenericMDIParentFrame *parent = GetGenericMDIParent();
if ( parent )
{
m_pMenuBar->SetParent(parent);
if ( parent->WXIsActiveChild(this) )
{
// Replace current menu bars
if (pOldMenuBar)
parent->WXSetChildMenuBar(NULL);
parent->WXSetChildMenuBar(this);
}
}
}
}
wxMenuBar *wxGenericMDIChildFrame::GetMenuBar() const
{
return m_pMenuBar;
}
#endif // wxUSE_MENUS
void wxGenericMDIChildFrame::SetTitle(const wxString& title)
{
m_title = title;
wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
if ( parent )
parent->WXUpdateChildTitle(this);
//else: it's ok, we might be not created yet
}
void wxGenericMDIChildFrame::Activate()
{
wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
wxCHECK_RET( parent, "can't activate MDI child without parent" );
parent->WXActivateChild(this);
}
void wxGenericMDIChildFrame::OnMenuHighlight(wxMenuEvent& event)
{
wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
if ( parent)
{
// we don't have any help text for this item,
// but may be the MDI frame does?
parent->OnMenuHighlight(event);
}
}
void wxGenericMDIChildFrame::OnClose(wxCloseEvent& WXUNUSED(event))
{
// we're not a TLW so don't delay the destruction of this window
delete this;
}
bool wxGenericMDIChildFrame::TryAfter(wxEvent& event)
{
// we shouldn't propagate the event to the parent if we received it from it
// in the first place
wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
if ( parent && parent->WXIsInsideChildHandler(this) )
return false;
return wxTDIChildFrame::TryAfter(event);
}
// ----------------------------------------------------------------------------
// wxGenericMDIClientWindow
// ----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIClientWindow, wxWindow)
bool
wxGenericMDIClientWindow::CreateGenericClient(wxWindow *parent)
{
if ( !wxWindow::Create(parent, wxID_ANY) )
return false;
m_notebook = new wxNotebook(this, wxID_ANY);
m_notebook->Connect
(
wxEVT_NOTEBOOK_PAGE_CHANGED,
wxNotebookEventHandler(
wxGenericMDIClientWindow::OnPageChanged),
NULL,
this
);
// now that we have a notebook to resize, hook up OnSize() too
Connect(wxEVT_SIZE, wxSizeEventHandler(wxGenericMDIClientWindow::OnSize));
return true;
}
wxBookCtrlBase *wxGenericMDIClientWindow::GetBookCtrl() const
{
return m_notebook;
}
wxGenericMDIChildFrame *wxGenericMDIClientWindow::GetChild(size_t pos) const
{
return static_cast<wxGenericMDIChildFrame *>(GetBookCtrl()->GetPage(pos));
}
int wxGenericMDIClientWindow::FindChild(wxGenericMDIChildFrame *child) const
{
wxBookCtrlBase * const book = GetBookCtrl();
const size_t count = book->GetPageCount();
for ( size_t pos = 0; pos < count; pos++ )
{
if ( book->GetPage(pos) == child )
return pos;
}
return wxNOT_FOUND;
}
void wxGenericMDIClientWindow::PageChanged(int oldSelection, int newSelection)
{
// Don't do anything if nothing changed
if (oldSelection == newSelection)
return;
// Again check if we really need to do this...
if (newSelection != -1)
{
wxGenericMDIChildFrame * const child = GetChild(newSelection);
if ( child->GetGenericMDIParent()->WXIsActiveChild(child) )
return;
}
// Notify old active child that it has been deactivated
if (oldSelection != -1)
{
wxGenericMDIChildFrame * const oldChild = GetChild(oldSelection);
if (oldChild)
{
wxActivateEvent event(wxEVT_ACTIVATE, false, oldChild->GetId());
event.SetEventObject( oldChild );
oldChild->GetEventHandler()->ProcessEvent(event);
}
}
// Notify new active child that it has been activated
if (newSelection != -1)
{
wxGenericMDIChildFrame * const activeChild = GetChild(newSelection);
if ( activeChild )
{
wxActivateEvent event(wxEVT_ACTIVATE, true, activeChild->GetId());
event.SetEventObject( activeChild );
activeChild->GetEventHandler()->ProcessEvent(event);
wxGenericMDIParentFrame * const
parent = activeChild->GetGenericMDIParent();
if ( parent )
{
// this is a dirty hack as activeChild is not really a
// wxMDIChildFrame at all but we still want to store it in the
// base class m_currentChild field and this will work as long
// as we only use as wxMDIChildFrameBase pointer (which it is)
parent->SetActiveChild(
reinterpret_cast<wxMDIChildFrame *>(activeChild));
parent->WXSetChildMenuBar(activeChild);
}
}
}
}
void wxGenericMDIClientWindow::OnPageChanged(wxBookCtrlEvent& event)
{
PageChanged(event.GetOldSelection(), event.GetSelection());
event.Skip();
}
void wxGenericMDIClientWindow::OnSize(wxSizeEvent& WXUNUSED(event))
{
m_notebook->SetSize(GetClientSize());
}
#endif // wxUSE_MDI