Don't ignore path when prompting for file in SaveAs()
[wxWidgets.git] / src / common / framecmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/framecmn.cpp
3 // Purpose: common (for all platforms) wxFrame functions
4 // Author: Julian Smart, Vadim Zeitlin
5 // Created: 01/02/97
6 // Id: $Id$
7 // Copyright: (c) 1998 Robert Roebling and Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #include "wx/frame.h"
27
28 #ifndef WX_PRECOMP
29 #include "wx/menu.h"
30 #include "wx/menuitem.h"
31 #include "wx/dcclient.h"
32 #include "wx/toolbar.h"
33 #include "wx/statusbr.h"
34 #endif // WX_PRECOMP
35
36 // ----------------------------------------------------------------------------
37 // event table
38 // ----------------------------------------------------------------------------
39
40 #if wxUSE_MENUS && wxUSE_STATUSBAR
41
42 BEGIN_EVENT_TABLE(wxFrameBase, wxTopLevelWindow)
43 EVT_MENU_OPEN(wxFrameBase::OnMenuOpen)
44 EVT_MENU_CLOSE(wxFrameBase::OnMenuClose)
45
46 EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight)
47 END_EVENT_TABLE()
48
49 #endif // wxUSE_MENUS && wxUSE_STATUSBAR
50
51 // ============================================================================
52 // implementation
53 // ============================================================================
54
55 // ----------------------------------------------------------------------------
56 // construction/destruction
57 // ----------------------------------------------------------------------------
58
59 wxFrameBase::wxFrameBase()
60 {
61 #if wxUSE_MENUS
62 m_frameMenuBar = NULL;
63 #endif // wxUSE_MENUS
64
65 #if wxUSE_TOOLBAR
66 m_frameToolBar = NULL;
67 #endif // wxUSE_TOOLBAR
68
69 #if wxUSE_STATUSBAR
70 m_frameStatusBar = NULL;
71 #endif // wxUSE_STATUSBAR
72
73 m_statusBarPane = 0;
74 }
75
76 wxFrameBase::~wxFrameBase()
77 {
78 // this destructor is required for Darwin
79 }
80
81 wxFrame *wxFrameBase::New(wxWindow *parent,
82 wxWindowID id,
83 const wxString& title,
84 const wxPoint& pos,
85 const wxSize& size,
86 long style,
87 const wxString& name)
88 {
89 return new wxFrame(parent, id, title, pos, size, style, name);
90 }
91
92 void wxFrameBase::DeleteAllBars()
93 {
94 #if wxUSE_MENUS
95 if ( m_frameMenuBar )
96 {
97 delete m_frameMenuBar;
98 m_frameMenuBar = (wxMenuBar *) NULL;
99 }
100 #endif // wxUSE_MENUS
101
102 #if wxUSE_STATUSBAR
103 if ( m_frameStatusBar )
104 {
105 delete m_frameStatusBar;
106 m_frameStatusBar = (wxStatusBar *) NULL;
107 }
108 #endif // wxUSE_STATUSBAR
109
110 #if wxUSE_TOOLBAR
111 if ( m_frameToolBar )
112 {
113 delete m_frameToolBar;
114 m_frameToolBar = (wxToolBar *) NULL;
115 }
116 #endif // wxUSE_TOOLBAR
117 }
118
119 bool wxFrameBase::IsOneOfBars(const wxWindow *win) const
120 {
121 #if wxUSE_MENUS
122 if ( win == GetMenuBar() )
123 return true;
124 #endif // wxUSE_MENUS
125
126 #if wxUSE_STATUSBAR
127 if ( win == GetStatusBar() )
128 return true;
129 #endif // wxUSE_STATUSBAR
130
131 #if wxUSE_TOOLBAR
132 if ( win == GetToolBar() )
133 return true;
134 #endif // wxUSE_TOOLBAR
135
136 wxUnusedVar(win);
137
138 return false;
139 }
140
141 // ----------------------------------------------------------------------------
142 // wxFrame size management: we exclude the areas taken by menu/status/toolbars
143 // from the client area, so the client area is what's really available for the
144 // frame contents
145 // ----------------------------------------------------------------------------
146
147 // get the origin of the client area in the client coordinates
148 wxPoint wxFrameBase::GetClientAreaOrigin() const
149 {
150 wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin();
151
152 #if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__)
153 wxToolBar *toolbar = GetToolBar();
154 if ( toolbar && toolbar->IsShown() )
155 {
156 int w, h;
157 toolbar->GetSize(&w, &h);
158
159 if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL )
160 {
161 pt.x += w;
162 }
163 else
164 {
165 pt.y += h;
166 }
167 }
168 #endif // wxUSE_TOOLBAR
169
170 return pt;
171 }
172
173
174 void wxFrameBase::SendSizeEvent()
175 {
176 wxSizeEvent event( GetSize(), GetId() );
177 event.SetEventObject( this );
178 GetEventHandler()->AddPendingEvent( event );
179 }
180
181
182 // ----------------------------------------------------------------------------
183 // misc
184 // ----------------------------------------------------------------------------
185
186 bool wxFrameBase::ProcessCommand(int id)
187 {
188 #if wxUSE_MENUS
189 wxMenuBar *bar = GetMenuBar();
190 if ( !bar )
191 return false;
192
193 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
194 commandEvent.SetEventObject(this);
195
196 wxMenuItem *item = bar->FindItem(id);
197 if (item)
198 {
199 if (!item->IsEnabled())
200 return true;
201
202 if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() )
203 return true;
204
205 if (item->IsCheckable())
206 {
207 item->Toggle();
208
209 // use the new value
210 commandEvent.SetInt(item->IsChecked());
211 }
212 }
213
214 GetEventHandler()->ProcessEvent(commandEvent);
215 return true;
216 #else // !wxUSE_MENUS
217 wxUnusedVar(id);
218
219 return false;
220 #endif // wxUSE_MENUS/!wxUSE_MENUS
221 }
222
223 // Do the UI update processing for this window. This is
224 // provided for the application to call if it wants to
225 // force a UI update, particularly for the menus and toolbar.
226 void wxFrameBase::UpdateWindowUI(long flags)
227 {
228 wxWindowBase::UpdateWindowUI(flags);
229
230 #if wxUSE_TOOLBAR
231 if (GetToolBar())
232 GetToolBar()->UpdateWindowUI(flags);
233 #endif
234
235 #if wxUSE_MENUS
236 if (GetMenuBar())
237 {
238 if ((flags & wxUPDATE_UI_FROMIDLE) && !wxUSE_IDLEMENUUPDATES)
239 {
240 // If coming from an idle event, we only
241 // want to update the menus if we're
242 // in the wxUSE_IDLEMENUUPDATES configuration:
243 // so if we're not, do nothing
244 }
245 else
246 DoMenuUpdates();
247 }
248 #endif // wxUSE_MENUS
249 }
250
251 // ----------------------------------------------------------------------------
252 // event handlers for status bar updates from menus
253 // ----------------------------------------------------------------------------
254
255 #if wxUSE_MENUS && wxUSE_STATUSBAR
256
257 void wxFrameBase::OnMenuHighlight(wxMenuEvent& event)
258 {
259 #if wxUSE_STATUSBAR
260 (void)ShowMenuHelp(event.GetMenuId());
261 #endif // wxUSE_STATUSBAR
262 }
263
264 #if !wxUSE_IDLEMENUUPDATES
265 void wxFrameBase::OnMenuOpen(wxMenuEvent& event)
266 #else
267 void wxFrameBase::OnMenuOpen(wxMenuEvent& WXUNUSED(event))
268 #endif
269 {
270 #if !wxUSE_IDLEMENUUPDATES
271 DoMenuUpdates(event.GetMenu());
272 #endif // !wxUSE_IDLEMENUUPDATES
273 }
274
275 void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event))
276 {
277 DoGiveHelp(wxEmptyString, false);
278 }
279
280 #endif // wxUSE_MENUS && wxUSE_STATUSBAR
281
282 // Implement internal behaviour (menu updating on some platforms)
283 void wxFrameBase::OnInternalIdle()
284 {
285 wxTopLevelWindow::OnInternalIdle();
286
287 #if wxUSE_MENUS && wxUSE_IDLEMENUUPDATES
288 if (wxUpdateUIEvent::CanUpdate(this))
289 DoMenuUpdates();
290 #endif
291 }
292
293 // ----------------------------------------------------------------------------
294 // status bar stuff
295 // ----------------------------------------------------------------------------
296
297 #if wxUSE_STATUSBAR
298
299 wxStatusBar* wxFrameBase::CreateStatusBar(int number,
300 long style,
301 wxWindowID id,
302 const wxString& name)
303 {
304 // the main status bar can only be created once (or else it should be
305 // deleted before calling CreateStatusBar() again)
306 wxCHECK_MSG( !m_frameStatusBar, (wxStatusBar *)NULL,
307 wxT("recreating status bar in wxFrame") );
308
309 SetStatusBar(OnCreateStatusBar(number, style, id, name));
310
311 return m_frameStatusBar;
312 }
313
314 wxStatusBar *wxFrameBase::OnCreateStatusBar(int number,
315 long style,
316 wxWindowID id,
317 const wxString& name)
318 {
319 wxStatusBar *statusBar = new wxStatusBar(this, id, style, name);
320
321 statusBar->SetFieldsCount(number);
322
323 return statusBar;
324 }
325
326 void wxFrameBase::SetStatusText(const wxString& text, int number)
327 {
328 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
329
330 m_frameStatusBar->SetStatusText(text, number);
331 }
332
333 void wxFrameBase::SetStatusWidths(int n, const int widths_field[] )
334 {
335 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") );
336
337 m_frameStatusBar->SetStatusWidths(n, widths_field);
338
339 PositionStatusBar();
340 }
341
342 void wxFrameBase::PushStatusText(const wxString& text, int number)
343 {
344 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
345
346 m_frameStatusBar->PushStatusText(text, number);
347 }
348
349 void wxFrameBase::PopStatusText(int number)
350 {
351 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
352
353 m_frameStatusBar->PopStatusText(number);
354 }
355
356 bool wxFrameBase::ShowMenuHelp(int menuId)
357 {
358 #if wxUSE_MENUS
359 // if no help string found, we will clear the status bar text
360 wxString helpString;
361 if ( menuId != wxID_SEPARATOR && menuId != -3 /* wxID_TITLE */ )
362 {
363 const wxMenuItem * const item = FindItemInMenuBar(menuId);
364 if ( item )
365 helpString = item->GetHelp();
366
367 // notice that it's ok if we don't find the item because it might
368 // belong to the popup menu, so don't assert here
369 }
370
371 DoGiveHelp(helpString, true);
372
373 return !helpString.empty();
374 #else // !wxUSE_MENUS
375 return false;
376 #endif // wxUSE_MENUS/!wxUSE_MENUS
377 }
378
379 void wxFrameBase::SetStatusBar(wxStatusBar *statBar)
380 {
381 bool hadBar = m_frameStatusBar != NULL;
382 m_frameStatusBar = statBar;
383
384 if ( (m_frameStatusBar != NULL) != hadBar )
385 {
386 PositionStatusBar();
387
388 DoLayout();
389 }
390 }
391
392 #endif // wxUSE_STATUSBAR
393
394 #if wxUSE_MENUS || wxUSE_TOOLBAR
395 void wxFrameBase::DoGiveHelp(const wxString& help, bool show)
396 {
397 #if wxUSE_STATUSBAR
398 if ( m_statusBarPane < 0 )
399 {
400 // status bar messages disabled
401 return;
402 }
403
404 wxStatusBar *statbar = GetStatusBar();
405 if ( !statbar )
406 return;
407
408 wxString text;
409 if ( show )
410 {
411 // remember the old status bar text if this is the first time we're
412 // called since the menu has been opened as we're going to overwrite it
413 // in our DoGiveHelp() and we want to restore it when the menu is
414 // closed
415 //
416 // note that it would be logical to do this in OnMenuOpen() but under
417 // MSW we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely
418 // enough, and so this doesn't work and instead we use the ugly trick
419 // with using special m_oldStatusText value as "menu opened" (but it is
420 // arguably better than adding yet another member variable to wxFrame
421 // on all platforms)
422 if ( m_oldStatusText.empty() )
423 {
424 m_oldStatusText = statbar->GetStatusText(m_statusBarPane);
425 if ( m_oldStatusText.empty() )
426 {
427 // use special value to prevent us from doing this the next time
428 m_oldStatusText += _T('\0');
429 }
430 }
431
432 text = help;
433 }
434 else // hide help, restore the original text
435 {
436 text = m_oldStatusText;
437 m_oldStatusText.clear();
438 }
439
440 statbar->SetStatusText(text, m_statusBarPane);
441 #else
442 wxUnusedVar(help);
443 wxUnusedVar(show);
444 #endif // wxUSE_STATUSBAR
445 }
446 #endif // wxUSE_MENUS || wxUSE_TOOLBAR
447
448
449 // ----------------------------------------------------------------------------
450 // toolbar stuff
451 // ----------------------------------------------------------------------------
452
453 #if wxUSE_TOOLBAR
454
455 wxToolBar* wxFrameBase::CreateToolBar(long style,
456 wxWindowID id,
457 const wxString& name)
458 {
459 // the main toolbar can't be recreated (unless it was explicitly deleted
460 // before)
461 wxCHECK_MSG( !m_frameToolBar, (wxToolBar *)NULL,
462 wxT("recreating toolbar in wxFrame") );
463
464 if ( style == -1 )
465 {
466 // use default style
467 //
468 // NB: we don't specify the default value in the method declaration
469 // because
470 // a) this allows us to have different defaults for different
471 // platforms (even if we don't have them right now)
472 // b) we don't need to include wx/toolbar.h in the header then
473 style = wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT;
474 }
475
476 SetToolBar(OnCreateToolBar(style, id, name));
477
478 return m_frameToolBar;
479 }
480
481 wxToolBar* wxFrameBase::OnCreateToolBar(long style,
482 wxWindowID id,
483 const wxString& name)
484 {
485 #if defined(__WXWINCE__) && defined(__POCKETPC__)
486 return new wxToolMenuBar(this, id,
487 wxDefaultPosition, wxDefaultSize,
488 style, name);
489 #else
490 return new wxToolBar(this, id,
491 wxDefaultPosition, wxDefaultSize,
492 style, name);
493 #endif
494 }
495
496 void wxFrameBase::SetToolBar(wxToolBar *toolbar)
497 {
498 bool hadBar = m_frameToolBar != NULL;
499 m_frameToolBar = toolbar;
500
501 if ( (m_frameToolBar != NULL) != hadBar )
502 {
503 PositionToolBar();
504
505 DoLayout();
506 }
507 }
508
509 #endif // wxUSE_TOOLBAR
510
511 // ----------------------------------------------------------------------------
512 // menus
513 // ----------------------------------------------------------------------------
514
515 #if wxUSE_MENUS
516
517 // update all menus
518 void wxFrameBase::DoMenuUpdates(wxMenu* menu)
519 {
520 if (menu)
521 {
522 wxEvtHandler* source = GetEventHandler();
523 menu->UpdateUI(source);
524 }
525 else
526 {
527 wxMenuBar* bar = GetMenuBar();
528 if (bar != NULL)
529 bar->UpdateMenus();
530 }
531 }
532
533 void wxFrameBase::DetachMenuBar()
534 {
535 if ( m_frameMenuBar )
536 {
537 m_frameMenuBar->Detach();
538 m_frameMenuBar = NULL;
539 }
540 }
541
542 void wxFrameBase::AttachMenuBar(wxMenuBar *menubar)
543 {
544 if ( menubar )
545 {
546 menubar->Attach((wxFrame *)this);
547 m_frameMenuBar = menubar;
548 }
549 }
550
551 void wxFrameBase::SetMenuBar(wxMenuBar *menubar)
552 {
553 if ( menubar == GetMenuBar() )
554 {
555 // nothing to do
556 return;
557 }
558
559 DetachMenuBar();
560
561 this->AttachMenuBar(menubar);
562 }
563
564 const wxMenuItem *wxFrameBase::FindItemInMenuBar(int menuId) const
565 {
566 const wxMenuBar * const menuBar = GetMenuBar();
567
568 return menuBar ? menuBar->FindItem(menuId) : NULL;
569 }
570
571 #endif // wxUSE_MENUS