]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/mdi.mm
Added implementation of MDI using top level windows
[wxWidgets.git] / src / cocoa / mdi.mm
CommitLineData
f99422e9
DE
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: wxWindows 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>
27WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
28
29WX_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("[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// ========================================================================
70IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
71BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
72END_EVENT_TABLE()
73
74void 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
85bool 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
96wxMDIParentFrame::~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
110void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
111{
112 m_mdiChildren.Append(child);
113}
114
115void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
116{
117 m_mdiChildren.DeleteObject(child);
118 if(child==m_currentChild)
119 SetActiveChild(NULL);
120}
121
122wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
123{
124 return m_currentChild;
125}
126
127void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
128{
129 m_currentChild = child;
130 wxMenuBarManager::GetInstance()->UpdateMenuBar();
131}
132
133wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
134{
135 return m_clientWindow;
136}
137
138wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
139{
140 m_clientWindow = new wxMDIClientWindow( this );
141 return m_clientWindow;
142}
143
144void wxMDIParentFrame::ActivateNext()
145{
146}
147
148void wxMDIParentFrame::ActivatePrevious()
149{
150}
151
152wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
153{
154 if(m_currentChild && (win==this))
155 return m_currentChild->GetAppMenuBar(win);
156 return wxFrame::GetAppMenuBar(win);
157}
158
159void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
160{
161 wxLogDebug("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
184void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
185{
186 wxLogDebug("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
195bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome)
196{
197 canBecome = m_mdiChildren.IsEmpty(); return true;
198}
199
200void 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// ========================================================================
248IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
249BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
250END_EVENT_TABLE()
251
252void wxMDIChildFrame::Init()
253{
254 m_mdiParent = NULL;
255}
256
257bool 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
271wxMDIChildFrame::~wxMDIChildFrame()
272{
273 // Just in case Destroy() wasn't called
274 m_mdiParent->RemoveMDIChild(this);
275}
276
277void wxMDIChildFrame::Activate()
278{
279}
280
281void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
282{
283 wxLogDebug("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
294void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
295{
296 m_mdiParent->SetActiveChild(this);
297 wxFrame::CocoaDelegate_windowDidBecomeMain();
298}
299
300void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
301{
302 wxLogDebug("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey",this);
303 sm_cocoaDeactivateWindow = this;
304}
305
306bool 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// ========================================================================
316IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
317
318wxMDIClientWindow::wxMDIClientWindow()
319{
320}
321
322wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style)
323: wxWindow(parent, -1)
324{
325}
326
327wxMDIClientWindow::~wxMDIClientWindow()
328{
329}
330
331bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style)
332{
333 return false;
334}
335