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