]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
Refactor wxFileName existence checking code.
[wxWidgets.git] / src / gtk / mdi.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
72c23f8e 2// Name: src/gtk/mdi.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
a81258be
RR
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
88a7a4e1
WS
13#if wxUSE_MDI
14
c801d85f 15#include "wx/mdi.h"
dcf924a3 16
88a7a4e1
WS
17#ifndef WX_PRECOMP
18 #include "wx/intl.h"
3b3dc801 19 #include "wx/menu.h"
88a7a4e1 20#endif
dcf924a3 21
fab591c5 22#include "wx/gtk/private.h"
716b7364 23
5e014a0c
RR
24//-----------------------------------------------------------------------------
25// "switch_page"
26//-----------------------------------------------------------------------------
27
865bb325 28extern "C" {
f6bcfd97 29static void
385e8575 30switch_page(GtkNotebook* widget, GtkNotebookPage*, guint page_num, wxMDIParentFrame* parent)
5e014a0c 31{
e90196a5
RR
32 // send deactivate event to old child
33
5e014a0c 34 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
35 if (child)
36 {
b1d4dd7a 37 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5 38 event1.SetEventObject( child);
937013e0 39 child->HandleWindowEvent( event1 );
e90196a5 40 }
f6bcfd97 41
e90196a5 42 // send activate event to new child
f6bcfd97 43
d2824cdb
VZ
44 wxMDIClientWindowBase *client_window = parent->GetClientWindow();
45 if ( !client_window )
e90196a5
RR
46 return;
47
d2824cdb 48 child = NULL;
385e8575 49 GtkWidget* page = gtk_notebook_get_nth_page(widget, page_num);
e90196a5 50
222ed1d6 51 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
af6c0f1d 52 while ( node )
e90196a5 53 {
b1d4dd7a 54 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
b1d4dd7a 55
af6c0f1d
VZ
56 // child_frame can be NULL when this is called from dtor, probably
57 // because g_signal_connect (m_widget, "switch_page", (see below)
58 // isn't deleted early enough
385e8575 59 if (child_frame && child_frame->m_widget == page)
f6bcfd97 60 {
e90196a5 61 child = child_frame;
f6bcfd97
BP
62 break;
63 }
b1d4dd7a 64 node = node->GetNext();
e90196a5 65 }
f6bcfd97 66
e90196a5
RR
67 if (!child)
68 return;
f6bcfd97 69
b1d4dd7a 70 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5 71 event2.SetEventObject( child);
937013e0 72 child->HandleWindowEvent( event2 );
5e014a0c 73}
865bb325 74}
5e014a0c 75
6ca41e57
RR
76//-----------------------------------------------------------------------------
77// wxMDIParentFrame
33d0b396
RR
78//-----------------------------------------------------------------------------
79
c801d85f
KB
80IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
81
f6bcfd97 82void wxMDIParentFrame::Init()
c801d85f 83{
b1d4dd7a 84 m_justInserted = false;
ff7b1510 85}
c801d85f 86
f6bcfd97
BP
87bool wxMDIParentFrame::Create(wxWindow *parent,
88 wxWindowID id,
89 const wxString& title,
90 const wxPoint& pos,
91 const wxSize& size,
92 long style,
93 const wxString& name )
c801d85f 94{
6e42617a
VZ
95 if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
96 return false;
a3622daa 97
6e42617a 98 m_clientWindow = OnCreateClient();
d2824cdb
VZ
99 if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
100 return false;
a3622daa 101
d2824cdb 102 return true;
ff7b1510 103}
c801d85f 104
ab2b3dd4
RR
105void wxMDIParentFrame::OnInternalIdle()
106{
d2824cdb 107 /* if a MDI child window has just been inserted
ab2b3dd4
RR
108 it has to be brought to the top in idle time. we
109 simply set the last notebook page active as new
110 pages can only be appended at the end */
111
112 if (m_justInserted)
83624f79 113 {
a2053b27 114 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
385e8575 115 gtk_notebook_set_current_page(notebook, -1);
a0fdacee 116
147d6669 117 /* need to set the menubar of the child */
1d608029 118 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 119 if (active_child_frame != NULL)
147d6669 120 {
1b10056f
RD
121 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
122 if (menu_bar)
123 {
6abf7b63 124 menu_bar->Attach(active_child_frame);
1b10056f 125 }
147d6669 126 }
b1d4dd7a 127 m_justInserted = false;
a0fdacee 128 return;
83624f79 129 }
a0fdacee 130
ab2b3dd4 131 wxFrame::OnInternalIdle();
c626a8b7 132
ab2b3dd4 133 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 134 bool visible_child_menu = false;
a0fdacee 135
222ed1d6 136 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 137 while (node)
83624f79 138 {
b1d4dd7a
RL
139 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
140
f6bcfd97 141 if ( child_frame )
a0fdacee 142 {
f6bcfd97
BP
143 wxMenuBar *menu_bar = child_frame->m_menuBar;
144 if ( menu_bar )
f03fc89f 145 {
f6bcfd97
BP
146 if (child_frame == active_child_frame)
147 {
b1d4dd7a 148 if (menu_bar->Show(true))
f6bcfd97 149 {
6abf7b63
VZ
150 // Attach() asserts if we call it for an already
151 // attached menu bar so don't do it if we're already
152 // associated with this frame (it would be nice to get
153 // rid of this check and ensure that this doesn't
154 // happen...)
155 if ( menu_bar->GetFrame() != child_frame )
156 menu_bar->Attach( child_frame );
f6bcfd97 157 }
b1d4dd7a 158 visible_child_menu = true;
f6bcfd97
BP
159 }
160 else
161 {
b1d4dd7a 162 if (menu_bar->Show(false))
f6bcfd97 163 {
6abf7b63 164 menu_bar->Detach();
f6bcfd97
BP
165 }
166 }
f03fc89f 167 }
a0fdacee 168 }
f6bcfd97 169
b1d4dd7a 170 node = node->GetNext();
83624f79 171 }
a0fdacee 172
e27ce4e9 173 /* show/hide parent menu bar as required */
5bd9e519
RR
174 if ((m_frameMenuBar) &&
175 (m_frameMenuBar->IsShown() == visible_child_menu))
176 {
177 if (visible_child_menu)
f6bcfd97 178 {
b1d4dd7a 179 m_frameMenuBar->Show( false );
6abf7b63 180 m_frameMenuBar->Detach();
f6bcfd97
BP
181 }
182 else
183 {
b1d4dd7a 184 m_frameMenuBar->Show( true );
6abf7b63 185 m_frameMenuBar->Attach( this );
cca410b3
PC
186 }
187 }
188}
f6bcfd97 189
cca410b3
PC
190void wxMDIParentFrame::DoGetClientSize(int* width, int* height) const
191{
192 wxFrame::DoGetClientSize(width, height);
193
194 if (height)
195 {
196 wxMDIChildFrame* active_child_frame = GetActiveChild();
197 if (active_child_frame)
198 {
199 wxMenuBar* menubar = active_child_frame->m_menuBar;
200 if (menubar && menubar->IsShown())
201 {
202 GtkRequisition req;
203 gtk_widget_size_request(menubar->m_widget, &req);
204 *height -= req.height;
205 if (*height < 0) *height = 0;
206 }
f6bcfd97 207 }
5bd9e519 208 }
ff7b1510 209}
716b7364 210
ab2b3dd4
RR
211wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
212{
d2824cdb 213 if (!m_clientWindow) return NULL;
a0fdacee 214
a2053b27 215 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
d2824cdb 216 if (!notebook) return NULL;
a0fdacee 217
ab2b3dd4 218 gint i = gtk_notebook_get_current_page( notebook );
d2824cdb 219 if (i < 0) return NULL;
f4322df6 220
385e8575 221 GtkWidget* page = gtk_notebook_get_nth_page(notebook, i);
d2824cdb 222 if (!page) return NULL;
a0fdacee 223
222ed1d6 224 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
225 while (node)
226 {
3811dacb 227 if ( wxPendingDelete.Member(node->GetData()) )
d2824cdb 228 return NULL;
f4322df6 229
b1d4dd7a
RL
230 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
231
3811dacb 232 if (!child_frame)
d2824cdb 233 return NULL;
b1d4dd7a 234
385e8575 235 if (child_frame->m_widget == page)
ab2b3dd4 236 return child_frame;
f4322df6 237
b1d4dd7a 238 node = node->GetNext();
ab2b3dd4 239 }
a0fdacee 240
d2824cdb 241 return NULL;
ff7b1510 242}
c801d85f 243
ab2b3dd4 244void wxMDIParentFrame::ActivateNext()
c801d85f 245{
83624f79 246 if (m_clientWindow)
a2053b27 247 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 248}
c801d85f 249
ab2b3dd4 250void wxMDIParentFrame::ActivatePrevious()
716b7364 251{
83624f79 252 if (m_clientWindow)
a2053b27 253 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 254}
716b7364 255
c801d85f
KB
256//-----------------------------------------------------------------------------
257// wxMDIChildFrame
258//-----------------------------------------------------------------------------
259
cf4219e7 260IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 261
cf4219e7 262BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 263 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 264 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
265END_EVENT_TABLE()
266
d2824cdb 267void wxMDIChildFrame::Init()
c801d85f 268{
d2824cdb 269 m_menuBar = NULL;
ff7b1510 270}
c801d85f 271
d2824cdb
VZ
272bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
273 wxWindowID id,
274 const wxString& title,
275 const wxPoint& WXUNUSED(pos),
276 const wxSize& size,
277 long style,
278 const wxString& name)
c801d85f 279{
d2824cdb
VZ
280 m_mdiParent = parent;
281 m_title = title;
282
283 return wxWindow::Create(parent->GetClientWindow(), id,
284 wxDefaultPosition, size,
285 style, name);
ff7b1510 286}
c801d85f 287
ab2b3dd4 288wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 289{
d2824cdb 290 delete m_menuBar;
002626c5
PC
291
292 // wxMDIClientWindow does not get redrawn properly after last child is removed
293 if (m_parent && m_parent->GetChildren().size() <= 1)
294 gtk_widget_queue_draw(m_parent->m_widget);
72c23f8e 295}
c801d85f 296
3ec3c160
PC
297void wxMDIChildFrame::GTKHandleRealized()
298{
299 // since m_widget is not a GtkWindow, must bypass wxTopLevelWindowGTK
300 wxTopLevelWindowBase::GTKHandleRealized();
301}
302
716b7364
RR
303void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
304{
d2824cdb 305 wxASSERT_MSG( m_menuBar == NULL, "Only one menubar allowed" );
5bd9e519 306
83624f79 307 m_menuBar = menu_bar;
a3622daa 308
83624f79 309 if (m_menuBar)
716b7364 310 {
f03fc89f 311 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 312
5bd9e519 313 m_menuBar->SetParent( mdi_frame );
c626a8b7 314
ab2b3dd4 315 /* insert the invisible menu bar into the _parent_ mdi frame */
cca410b3
PC
316 m_menuBar->Show(false);
317 gtk_box_pack_start(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, false, false, 0);
318 gtk_box_reorder_child(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0);
319
320 gulong handler_id = g_signal_handler_find(
321 m_menuBar->m_widget,
322 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
323 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
324 0, NULL, NULL, m_menuBar);
325 if (handler_id != 0)
326 g_signal_handler_disconnect(m_menuBar->m_widget, handler_id);
327 gtk_widget_set_size_request(m_menuBar->m_widget, -1, -1);
716b7364 328 }
ff7b1510 329}
cf4219e7 330
33b64e6f 331wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 332{
83624f79 333 return m_menuBar;
ff7b1510 334}
c801d85f 335
d2824cdb
VZ
336GtkNotebook *wxMDIChildFrame::GTKGetNotebook() const
337{
338 wxMDIClientWindow * const
339 client = wxStaticCast(GetParent(), wxMDIClientWindow);
340 wxCHECK( client, NULL );
341
342 return GTK_NOTEBOOK(client->m_widget);
343}
344
ab2b3dd4 345void wxMDIChildFrame::Activate()
c801d85f 346{
d2824cdb
VZ
347 GtkNotebook * const notebook = GTKGetNotebook();
348 wxCHECK_RET( notebook, "no parent notebook?" );
349
9e691f46 350 gint pageno = gtk_notebook_page_num( notebook, m_widget );
38f1df7c 351 gtk_notebook_set_current_page( notebook, pageno );
ff7b1510 352}
c801d85f 353
f6bcfd97
BP
354void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
355{
356}
357
358void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 359{
f6bcfd97
BP
360#if wxUSE_STATUSBAR
361 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 362 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
363 {
364 // we don't have any help text for this item, but may be the MDI frame
365 // does?
366 mdi_frame->OnMenuHighlight(event);
367 }
368#endif // wxUSE_STATUSBAR
369}
370
371void wxMDIChildFrame::SetTitle( const wxString &title )
372{
373 if ( title == m_title )
374 return;
375
376 m_title = title;
377
d2824cdb
VZ
378 GtkNotebook * const notebook = GTKGetNotebook();
379 wxCHECK_RET( notebook, "no parent notebook?" );
fab591c5 380 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 381}
9746a2ba 382
c801d85f
KB
383//-----------------------------------------------------------------------------
384// wxMDIClientWindow
385//-----------------------------------------------------------------------------
386
d2824cdb 387IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
c801d85f 388
5a0a15cf
FM
389wxMDIClientWindow::~wxMDIClientWindow()
390{
391 // disconnect our handler because our ~wxWindow (which is going to be called
392 // after this dtor) will call DestroyChildren(); in turns our children
393 // ~wxWindow dtors will call wxWindow::Show(false) and this will generate
394 // a call to gtk_mdi_page_change_callback with an invalid parent
395 // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but
396 // at that point of the dtor chain we are a simple wxWindow!)
385e8575 397 g_signal_handlers_disconnect_by_func(m_widget, (void*)switch_page, GetParent());
5a0a15cf
FM
398}
399
d2824cdb 400bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
c801d85f 401{
d2824cdb
VZ
402 if ( !PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
403 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
404 style, wxDefaultValidator, "wxMDIClientWindow" ))
4dcaf11a 405 {
d2824cdb 406 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
b1d4dd7a 407 return false;
4dcaf11a 408 }
c801d85f 409
83624f79 410 m_widget = gtk_notebook_new();
9ff9d30c 411 g_object_ref(m_widget);
a3622daa 412
385e8575 413 g_signal_connect(m_widget, "switch_page", G_CALLBACK(switch_page), parent);
5e014a0c 414
83624f79 415 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 416
f03fc89f 417 m_parent->DoAddChild( this );
c626a8b7 418
83624f79 419 PostCreation();
a3622daa 420
b1d4dd7a 421 Show( true );
a3622daa 422
b1d4dd7a 423 return true;
ff7b1510 424}
c801d85f 425
d2824cdb
VZ
426void wxMDIClientWindow::AddChildGTK(wxWindowGTK* child)
427{
428 wxMDIChildFrame* child_frame = static_cast<wxMDIChildFrame*>(child);
429 wxString s = child_frame->GetTitle();
430 if ( s.empty() )
431 s = _("MDI child");
432
433 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
434 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
435
436 GtkNotebook* notebook = GTK_NOTEBOOK(m_widget);
437
438 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
439
d2824cdb
VZ
440 wxMDIParentFrame* parent_frame = static_cast<wxMDIParentFrame*>(GetParent());
441 parent_frame->m_justInserted = true;
442}
443
e8375af8 444#endif // wxUSE_MDI