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