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