]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/mdi.mm
made wxFFile a bit more safe: don't crash when Tell() and Length() are called on...
[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: 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>
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 wxLogDebug(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 wxLogDebug(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 wxLogDebug(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 wxLogDebug(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