if wxUSE_XXX fixes
[wxWidgets.git] / src / cocoa / mdi.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        cocoa/mdi.mm
3 // Purpose:     wxMDIParentFrame, wxMDIChildFrame, wxMDIClientWindow
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2003/09/08
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2003 David Elliott
9 // Licence:     wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_MDI
15
16 #ifndef WX_PRECOMP
17     #include "wx/log.h"
18     #include "wx/mdi.h"
19 #endif // WX_PRECOMP
20
21 // #include "wx/cocoa/autorelease.h"
22 #include "wx/cocoa/mbarman.h"
23
24 #import <AppKit/NSWindow.h>
25 #import <Foundation/NSNotification.h>
26 // #import <AppKit/NSApplication.h>
27 // #import <AppKit/NSView.h>
28
29 #include "wx/listimpl.cpp"
30 WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
31
32 WX_DECLARE_HASH_MAP(int, wxMDIChildFrame*, wxIntegerHash, wxIntegerEqual, wxIntMDIChildFrameHashMap);
33
34 // ============================================================================
35 // wxMDIParentFrameObserver
36 // ============================================================================
37 @interface wxMDIParentFrameObserver : NSObject
38 {
39     wxMDIParentFrame *m_mdiParent;
40 }
41
42 - (id)init;
43 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent;
44 - (void)windowDidBecomeMain: (NSNotification *)notification;
45 @end // interface wxMDIParentFrameObserver : NSObject
46
47 @implementation wxMDIParentFrameObserver : NSObject
48 - (id)init
49 {
50     wxFAIL_MSG(wxT("[wxMDIParentFrameObserver -init] should never be called!"));
51     m_mdiParent = NULL;
52     return self;
53 }
54
55 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent
56 {
57     wxASSERT(mdiParent);
58     m_mdiParent = mdiParent;
59     return [super init];
60 }
61
62 - (void)windowDidBecomeMain: (NSNotification *)notification
63 {
64     wxASSERT(m_mdiParent);
65     m_mdiParent->WindowDidBecomeMain(notification);
66 }
67
68 @end // implementation wxMDIParentFrameObserver : NSObject
69
70 // ========================================================================
71 // wxMDIParentFrame
72 // ========================================================================
73 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
74 BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
75 END_EVENT_TABLE()
76
77 void wxMDIParentFrame::Init()
78 {
79     m_clientWindow = NULL;
80     m_currentChild = NULL;
81     m_observer = [[wxMDIParentFrameObserver alloc]
82             initWithWxMDIParentFrame:this];
83     [[NSNotificationCenter defaultCenter] addObserver:m_observer
84             selector:@selector(windowDidBecomeMain:)
85             name:NSWindowDidBecomeMainNotification object:nil];
86 }
87
88 bool wxMDIParentFrame::Create(wxWindow *parent,
89         wxWindowID winid, const wxString& title,
90         const wxPoint& pos, const wxSize& size,
91         long style, const wxString& name)
92 {
93     bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
94     if(success)
95         OnCreateClient();
96     return success;
97 }
98
99 wxMDIParentFrame::~wxMDIParentFrame()
100 {
101     for(wxCocoaMDIChildFrameList::compatibility_iterator node =
102             m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst())
103     {
104         wxMDIChildFrame *child = node->GetData();
105         // Delete it NOW
106         delete child;
107         wxASSERT_MSG(!m_mdiChildren.Find(child),
108             wxT("MDI child didn't remove itself using RemoveMDIChild()"));
109     }
110     [m_observer release];
111 }
112
113 void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
114 {
115     m_mdiChildren.Append(child);
116 }
117
118 void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
119 {
120     m_mdiChildren.DeleteObject(child);
121     if(child==m_currentChild)
122         SetActiveChild(NULL);
123 }
124
125 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
126 {
127     return m_currentChild;
128 }
129
130 void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
131 {
132     m_currentChild = child;
133     wxMenuBarManager::GetInstance()->UpdateMenuBar();
134 }
135
136 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
137 {
138     return m_clientWindow;
139 }
140
141 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
142 {
143     m_clientWindow = new wxMDIClientWindow( this );
144     return m_clientWindow;
145 }
146
147 void wxMDIParentFrame::ActivateNext()
148 {
149 }
150
151 void wxMDIParentFrame::ActivatePrevious()
152 {
153 }
154
155 wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
156 {
157     if(m_currentChild && (win==this))
158         return m_currentChild->GetAppMenuBar(win);
159     return wxFrame::GetAppMenuBar(win);
160 }
161
162 void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
163 {
164     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
165     if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild)
166     {
167         sm_cocoaDeactivateWindow = NULL;
168     }
169     #if 0
170     else if(sm_cocoaDeactivateWindow == this)
171     {
172         sm_cocoaDeactivateWindow = NULL;
173     }
174     #endif
175     else
176     {
177         if(m_currentChild)
178         {
179             NSWindow *nswin = m_currentChild->GetNSWindow();
180             if(![nswin isMainWindow])
181                 [nswin makeMainWindow];
182         }
183         wxFrame::CocoaDelegate_windowDidBecomeKey();
184     }
185 }
186
187 void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
188 {
189     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
190     if(m_closed)
191         wxFrame::CocoaDelegate_windowDidResignKey();
192     else
193         sm_cocoaDeactivateWindow = this;
194 }
195
196 // We should not become the main window as we aren't a document window
197 // MDI "Children" should be the main window
198 bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome)
199 {
200     canBecome = m_mdiChildren.IsEmpty(); return true;
201 }
202
203 void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification)
204 {
205     // If we aren't the key window, we don't care
206     if(![m_cocoaNSWindow isKeyWindow])
207         return;
208     wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
209     // If we are key and becoming main, that's great
210     if(win==this)
211         return;
212     // If one of our children is becoming main, also great
213     for(wxCocoaMDIChildFrameList::compatibility_iterator node =
214             m_mdiChildren.GetFirst(); node; node = node->GetNext())
215     {
216         wxMDIChildFrame *child = node->GetData();
217         if(win==child)
218             return;
219     }
220     // Some other window is becoming main, but we are key
221     // Make the new main window the key window
222     [[notification object] makeKeyWindow];
223     if(!m_currentChild)
224     {
225         wxIntMDIChildFrameHashMap hashmap;
226         for(wxCocoaMDIChildFrameList::compatibility_iterator node =
227                 m_mdiChildren.GetFirst(); node; node = node->GetNext())
228         {
229             wxMDIChildFrame *child = node->GetData();
230             hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child));
231         }
232         if(!hashmap.empty())
233         {
234             int windowCount = 0;
235             NSCountWindows(&windowCount);
236             wxASSERT(windowCount>0);
237             int *windowList = new int[windowCount];
238             NSWindowList(windowCount, windowList);
239             wxIntMDIChildFrameHashMap::iterator iter = hashmap.end();
240             for(int i=0; i<windowCount && iter == hashmap.end(); i++)
241                 iter=hashmap.find(windowList[i]);
242             if(iter != hashmap.end())
243                 m_currentChild = iter->second;
244         }
245     }
246 }
247
248 // ========================================================================
249 // wxMDIChildFrame
250 // ========================================================================
251 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
252 BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
253 END_EVENT_TABLE()
254
255 void wxMDIChildFrame::Init()
256 {
257     m_mdiParent = NULL;
258 }
259
260 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
261         wxWindowID winid, const wxString& title,
262         const wxPoint& pos, const wxSize& size,
263         long style, const wxString& name)
264 {
265     bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
266     if(success)
267     {
268         m_mdiParent = parent;
269         parent->AddMDIChild(this);
270     }
271     return success;
272 }
273
274 wxMDIChildFrame::~wxMDIChildFrame()
275 {
276     // Just in case Destroy() wasn't called
277     m_mdiParent->RemoveMDIChild(this);
278 }
279
280 void wxMDIChildFrame::Activate()
281 {
282 }
283
284 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
285 {
286     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
287     if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent)
288     {
289         sm_cocoaDeactivateWindow = NULL;
290         if(m_mdiParent->GetActiveChild() != this)
291             sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild();
292     }
293     m_mdiParent->SetActiveChild(this);
294     wxFrame::CocoaDelegate_windowDidBecomeKey();
295 }
296
297 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
298 {
299     m_mdiParent->SetActiveChild(this);
300     wxFrame::CocoaDelegate_windowDidBecomeMain();
301 }
302
303 void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
304 {
305     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
306     sm_cocoaDeactivateWindow = this;
307 }
308
309 bool wxMDIChildFrame::Destroy()
310 {
311     // It's good to do this here before we are really closed
312     m_mdiParent->RemoveMDIChild(this);
313     return wxFrame::Destroy();
314 }
315
316 // ========================================================================
317 // wxMDIClientWindow
318 // ========================================================================
319 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
320
321 wxMDIClientWindow::wxMDIClientWindow()
322 {
323 }
324
325 wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style)
326 :   wxWindow(parent, -1)
327 {
328 }
329
330 wxMDIClientWindow::~wxMDIClientWindow()
331 {
332 }
333
334 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style)
335 {
336     return false;
337 }
338
339 #endif