]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/mdi.mm
Further refine of #15226: wxRichTextCtrl: Implement setting properties with undo...
[wxWidgets.git] / src / cocoa / mdi.mm
CommitLineData
f99422e9 1/////////////////////////////////////////////////////////////////////////////
59cf2e49 2// Name: src/cocoa/mdi.mm
f99422e9
DE
3// Purpose: wxMDIParentFrame, wxMDIChildFrame, wxMDIClientWindow
4// Author: David Elliott
5// Modified by:
6// Created: 2003/09/08
f99422e9 7// Copyright: (c) 2003 David Elliott
526954c5 8// Licence: wxWindows licence
f99422e9
DE
9/////////////////////////////////////////////////////////////////////////////
10
11#include "wx/wxprec.h"
16c81607
RN
12
13#if wxUSE_MDI
14
59cf2e49
WS
15#include "wx/mdi.h"
16
e7e1ad7d
DE
17#include "wx/cocoa/objc/objc_uniquifying.h"
18
f99422e9
DE
19#ifndef WX_PRECOMP
20 #include "wx/log.h"
f99422e9
DE
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
d8418952 31#include "wx/listimpl.cpp"
f99422e9
DE
32WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
33
34WX_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
e7e1ad7d 48WX_DECLARE_GET_OBJC_CLASS(wxMDIParentFrameObserver,NSObject)
f99422e9
DE
49
50@implementation wxMDIParentFrameObserver : NSObject
51- (id)init
52{
2b030203 53 wxFAIL_MSG(wxT("[wxMDIParentFrameObserver -init] should never be called!"));
f99422e9
DE
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
e7e1ad7d 72WX_IMPLEMENT_GET_OBJC_CLASS(wxMDIParentFrameObserver,NSObject)
f99422e9
DE
73
74// ========================================================================
75// wxMDIParentFrame
76// ========================================================================
77IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
78BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
79END_EVENT_TABLE()
80
81void wxMDIParentFrame::Init()
82{
83 m_clientWindow = NULL;
84 m_currentChild = NULL;
e7e1ad7d 85 m_observer = [[WX_GET_OBJC_CLASS(wxMDIParentFrameObserver) alloc]
f99422e9
DE
86 initWithWxMDIParentFrame:this];
87 [[NSNotificationCenter defaultCenter] addObserver:m_observer
88 selector:@selector(windowDidBecomeMain:)
89 name:NSWindowDidBecomeMainNotification object:nil];
90}
91
92bool wxMDIParentFrame::Create(wxWindow *parent,
93 wxWindowID winid, const wxString& title,
94 const wxPoint& pos, const wxSize& size,
95 long style, const wxString& name)
96{
6e42617a
VZ
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;
f99422e9
DE
103}
104
105wxMDIParentFrame::~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
119void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
120{
121 m_mdiChildren.Append(child);
122}
123
124void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
125{
126 m_mdiChildren.DeleteObject(child);
127 if(child==m_currentChild)
128 SetActiveChild(NULL);
129}
130
f99422e9
DE
131void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
132{
133 m_currentChild = child;
134 wxMenuBarManager::GetInstance()->UpdateMenuBar();
135}
136
f99422e9
DE
137wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
138{
139 if(m_currentChild && (win==this))
140 return m_currentChild->GetAppMenuBar(win);
141 return wxFrame::GetAppMenuBar(win);
142}
143
144void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
145{
48580976 146 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
f99422e9
DE
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
169void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
170{
48580976 171 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
f99422e9
DE
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
180bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome)
181{
182 canBecome = m_mdiChildren.IsEmpty(); return true;
183}
184
185void 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 {
4799f3ba 216 NSInteger windowCount = 0;
f99422e9
DE
217 NSCountWindows(&windowCount);
218 wxASSERT(windowCount>0);
4799f3ba 219 NSInteger *windowList = new NSInteger[windowCount];
f99422e9
DE
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// ========================================================================
233IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
234BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
235END_EVENT_TABLE()
236
237void wxMDIChildFrame::Init()
238{
239 m_mdiParent = NULL;
240}
241
242bool 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
256wxMDIChildFrame::~wxMDIChildFrame()
257{
258 // Just in case Destroy() wasn't called
259 m_mdiParent->RemoveMDIChild(this);
260}
261
262void wxMDIChildFrame::Activate()
263{
264}
265
266void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
267{
48580976 268 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
f99422e9
DE
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
279void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
280{
281 m_mdiParent->SetActiveChild(this);
282 wxFrame::CocoaDelegate_windowDidBecomeMain();
283}
284
285void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
286{
48580976 287 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
f99422e9
DE
288 sm_cocoaDeactivateWindow = this;
289}
290
291bool 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// ========================================================================
301IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
302
d2824cdb 303bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
f99422e9 304{
d2824cdb 305 return Create(parent, wxID_ANY, wxPoint(0, 0), wxSize(0, 0), style);
f99422e9
DE
306}
307
d2824cdb 308#endif // wxUSE_MDI