Files
wxWidgets/src/generic/mdig.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

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