]> git.saurik.com Git - wxWidgets.git/blame - src/common/docview.cpp
Sun CC doesn't allow calling static function from template instantiations so rename...
[wxWidgets.git] / src / common / docview.cpp
CommitLineData
5d9ea849 1/////////////////////////////////////////////////////////////////////////////
1e6feb95 2// Name: src/common/docview.cpp
c801d85f
KB
3// Purpose: Document/view classes
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
55d99c7a 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
c801d85f
KB
10/////////////////////////////////////////////////////////////////////////////
11
0fb67cd1
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
c801d85f
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
8ecff181 24 #pragma hdrstop
c801d85f
KB
25#endif
26
47d67540 27#if wxUSE_DOC_VIEW_ARCHITECTURE
c801d85f 28
246c5004
WS
29#include "wx/docview.h"
30
c801d85f 31#ifndef WX_PRECOMP
8ecff181 32 #include "wx/list.h"
0fb67cd1
VZ
33 #include "wx/string.h"
34 #include "wx/utils.h"
35 #include "wx/app.h"
36 #include "wx/dc.h"
d0bdc3ca 37 #include "wx/dialog.h"
0fb67cd1 38 #include "wx/menu.h"
0fb67cd1 39 #include "wx/filedlg.h"
6de2f8b9 40 #include "wx/intl.h"
c0369005 41 #include "wx/log.h"
246c5004 42 #include "wx/msgdlg.h"
59cf2e49 43 #include "wx/mdi.h"
949c9f74 44 #include "wx/choicdlg.h"
f7bd2698
JS
45#endif
46
4fedd384
JS
47#include "wx/ffile.h"
48
b8afeb43
SC
49#ifdef __WXMAC__
50 #include "wx/filename.h"
51#endif
c2ff79b1 52
ce4169a4 53#if wxUSE_PRINTING_ARCHITECTURE
8ecff181
WS
54 #include "wx/prntbase.h"
55 #include "wx/printdlg.h"
ce4169a4
RR
56#endif
57
7f555861 58#include "wx/confbase.h"
74b31181 59#include "wx/file.h"
1e6feb95 60#include "wx/cmdproc.h"
0f30d8e3 61#include "wx/tokenzr.h"
b4a980f4 62#include "wx/filename.h"
c801d85f 63
c801d85f
KB
64#include <stdio.h>
65#include <string.h>
66
a533f5c1 67#if wxUSE_STD_IOSTREAM
8ecff181
WS
68 #include "wx/ioswrap.h"
69 #if wxUSE_IOSTREAMH
70 #include <fstream.h>
71 #else
72 #include <fstream>
73 #endif
a533f5c1 74#else
8ecff181 75 #include "wx/wfstream.h"
c801d85f
KB
76#endif
77
0fb67cd1 78// ----------------------------------------------------------------------------
77ffb593 79// wxWidgets macros
0fb67cd1
VZ
80// ----------------------------------------------------------------------------
81
1e6feb95
VZ
82IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler)
83IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler)
84IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject)
85IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler)
86IMPLEMENT_CLASS(wxDocChildFrame, wxFrame)
87IMPLEMENT_CLASS(wxDocParentFrame, wxFrame)
0fb67cd1 88
1e6feb95
VZ
89#if wxUSE_PRINTING_ARCHITECTURE
90 IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout)
91#endif
0fb67cd1 92
1e6feb95 93IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
c801d85f 94
0fb67cd1
VZ
95// ----------------------------------------------------------------------------
96// function prototypes
97// ----------------------------------------------------------------------------
98
9d4a05be 99static wxWindow* wxFindSuitableParent(void);
0fb67cd1 100
0c5d3e1c
VZ
101// ----------------------------------------------------------------------------
102// local constants
103// ----------------------------------------------------------------------------
104
2695a14e 105static const wxChar *s_MRUEntryFormat = wxT("&%d %s");
0c5d3e1c 106
0fb67cd1
VZ
107// ============================================================================
108// implementation
109// ============================================================================
110
111// ----------------------------------------------------------------------------
112// local functions
113// ----------------------------------------------------------------------------
114
86501081 115static wxString FindExtension(const wxString& path)
0fb67cd1
VZ
116{
117 wxString ext;
118 wxSplitPath(path, NULL, NULL, &ext);
119
120 // VZ: extensions are considered not case sensitive - is this really a good
121 // idea?
122 return ext.MakeLower();
123}
124
125// ----------------------------------------------------------------------------
126// Definition of wxDocument
127// ----------------------------------------------------------------------------
c801d85f
KB
128
129wxDocument::wxDocument(wxDocument *parent)
130{
68379eaf 131 m_documentModified = false;
0fb67cd1
VZ
132 m_documentParent = parent;
133 m_documentTemplate = (wxDocTemplate *) NULL;
f6bcfd97 134 m_commandProcessor = (wxCommandProcessor*) NULL;
68379eaf 135 m_savedYet = false;
c801d85f
KB
136}
137
0fb67cd1 138bool wxDocument::DeleteContents()
c801d85f 139{
68379eaf 140 return true;
c801d85f
KB
141}
142
0fb67cd1 143wxDocument::~wxDocument()
c801d85f 144{
0fb67cd1 145 DeleteContents();
c801d85f 146
0fb67cd1
VZ
147 if (m_commandProcessor)
148 delete m_commandProcessor;
c801d85f 149
f6bcfd97
BP
150 if (GetDocumentManager())
151 GetDocumentManager()->RemoveDocument(this);
c801d85f 152
0fb67cd1
VZ
153 // Not safe to do here, since it'll invoke virtual view functions
154 // expecting to see valid derived objects: and by the time we get here,
155 // we've called destructors higher up.
156 //DeleteAllViews();
c801d85f 157}
0fb67cd1
VZ
158
159bool wxDocument::Close()
c801d85f 160{
0fb67cd1
VZ
161 if (OnSaveModified())
162 return OnCloseDocument();
163 else
68379eaf 164 return false;
c801d85f 165}
0fb67cd1
VZ
166
167bool wxDocument::OnCloseDocument()
c801d85f 168{
b23e843b 169 // Tell all views that we're about to close
42771621 170 NotifyClosing();
0fb67cd1 171 DeleteContents();
68379eaf
WS
172 Modify(false);
173 return true;
c801d85f
KB
174}
175
0fb67cd1
VZ
176// Note that this implicitly deletes the document when the last view is
177// deleted.
178bool wxDocument::DeleteAllViews()
c801d85f 179{
f6bcfd97
BP
180 wxDocManager* manager = GetDocumentManager();
181
40702099
VZ
182 // first check if all views agree to be closed
183 const wxList::iterator end = m_documentViews.end();
184 for ( wxList::iterator i = m_documentViews.begin(); i != end; ++i )
0fb67cd1 185 {
40702099
VZ
186 wxView *view = (wxView *)*i;
187 if ( !view->Close() )
68379eaf 188 return false;
0fb67cd1 189 }
d5a93fda 190
40702099
VZ
191 // all views agreed to close, now do close them
192 if ( m_documentViews.empty() )
193 {
194 // normally the document would be implicitly deleted when the last view
195 // is, but if don't have any views, do it here instead
196 if ( manager && manager->GetDocuments().Member(this) )
197 delete this;
198 }
199 else // have views
200 {
201 // as we delete elements we iterate over, don't use the usual "from
202 // begin to end" loop
203 for ( ;; )
204 {
205 wxView *view = (wxView *)*m_documentViews.begin();
206
207 bool isLastOne = m_documentViews.size() == 1;
208
209 // this always deletes the node implicitly and if this is the last
210 // view also deletes this object itself (also implicitly, great),
211 // so we can't test for m_documentViews.empty() after calling this!
212 delete view;
213
214 if ( isLastOne )
215 break;
216 }
217 }
f6bcfd97 218
68379eaf 219 return true;
c801d85f
KB
220}
221
6de2f8b9 222wxView *wxDocument::GetFirstView() const
c801d85f 223{
b1d4dd7a 224 if (m_documentViews.GetCount() == 0)
0fb67cd1 225 return (wxView *) NULL;
b1d4dd7a 226 return (wxView *)m_documentViews.GetFirst()->GetData();
c801d85f
KB
227}
228
6de2f8b9 229wxDocManager *wxDocument::GetDocumentManager() const
c801d85f 230{
f6bcfd97 231 return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL);
c801d85f
KB
232}
233
0fb67cd1 234bool wxDocument::OnNewDocument()
c801d85f 235{
0fb67cd1 236 if (!OnSaveModified())
68379eaf 237 return false;
c801d85f 238
68379eaf 239 if (OnCloseDocument()==false) return false;
0fb67cd1 240 DeleteContents();
68379eaf
WS
241 Modify(false);
242 SetDocumentSaved(false);
c801d85f 243
724b119a 244 const wxString name = GetDocumentManager()->MakeNewDocumentName();
0fb67cd1 245 SetTitle(name);
68379eaf 246 SetFilename(name, true);
0fb67cd1 247
68379eaf 248 return true;
c801d85f
KB
249}
250
0fb67cd1 251bool wxDocument::Save()
c801d85f 252{
d06a66f5 253 if (!IsModified() && m_savedYet)
68379eaf 254 return true;
c801d85f 255
d06a66f5
VZ
256 if ( m_documentFile.empty() || !m_savedYet )
257 return SaveAs();
258
259 return OnSaveDocument(m_documentFile);
c801d85f 260}
0fb67cd1
VZ
261
262bool wxDocument::SaveAs()
c801d85f 263{
ba681060
VZ
264 wxDocTemplate *docTemplate = GetDocumentTemplate();
265 if (!docTemplate)
68379eaf 266 return false;
0fb67cd1 267
04129514
JS
268#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__)
269 wxString filter = docTemplate->GetDescription() + wxT(" (") + docTemplate->GetFileFilter() + wxT(")|") + docTemplate->GetFileFilter();
270
271 // Now see if there are some other template with identical view and document
272 // classes, whose filters may also be used.
273
274 if (docTemplate->GetViewClassInfo() && docTemplate->GetDocClassInfo())
275 {
e7b21b01 276 wxList::compatibility_iterator node = docTemplate->GetDocumentManager()->GetTemplates().GetFirst();
04129514
JS
277 while (node)
278 {
279 wxDocTemplate *t = (wxDocTemplate*) node->GetData();
68379eaf 280
04129514
JS
281 if (t->IsVisible() && t != docTemplate &&
282 t->GetViewClassInfo() == docTemplate->GetViewClassInfo() &&
283 t->GetDocClassInfo() == docTemplate->GetDocClassInfo())
284 {
285 // add a '|' to separate this filter from the previous one
b494c48b 286 if ( !filter.empty() )
04129514 287 filter << wxT('|');
68379eaf 288
04129514
JS
289 filter << t->GetDescription() << wxT(" (") << t->GetFileFilter() << wxT(") |")
290 << t->GetFileFilter();
291 }
292
293 node = node->GetNext();
294 }
295 }
296#else
297 wxString filter = docTemplate->GetFileFilter() ;
298#endif
ba681060 299 wxString tmp = wxFileSelector(_("Save as"),
0fb67cd1 300 docTemplate->GetDirectory(),
015e69f3 301 wxFileNameFromPath(GetFilename()),
0fb67cd1 302 docTemplate->GetDefaultExtension(),
04129514 303 filter,
ff3e84ff 304 wxFD_SAVE | wxFD_OVERWRITE_PROMPT,
0fb67cd1
VZ
305 GetDocumentWindow());
306
b494c48b 307 if (tmp.empty())
68379eaf 308 return false;
ba681060 309
2bb0cd28 310 wxString fileName(tmp);
88ac883a 311 wxString path, name, ext;
2bb0cd28
JS
312 wxSplitPath(fileName, & path, & name, & ext);
313
b494c48b 314 if (ext.empty())
2bb0cd28 315 {
2b5f62a0 316 fileName += wxT(".");
2bb0cd28
JS
317 fileName += docTemplate->GetDefaultExtension();
318 }
319
320 SetFilename(fileName);
321 SetTitle(wxFileNameFromPath(fileName));
0fb67cd1 322
c801d85f 323 // Notify the views that the filename has changed
222ed1d6 324 wxList::compatibility_iterator node = m_documentViews.GetFirst();
c801d85f
KB
325 while (node)
326 {
b1d4dd7a 327 wxView *view = (wxView *)node->GetData();
0fb67cd1 328 view->OnChangeFilename();
b1d4dd7a 329 node = node->GetNext();
c801d85f 330 }
ba681060 331
9d4a05be
JS
332 // Files that were not saved correctly are not added to the FileHistory.
333 if (!OnSaveDocument(m_documentFile))
68379eaf 334 return false;
9d4a05be 335
42771621 336 // A file that doesn't use the default extension of its document template cannot be opened
9d4a05be
JS
337 // via the FileHistory, so we do not add it.
338 if (docTemplate->FileMatchesTemplate(fileName))
339 {
340 GetDocumentManager()->AddFileToHistory(fileName);
341 }
342 else
343 {
344 // The user will probably not be able to open the file again, so
345 // we could warn about the wrong file-extension here.
346 }
68379eaf 347 return true;
c801d85f 348}
0fb67cd1 349
c801d85f
KB
350bool wxDocument::OnSaveDocument(const wxString& file)
351{
0fb67cd1 352 if ( !file )
68379eaf 353 return false;
c801d85f 354
69936aea 355 if ( !DoSaveDocument(file) )
68379eaf 356 return false;
0fb67cd1 357
68379eaf 358 Modify(false);
0fb67cd1 359 SetFilename(file);
68379eaf 360 SetDocumentSaved(true);
b8afeb43
SC
361#ifdef __WXMAC__
362 wxFileName fn(file) ;
363 fn.MacSetDefaultTypeAndCreator() ;
364#endif
68379eaf 365 return true;
c801d85f 366}
0fb67cd1 367
c801d85f
KB
368bool wxDocument::OnOpenDocument(const wxString& file)
369{
0fb67cd1 370 if (!OnSaveModified())
68379eaf 371 return false;
c801d85f 372
69936aea 373 if ( !DoOpenDocument(file) )
68379eaf 374 return false;
0fb67cd1 375
68379eaf
WS
376 SetFilename(file, true);
377 Modify(false);
378 m_savedYet = true;
0fb67cd1
VZ
379
380 UpdateAllViews();
c801d85f 381
68379eaf 382 return true;
c801d85f 383}
0fb67cd1 384
a533f5c1 385#if wxUSE_STD_IOSTREAM
dd107c50 386wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream)
23a54e14
RR
387#else
388wxInputStream& wxDocument::LoadObject(wxInputStream& stream)
389#endif
c801d85f 390{
0fb67cd1 391 return stream;
c801d85f
KB
392}
393
23a54e14 394#if wxUSE_STD_IOSTREAM
dd107c50 395wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream)
a533f5c1 396#else
23a54e14
RR
397wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream)
398#endif
a533f5c1 399{
23a54e14 400 return stream;
a533f5c1 401}
c801d85f 402
0fb67cd1 403bool wxDocument::Revert()
c801d85f 404{
68379eaf 405 return false;
c801d85f
KB
406}
407
408
409// Get title, or filename if no title, else unnamed
724b119a 410#if WXWIN_COMPATIBILITY_2_8
c801d85f
KB
411bool wxDocument::GetPrintableName(wxString& buf) const
412{
724b119a
VZ
413 // this function can not only be overridden by the user code but also
414 // called by it so we need to ensure that we return the same thing as
415 // GetUserReadableName() but we can't call it because this would result in
416 // an infinite recursion, hence we use the helper DoGetUserReadableName()
417 buf = DoGetUserReadableName();
418
419 return true;
420}
421#endif // WXWIN_COMPATIBILITY_2_8
422
423wxString wxDocument::GetUserReadableName() const
424{
425#if WXWIN_COMPATIBILITY_2_8
426 // we need to call the old virtual function to ensure that the overridden
427 // version of it is still called
428 wxString name;
429 if ( GetPrintableName(name) )
430 return name;
431#endif // WXWIN_COMPATIBILITY_2_8
432
433 return DoGetUserReadableName();
434}
435
436wxString wxDocument::DoGetUserReadableName() const
437{
438 if ( !m_documentTitle.empty() )
439 return m_documentTitle;
440
441 if ( !m_documentFile.empty() )
442 return wxFileNameFromPath(m_documentFile);
443
444 return _("unnamed");
c801d85f
KB
445}
446
6de2f8b9 447wxWindow *wxDocument::GetDocumentWindow() const
c801d85f 448{
0fb67cd1
VZ
449 wxView *view = GetFirstView();
450 if (view)
451 return view->GetFrame();
452 else
453 return wxTheApp->GetTopWindow();
c801d85f
KB
454}
455
0fb67cd1 456wxCommandProcessor *wxDocument::OnCreateCommandProcessor()
c801d85f 457{
0fb67cd1 458 return new wxCommandProcessor;
c801d85f
KB
459}
460
68379eaf 461// true if safe to close
0fb67cd1 462bool wxDocument::OnSaveModified()
c801d85f 463{
0fb67cd1 464 if (IsModified())
c801d85f 465 {
724b119a 466 wxString title = GetUserReadableName();
0fb67cd1
VZ
467
468 wxString msgTitle;
b494c48b 469 if (!wxTheApp->GetAppName().empty())
0fb67cd1
VZ
470 msgTitle = wxTheApp->GetAppName();
471 else
472 msgTitle = wxString(_("Warning"));
473
474 wxString prompt;
86501081 475 prompt.Printf(_("Do you want to save changes to document %s?"), title);
0fb67cd1
VZ
476 int res = wxMessageBox(prompt, msgTitle,
477 wxYES_NO|wxCANCEL|wxICON_QUESTION,
478 GetDocumentWindow());
479 if (res == wxNO)
480 {
68379eaf
WS
481 Modify(false);
482 return true;
0fb67cd1
VZ
483 }
484 else if (res == wxYES)
485 return Save();
486 else if (res == wxCANCEL)
68379eaf 487 return false;
c801d85f 488 }
68379eaf 489 return true;
c801d85f
KB
490}
491
492bool wxDocument::Draw(wxDC& WXUNUSED(context))
493{
68379eaf 494 return true;
c801d85f
KB
495}
496
497bool wxDocument::AddView(wxView *view)
498{
0fb67cd1
VZ
499 if (!m_documentViews.Member(view))
500 {
501 m_documentViews.Append(view);
502 OnChangedViewList();
503 }
68379eaf 504 return true;
c801d85f
KB
505}
506
507bool wxDocument::RemoveView(wxView *view)
508{
0fb67cd1
VZ
509 (void)m_documentViews.DeleteObject(view);
510 OnChangedViewList();
68379eaf 511 return true;
c801d85f
KB
512}
513
514bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags)
515{
0fb67cd1 516 if (GetDocumentTemplate()->CreateView(this, flags))
68379eaf 517 return true;
0fb67cd1 518 else
68379eaf 519 return false;
c801d85f
KB
520}
521
522// Called after a view is added or removed.
523// The default implementation deletes the document if
524// there are no more views.
0fb67cd1 525void wxDocument::OnChangedViewList()
c801d85f 526{
b1d4dd7a 527 if (m_documentViews.GetCount() == 0)
c801d85f 528 {
0fb67cd1
VZ
529 if (OnSaveModified())
530 {
531 delete this;
532 }
c801d85f 533 }
c801d85f
KB
534}
535
536void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint)
537{
222ed1d6 538 wxList::compatibility_iterator node = m_documentViews.GetFirst();
0fb67cd1
VZ
539 while (node)
540 {
b1d4dd7a 541 wxView *view = (wxView *)node->GetData();
42771621 542 if (view != sender)
2b5f62a0 543 view->OnUpdate(sender, hint);
b1d4dd7a 544 node = node->GetNext();
0fb67cd1 545 }
c801d85f
KB
546}
547
b23e843b
JS
548void wxDocument::NotifyClosing()
549{
222ed1d6 550 wxList::compatibility_iterator node = m_documentViews.GetFirst();
b23e843b
JS
551 while (node)
552 {
b1d4dd7a 553 wxView *view = (wxView *)node->GetData();
b23e843b 554 view->OnClosingDocument();
b1d4dd7a 555 node = node->GetNext();
b23e843b
JS
556 }
557}
558
c801d85f
KB
559void wxDocument::SetFilename(const wxString& filename, bool notifyViews)
560{
0fb67cd1
VZ
561 m_documentFile = filename;
562 if ( notifyViews )
c801d85f 563 {
0fb67cd1 564 // Notify the views that the filename has changed
222ed1d6 565 wxList::compatibility_iterator node = m_documentViews.GetFirst();
0fb67cd1
VZ
566 while (node)
567 {
b1d4dd7a 568 wxView *view = (wxView *)node->GetData();
0fb67cd1 569 view->OnChangeFilename();
b1d4dd7a 570 node = node->GetNext();
0fb67cd1 571 }
c801d85f 572 }
c801d85f
KB
573}
574
69936aea
VZ
575bool wxDocument::DoSaveDocument(const wxString& file)
576{
577 wxString msgTitle;
b494c48b 578 if (!wxTheApp->GetAppName().empty())
69936aea
VZ
579 msgTitle = wxTheApp->GetAppName();
580 else
581 msgTitle = wxString(_("File error"));
582
583#if wxUSE_STD_IOSTREAM
53e2e87c 584 wxSTD ofstream store(file.mb_str(), wxSTD ios::binary);
69936aea
VZ
585 if (store.fail() || store.bad())
586#else
587 wxFileOutputStream store(file);
588 if (store.GetLastError() != wxSTREAM_NO_ERROR)
589#endif
590 {
591 (void)wxMessageBox(_("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION,
592 GetDocumentWindow());
593 // Saving error
68379eaf 594 return false;
69936aea
VZ
595 }
596 if (!SaveObject(store))
597 {
598 (void)wxMessageBox(_("Sorry, could not save this file."), msgTitle, wxOK | wxICON_EXCLAMATION,
599 GetDocumentWindow());
600 // Saving error
68379eaf 601 return false;
69936aea
VZ
602 }
603
68379eaf 604 return true;
69936aea
VZ
605}
606
607bool wxDocument::DoOpenDocument(const wxString& file)
608{
69936aea 609#if wxUSE_STD_IOSTREAM
53e2e87c 610 wxSTD ifstream store(file.mb_str(), wxSTD ios::binary);
64c12a6d 611 if (!store.fail() && !store.bad())
69936aea
VZ
612#else
613 wxFileInputStream store(file);
64c12a6d 614 if (store.GetLastError() == wxSTREAM_NO_ERROR)
69936aea
VZ
615#endif
616 {
69936aea 617#if wxUSE_STD_IOSTREAM
64c12a6d
VZ
618 LoadObject(store);
619 if ( !!store || store.eof() )
69936aea 620#else
64c12a6d
VZ
621 int res = LoadObject(store).GetLastError();
622 if ( res == wxSTREAM_NO_ERROR || res == wxSTREAM_EOF )
69936aea 623#endif
64c12a6d 624 return true;
69936aea
VZ
625 }
626
64c12a6d
VZ
627 wxLogError(_("Sorry, could not open this file."));
628 return false;
69936aea
VZ
629}
630
631
0fb67cd1
VZ
632// ----------------------------------------------------------------------------
633// Document view
634// ----------------------------------------------------------------------------
c801d85f 635
dbdb39b2 636wxView::wxView()
c801d85f 637{
0fb67cd1
VZ
638 m_viewDocument = (wxDocument*) NULL;
639
0fb67cd1 640 m_viewFrame = (wxFrame *) NULL;
c801d85f
KB
641}
642
0fb67cd1 643wxView::~wxView()
c801d85f 644{
68379eaf 645 GetDocumentManager()->ActivateView(this, false);
0fb67cd1 646 m_viewDocument->RemoveView(this);
c801d85f
KB
647}
648
649// Extend event processing to search the document's event table
650bool wxView::ProcessEvent(wxEvent& event)
651{
0fb67cd1
VZ
652 if ( !GetDocument() || !GetDocument()->ProcessEvent(event) )
653 return wxEvtHandler::ProcessEvent(event);
18759f78 654
68379eaf 655 return true;
c801d85f
KB
656}
657
658void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView))
659{
660}
661
662void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info))
663{
0fb67cd1 664 OnDraw(dc);
c801d85f
KB
665}
666
667void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
668{
669}
670
0fb67cd1 671void wxView::OnChangeFilename()
c801d85f 672{
faa49bfd
WS
673 // GetFrame can return wxWindow rather than wxTopLevelWindow due to
674 // generic MDI implementation so use SetLabel rather than SetTitle.
675 // It should cause SetTitle() for top level windows.
676 wxWindow *win = GetFrame();
677 if (!win) return;
f2506310 678
faa49bfd
WS
679 wxDocument *doc = GetDocument();
680 if (!doc) return;
c801d85f 681
724b119a 682 win->SetLabel(doc->GetUserReadableName());
c801d85f
KB
683}
684
685void wxView::SetDocument(wxDocument *doc)
686{
0fb67cd1
VZ
687 m_viewDocument = doc;
688 if (doc)
689 doc->AddView(this);
c801d85f
KB
690}
691
692bool wxView::Close(bool deleteWindow)
693{
0fb67cd1 694 if (OnClose(deleteWindow))
68379eaf 695 return true;
0fb67cd1 696 else
68379eaf 697 return false;
c801d85f
KB
698}
699
700void wxView::Activate(bool activate)
701{
bb28b477 702 if (GetDocument() && GetDocumentManager())
0fb67cd1
VZ
703 {
704 OnActivateView(activate, this, GetDocumentManager()->GetCurrentView());
705 GetDocumentManager()->ActivateView(this, activate);
706 }
c801d85f
KB
707}
708
709bool wxView::OnClose(bool WXUNUSED(deleteWindow))
710{
68379eaf 711 return GetDocument() ? GetDocument()->Close() : true;
c801d85f
KB
712}
713
47d67540 714#if wxUSE_PRINTING_ARCHITECTURE
0fb67cd1 715wxPrintout *wxView::OnCreatePrintout()
c801d85f 716{
0fb67cd1 717 return new wxDocPrintout(this);
c801d85f 718}
6de2f8b9 719#endif // wxUSE_PRINTING_ARCHITECTURE
c801d85f 720
0fb67cd1
VZ
721// ----------------------------------------------------------------------------
722// wxDocTemplate
723// ----------------------------------------------------------------------------
c801d85f 724
0fb67cd1
VZ
725wxDocTemplate::wxDocTemplate(wxDocManager *manager,
726 const wxString& descr,
727 const wxString& filter,
728 const wxString& dir,
729 const wxString& ext,
730 const wxString& docTypeName,
731 const wxString& viewTypeName,
732 wxClassInfo *docClassInfo,
733 wxClassInfo *viewClassInfo,
734 long flags)
c801d85f 735{
0fb67cd1 736 m_documentManager = manager;
0fb67cd1
VZ
737 m_description = descr;
738 m_directory = dir;
739 m_defaultExt = ext;
740 m_fileFilter = filter;
741 m_flags = flags;
742 m_docTypeName = docTypeName;
743 m_viewTypeName = viewTypeName;
744 m_documentManager->AssociateTemplate(this);
c801d85f 745
0fb67cd1
VZ
746 m_docClassInfo = docClassInfo;
747 m_viewClassInfo = viewClassInfo;
c801d85f
KB
748}
749
0fb67cd1 750wxDocTemplate::~wxDocTemplate()
c801d85f 751{
0fb67cd1 752 m_documentManager->DisassociateTemplate(this);
c801d85f 753}
0fb67cd1
VZ
754
755// Tries to dynamically construct an object of the right class.
c801d85f
KB
756wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags)
757{
69936aea
VZ
758 wxDocument *doc = DoCreateDocument();
759 if ( doc == NULL )
0fb67cd1 760 return (wxDocument *) NULL;
68379eaf 761
217b7140
JS
762 if (InitDocument(doc, path, flags))
763 {
764 return doc;
765 }
766 else
767 {
768 return (wxDocument *) NULL;
769 }
770}
771
772bool wxDocTemplate::InitDocument(wxDocument* doc, const wxString& path, long flags)
773{
0fb67cd1
VZ
774 doc->SetFilename(path);
775 doc->SetDocumentTemplate(this);
776 GetDocumentManager()->AddDocument(doc);
777 doc->SetCommandProcessor(doc->OnCreateCommandProcessor());
778
779 if (doc->OnCreate(path, flags))
217b7140 780 return true;
0fb67cd1
VZ
781 else
782 {
f6bcfd97
BP
783 if (GetDocumentManager()->GetDocuments().Member(doc))
784 doc->DeleteAllViews();
217b7140 785 return false;
0fb67cd1 786 }
c801d85f
KB
787}
788
789wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags)
790{
69936aea
VZ
791 wxView *view = DoCreateView();
792 if ( view == NULL )
0fb67cd1 793 return (wxView *) NULL;
69936aea 794
0fb67cd1
VZ
795 view->SetDocument(doc);
796 if (view->OnCreate(doc, flags))
797 {
798 return view;
799 }
800 else
801 {
802 delete view;
803 return (wxView *) NULL;
804 }
c801d85f
KB
805}
806
6de2f8b9
VZ
807// The default (very primitive) format detection: check is the extension is
808// that of the template
809bool wxDocTemplate::FileMatchesTemplate(const wxString& path)
810{
0f30d8e3
WS
811 wxStringTokenizer parser (GetFileFilter(), wxT(";"));
812 wxString anything = wxT ("*");
813 while (parser.HasMoreTokens())
814 {
815 wxString filter = parser.GetNextToken();
816 wxString filterExt = FindExtension (filter);
817 if ( filter.IsSameAs (anything) ||
818 filterExt.IsSameAs (anything) ||
819 filterExt.IsSameAs (FindExtension (path)) )
820 return true;
821 }
6de2f8b9
VZ
822 return GetDefaultExtension().IsSameAs(FindExtension(path));
823}
824
69936aea
VZ
825wxDocument *wxDocTemplate::DoCreateDocument()
826{
827 if (!m_docClassInfo)
828 return (wxDocument *) NULL;
829
830 return (wxDocument *)m_docClassInfo->CreateObject();
831}
832
833wxView *wxDocTemplate::DoCreateView()
834{
835 if (!m_viewClassInfo)
836 return (wxView *) NULL;
837
838 return (wxView *)m_viewClassInfo->CreateObject();
839}
840
0fb67cd1
VZ
841// ----------------------------------------------------------------------------
842// wxDocManager
843// ----------------------------------------------------------------------------
844
c801d85f
KB
845BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler)
846 EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen)
847 EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose)
33a20136 848 EVT_MENU(wxID_CLOSE_ALL, wxDocManager::OnFileCloseAll)
c801d85f
KB
849 EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert)
850 EVT_MENU(wxID_NEW, wxDocManager::OnFileNew)
851 EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave)
852 EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs)
853 EVT_MENU(wxID_UNDO, wxDocManager::OnUndo)
854 EVT_MENU(wxID_REDO, wxDocManager::OnRedo)
f2506310
JS
855
856 EVT_UPDATE_UI(wxID_OPEN, wxDocManager::OnUpdateFileOpen)
857 EVT_UPDATE_UI(wxID_CLOSE, wxDocManager::OnUpdateFileClose)
33a20136 858 EVT_UPDATE_UI(wxID_CLOSE_ALL, wxDocManager::OnUpdateFileClose)
f2506310
JS
859 EVT_UPDATE_UI(wxID_REVERT, wxDocManager::OnUpdateFileRevert)
860 EVT_UPDATE_UI(wxID_NEW, wxDocManager::OnUpdateFileNew)
861 EVT_UPDATE_UI(wxID_SAVE, wxDocManager::OnUpdateFileSave)
862 EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateFileSaveAs)
863 EVT_UPDATE_UI(wxID_UNDO, wxDocManager::OnUpdateUndo)
864 EVT_UPDATE_UI(wxID_REDO, wxDocManager::OnUpdateRedo)
865
ce4169a4 866#if wxUSE_PRINTING_ARCHITECTURE
c801d85f 867 EVT_MENU(wxID_PRINT, wxDocManager::OnPrint)
c801d85f 868 EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview)
f2506310
JS
869
870 EVT_UPDATE_UI(wxID_PRINT, wxDocManager::OnUpdatePrint)
f2506310 871 EVT_UPDATE_UI(wxID_PREVIEW, wxDocManager::OnUpdatePreview)
ce4169a4 872#endif
c801d85f
KB
873END_EVENT_TABLE()
874
f2506310
JS
875wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL;
876
c801d85f
KB
877wxDocManager::wxDocManager(long flags, bool initialize)
878{
0fb67cd1
VZ
879 m_defaultDocumentNameCounter = 1;
880 m_flags = flags;
881 m_currentView = (wxView *) NULL;
882 m_maxDocsOpen = 10000;
883 m_fileHistory = (wxFileHistory *) NULL;
884 if (initialize)
885 Initialize();
f2506310 886 sm_docManager = this;
c801d85f
KB
887}
888
0fb67cd1 889wxDocManager::~wxDocManager()
c801d85f 890{
0fb67cd1
VZ
891 Clear();
892 if (m_fileHistory)
893 delete m_fileHistory;
f2506310 894 sm_docManager = (wxDocManager*) NULL;
c801d85f
KB
895}
896
b72b1920
JS
897// closes the specified document
898bool wxDocManager::CloseDocument(wxDocument* doc, bool force)
899{
900 if (doc->Close() || force)
901 {
902 // Implicitly deletes the document when
903 // the last view is deleted
904 doc->DeleteAllViews();
905
906 // Check we're really deleted
907 if (m_docs.Member(doc))
908 delete doc;
42771621 909
68379eaf 910 return true;
b72b1920 911 }
68379eaf 912 return false;
b72b1920
JS
913}
914
33a20136 915bool wxDocManager::CloseDocuments(bool force)
c801d85f 916{
222ed1d6 917 wxList::compatibility_iterator node = m_docs.GetFirst();
0fb67cd1
VZ
918 while (node)
919 {
b1d4dd7a 920 wxDocument *doc = (wxDocument *)node->GetData();
222ed1d6 921 wxList::compatibility_iterator next = node->GetNext();
68379eaf 922
b72b1920 923 if (!CloseDocument(doc, force))
68379eaf 924 return false;
0fb67cd1 925
0fb67cd1
VZ
926 // This assumes that documents are not connected in
927 // any way, i.e. deleting one document does NOT
928 // delete another.
929 node = next;
930 }
68379eaf 931 return true;
33a20136
VZ
932}
933
934bool wxDocManager::Clear(bool force)
935{
936 if (!CloseDocuments(force))
68379eaf 937 return false;
33a20136 938
8af94d3b
VZ
939 m_currentView = NULL;
940
222ed1d6 941 wxList::compatibility_iterator node = m_templates.GetFirst();
0fb67cd1
VZ
942 while (node)
943 {
b1d4dd7a 944 wxDocTemplate *templ = (wxDocTemplate*) node->GetData();
222ed1d6 945 wxList::compatibility_iterator next = node->GetNext();
c801d85f
KB
946 delete templ;
947 node = next;
0fb67cd1 948 }
68379eaf 949 return true;
c801d85f
KB
950}
951
0fb67cd1 952bool wxDocManager::Initialize()
c801d85f 953{
0fb67cd1 954 m_fileHistory = OnCreateFileHistory();
68379eaf 955 return true;
c801d85f
KB
956}
957
0fb67cd1 958wxFileHistory *wxDocManager::OnCreateFileHistory()
c801d85f 959{
0fb67cd1 960 return new wxFileHistory;
c801d85f
KB
961}
962
963void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event))
964{
0fb67cd1
VZ
965 wxDocument *doc = GetCurrentDocument();
966 if (!doc)
967 return;
968 if (doc->Close())
969 {
970 doc->DeleteAllViews();
971 if (m_docs.Member(doc))
972 delete doc;
973 }
c801d85f
KB
974}
975
33a20136
VZ
976void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event))
977{
68379eaf 978 CloseDocuments(false);
33a20136
VZ
979}
980
c801d85f
KB
981void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event))
982{
b494c48b 983 CreateDocument( wxEmptyString, wxDOC_NEW );
c801d85f
KB
984}
985
986void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event))
987{
b494c48b 988 if ( !CreateDocument( wxEmptyString, 0) )
5f170f33
VZ
989 {
990 OnOpenFileFailure();
991 }
c801d85f
KB
992}
993
994void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event))
995{
0fb67cd1
VZ
996 wxDocument *doc = GetCurrentDocument();
997 if (!doc)
998 return;
999 doc->Revert();
c801d85f
KB
1000}
1001
1002void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event))
1003{
0fb67cd1
VZ
1004 wxDocument *doc = GetCurrentDocument();
1005 if (!doc)
1006 return;
1007 doc->Save();
c801d85f
KB
1008}
1009
1010void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event))
1011{
0fb67cd1
VZ
1012 wxDocument *doc = GetCurrentDocument();
1013 if (!doc)
1014 return;
1015 doc->SaveAs();
c801d85f
KB
1016}
1017
1018void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event))
1019{
88ac883a 1020#if wxUSE_PRINTING_ARCHITECTURE
0fb67cd1
VZ
1021 wxView *view = GetCurrentView();
1022 if (!view)
1023 return;
c801d85f 1024
0fb67cd1
VZ
1025 wxPrintout *printout = view->OnCreatePrintout();
1026 if (printout)
1027 {
1028 wxPrinter printer;
68379eaf 1029 printer.Print(view->GetFrame(), printout, true);
c801d85f 1030
0fb67cd1
VZ
1031 delete printout;
1032 }
88ac883a 1033#endif // wxUSE_PRINTING_ARCHITECTURE
c801d85f
KB
1034}
1035
c801d85f
KB
1036void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event))
1037{
88ac883a 1038#if wxUSE_PRINTING_ARCHITECTURE
0fb67cd1
VZ
1039 wxView *view = GetCurrentView();
1040 if (!view)
1041 return;
c801d85f 1042
0fb67cd1
VZ
1043 wxPrintout *printout = view->OnCreatePrintout();
1044 if (printout)
1045 {
1046 // Pass two printout objects: for preview, and possible printing.
999836aa 1047 wxPrintPreviewBase *preview = new wxPrintPreview(printout, view->OnCreatePrintout());
3f8b4a3f
JS
1048 if ( !preview->Ok() )
1049 {
1050 delete preview;
1051 wxMessageBox( _("Sorry, print preview needs a printer to be installed.") );
1052 return;
1053 }
0fb67cd1
VZ
1054
1055 wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), _("Print Preview"),
1056 wxPoint(100, 100), wxSize(600, 650));
1057 frame->Centre(wxBOTH);
1058 frame->Initialize();
68379eaf 1059 frame->Show(true);
0fb67cd1 1060 }
88ac883a 1061#endif // wxUSE_PRINTING_ARCHITECTURE
c801d85f
KB
1062}
1063
34aa6140 1064void wxDocManager::OnUndo(wxCommandEvent& event)
c801d85f 1065{
0fb67cd1
VZ
1066 wxDocument *doc = GetCurrentDocument();
1067 if (!doc)
1068 return;
1069 if (doc->GetCommandProcessor())
1070 doc->GetCommandProcessor()->Undo();
34aa6140
JS
1071 else
1072 event.Skip();
c801d85f
KB
1073}
1074
34aa6140 1075void wxDocManager::OnRedo(wxCommandEvent& event)
c801d85f 1076{
0fb67cd1
VZ
1077 wxDocument *doc = GetCurrentDocument();
1078 if (!doc)
1079 return;
1080 if (doc->GetCommandProcessor())
1081 doc->GetCommandProcessor()->Redo();
34aa6140
JS
1082 else
1083 event.Skip();
c801d85f
KB
1084}
1085
f2506310
JS
1086// Handlers for UI update commands
1087
1088void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event)
1089{
68379eaf 1090 event.Enable( true );
f2506310
JS
1091}
1092
1093void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event)
1094{
1095 wxDocument *doc = GetCurrentDocument();
1096 event.Enable( (doc != (wxDocument*) NULL) );
1097}
1098
1099void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event)
1100{
1101 wxDocument *doc = GetCurrentDocument();
1102 event.Enable( (doc != (wxDocument*) NULL) );
1103}
1104
1105void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event)
1106{
68379eaf 1107 event.Enable( true );
f2506310
JS
1108}
1109
1110void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event)
1111{
1112 wxDocument *doc = GetCurrentDocument();
9cb0033c 1113 event.Enable( doc && doc->IsModified() );
f2506310
JS
1114}
1115
1116void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event)
1117{
1118 wxDocument *doc = GetCurrentDocument();
1119 event.Enable( (doc != (wxDocument*) NULL) );
1120}
1121
1122void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event)
1123{
1124 wxDocument *doc = GetCurrentDocument();
34aa6140 1125 if (!doc)
68379eaf 1126 event.Enable(false);
34aa6140
JS
1127 else if (!doc->GetCommandProcessor())
1128 event.Skip();
1129 else
1130 {
1131 event.Enable( doc->GetCommandProcessor()->CanUndo() );
2599ee02 1132 doc->GetCommandProcessor()->SetMenuStrings();
34aa6140 1133 }
f2506310
JS
1134}
1135
1136void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event)
1137{
1138 wxDocument *doc = GetCurrentDocument();
34aa6140 1139 if (!doc)
68379eaf 1140 event.Enable(false);
34aa6140
JS
1141 else if (!doc->GetCommandProcessor())
1142 event.Skip();
1143 else
1144 {
1145 event.Enable( doc->GetCommandProcessor()->CanRedo() );
2599ee02 1146 doc->GetCommandProcessor()->SetMenuStrings();
34aa6140 1147 }
f2506310
JS
1148}
1149
1150void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event)
1151{
1152 wxDocument *doc = GetCurrentDocument();
1153 event.Enable( (doc != (wxDocument*) NULL) );
1154}
1155
f2506310
JS
1156void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event)
1157{
1158 wxDocument *doc = GetCurrentDocument();
1159 event.Enable( (doc != (wxDocument*) NULL) );
1160}
1161
6de2f8b9 1162wxView *wxDocManager::GetCurrentView() const
637f467a
JS
1163{
1164 if (m_currentView)
1165 return m_currentView;
b1d4dd7a 1166 if (m_docs.GetCount() == 1)
637f467a 1167 {
b1d4dd7a 1168 wxDocument* doc = (wxDocument*) m_docs.GetFirst()->GetData();
637f467a
JS
1169 return doc->GetFirstView();
1170 }
c67daf87 1171 return (wxView *) NULL;
637f467a
JS
1172}
1173
1174// Extend event processing to search the view's event table
1175bool wxDocManager::ProcessEvent(wxEvent& event)
1176{
1177 wxView* view = GetCurrentView();
1178 if (view)
1179 {
1180 if (view->ProcessEvent(event))
68379eaf 1181 return true;
637f467a
JS
1182 }
1183 return wxEvtHandler::ProcessEvent(event);
1184}
1185
c801d85f
KB
1186wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags)
1187{
b1d4dd7a
RL
1188 wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()];
1189 int n = 0;
1190
1191 for (size_t i = 0; i < m_templates.GetCount(); i++)
c801d85f 1192 {
b1d4dd7a 1193 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData());
0fb67cd1
VZ
1194 if (temp->IsVisible())
1195 {
1196 templates[n] = temp;
1197 n ++;
1198 }
c801d85f 1199 }
0fb67cd1 1200 if (n == 0)
c801d85f 1201 {
0fb67cd1
VZ
1202 delete[] templates;
1203 return (wxDocument *) NULL;
c801d85f 1204 }
42771621 1205
b72b1920 1206 wxDocument* docToClose = NULL;
0fb67cd1
VZ
1207
1208 // If we've reached the max number of docs, close the
1209 // first one.
b1d4dd7a 1210 if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen )
c801d85f 1211 {
b1d4dd7a 1212 wxDocument *doc = (wxDocument *)GetDocuments().GetFirst()->GetData();
b72b1920 1213 docToClose = doc;
c801d85f
KB
1214 }
1215
0fb67cd1
VZ
1216 // New document: user chooses a template, unless there's only one.
1217 if (flags & wxDOC_NEW)
c801d85f 1218 {
0fb67cd1
VZ
1219 if (n == 1)
1220 {
b72b1920
JS
1221 if (docToClose)
1222 {
68379eaf 1223 if (!CloseDocument(docToClose, false))
b72b1920 1224 {
7a311019 1225 delete[] templates;
b72b1920
JS
1226 return NULL;
1227 }
1228 }
42771621 1229
0fb67cd1
VZ
1230 wxDocTemplate *temp = templates[0];
1231 delete[] templates;
1232 wxDocument *newDoc = temp->CreateDocument(path, flags);
42771621 1233
0fb67cd1
VZ
1234 if (newDoc)
1235 {
1236 newDoc->SetDocumentName(temp->GetDocumentName());
1237 newDoc->SetDocumentTemplate(temp);
f5729a6b
JS
1238 if (!newDoc->OnNewDocument() )
1239 {
1240 // Document is implicitly deleted by DeleteAllViews
1241 newDoc->DeleteAllViews();
1242 return NULL;
1243 }
0fb67cd1
VZ
1244 }
1245 return newDoc;
1246 }
1247
1248 wxDocTemplate *temp = SelectDocumentType(templates, n);
1249 delete[] templates;
1250 if (temp)
1251 {
b72b1920
JS
1252 if (docToClose)
1253 {
68379eaf 1254 if (!CloseDocument(docToClose, false))
b72b1920
JS
1255 {
1256 return NULL;
1257 }
1258 }
42771621 1259
0fb67cd1 1260 wxDocument *newDoc = temp->CreateDocument(path, flags);
b72b1920 1261
0fb67cd1
VZ
1262 if (newDoc)
1263 {
1264 newDoc->SetDocumentName(temp->GetDocumentName());
1265 newDoc->SetDocumentTemplate(temp);
f5729a6b
JS
1266 if (!newDoc->OnNewDocument() )
1267 {
1268 // Document is implicitly deleted by DeleteAllViews
1269 newDoc->DeleteAllViews();
1270 return NULL;
1271 }
0fb67cd1
VZ
1272 }
1273 return newDoc;
1274 }
1275 else
1276 return (wxDocument *) NULL;
c801d85f 1277 }
c801d85f 1278
0fb67cd1 1279 // Existing document
999836aa 1280 wxDocTemplate *temp;
c801d85f 1281
b494c48b 1282 wxString path2 = path;
c801d85f 1283
0fb67cd1 1284 if (flags & wxDOC_SILENT)
9d4a05be 1285 {
0fb67cd1 1286 temp = FindTemplateForPath(path2);
9d4a05be
JS
1287 if (!temp)
1288 {
42771621 1289 // Since we do not add files with non-default extensions to the FileHistory this
9d4a05be
JS
1290 // can only happen if the application changes the allowed templates in runtime.
1291 (void)wxMessageBox(_("Sorry, the format for this file is unknown."),
42771621 1292 _("Open File"),
9d4a05be
JS
1293 wxOK | wxICON_EXCLAMATION, wxFindSuitableParent());
1294 }
1295 }
0fb67cd1
VZ
1296 else
1297 temp = SelectDocumentPath(templates, n, path2, flags);
c801d85f 1298
0fb67cd1 1299 delete[] templates;
c801d85f 1300
0fb67cd1 1301 if (temp)
c801d85f 1302 {
b72b1920
JS
1303 if (docToClose)
1304 {
68379eaf 1305 if (!CloseDocument(docToClose, false))
b72b1920
JS
1306 {
1307 return NULL;
1308 }
1309 }
42771621 1310
6489e7ee
JS
1311 //see if this file is already open
1312 for (size_t i = 0; i < GetDocuments().GetCount(); ++i)
1313 {
1314 wxDocument* currentDoc = (wxDocument*)(GetDocuments().Item(i)->GetData());
1315#ifdef __WXMSW__
1316 //file paths are case-insensitive on Windows
1317 if (path2.CmpNoCase(currentDoc->GetFilename()) == 0)
1318#else
1319 if (path2.Cmp(currentDoc->GetFilename()) == 0)
1320#endif
1321 {
1322 //file already open. Just activate it and return
1323 if (currentDoc->GetFirstView())
1324 {
1325 ActivateView(currentDoc->GetFirstView(), true);
1326 if (currentDoc->GetDocumentWindow())
1327 currentDoc->GetDocumentWindow()->SetFocus();
1328 return currentDoc;
1329 }
1330 }
1331 }
1332
0fb67cd1
VZ
1333 wxDocument *newDoc = temp->CreateDocument(path2, flags);
1334 if (newDoc)
1335 {
1336 newDoc->SetDocumentName(temp->GetDocumentName());
1337 newDoc->SetDocumentTemplate(temp);
1338 if (!newDoc->OnOpenDocument(path2))
1339 {
f6bcfd97
BP
1340 newDoc->DeleteAllViews();
1341 // delete newDoc; // Implicitly deleted by DeleteAllViews
0fb67cd1
VZ
1342 return (wxDocument *) NULL;
1343 }
9d4a05be
JS
1344 // A file that doesn't use the default extension of its document
1345 // template cannot be opened via the FileHistory, so we do not
1346 // add it.
1347 if (temp->FileMatchesTemplate(path2))
1348 AddFileToHistory(path2);
0fb67cd1
VZ
1349 }
1350 return newDoc;
c801d85f 1351 }
3ca6a5f0
BP
1352
1353 return (wxDocument *) NULL;
c801d85f
KB
1354}
1355
1356wxView *wxDocManager::CreateView(wxDocument *doc, long flags)
1357{
b1d4dd7a
RL
1358 wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()];
1359 int n =0;
1360
1361 for (size_t i = 0; i < m_templates.GetCount(); i++)
0fb67cd1 1362 {
b1d4dd7a 1363 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData());
0fb67cd1
VZ
1364 if (temp->IsVisible())
1365 {
1366 if (temp->GetDocumentName() == doc->GetDocumentName())
1367 {
1368 templates[n] = temp;
1369 n ++;
1370 }
1371 }
1372 }
1373 if (n == 0)
1374 {
1375 delete[] templates;
1376 return (wxView *) NULL;
1377 }
1378 if (n == 1)
1379 {
1380 wxDocTemplate *temp = templates[0];
1381 delete[] templates;
1382 wxView *view = temp->CreateView(doc, flags);
1383 if (view)
1384 view->SetViewName(temp->GetViewName());
1385 return view;
1386 }
1387
1388 wxDocTemplate *temp = SelectViewType(templates, n);
c801d85f 1389 delete[] templates;
0fb67cd1
VZ
1390 if (temp)
1391 {
1392 wxView *view = temp->CreateView(doc, flags);
1393 if (view)
1394 view->SetViewName(temp->GetViewName());
1395 return view;
1396 }
1397 else
1398 return (wxView *) NULL;
c801d85f
KB
1399}
1400
1401// Not yet implemented
1402void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags))
1403{
1404}
1405
1406// Not yet implemented
1407bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc))
1408{
68379eaf 1409 return false;
c801d85f
KB
1410}
1411
6de2f8b9 1412wxDocument *wxDocManager::GetCurrentDocument() const
c801d85f 1413{
9cb0033c
VZ
1414 wxView *view = GetCurrentView();
1415 if (view)
1416 return view->GetDocument();
0fb67cd1
VZ
1417 else
1418 return (wxDocument *) NULL;
c801d85f
KB
1419}
1420
724b119a
VZ
1421// Make a default name for a new document
1422#if WXWIN_COMPATIBILITY_2_8
1423bool wxDocManager::MakeDefaultName(wxString& WXUNUSED(name))
1424{
1425 // we consider that this function can only be overridden by the user code,
1426 // not called by it as it only makes sense to call it internally, so we
1427 // don't bother to return anything from here
1428 return false;
1429}
1430#endif // WXWIN_COMPATIBILITY_2_8
1431
1432wxString wxDocManager::MakeNewDocumentName()
c801d85f 1433{
724b119a 1434 wxString name;
53c6e7cc 1435
724b119a
VZ
1436#if WXWIN_COMPATIBILITY_2_8
1437 if ( !MakeDefaultName(name) )
1438#endif // WXWIN_COMPATIBILITY_2_8
1439 {
1440 name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter);
1441 m_defaultDocumentNameCounter++;
1442 }
1443
1444 return name;
c801d85f
KB
1445}
1446
f2506310
JS
1447// Make a frame title (override this to do something different)
1448// If docName is empty, a document is not currently active.
1449wxString wxDocManager::MakeFrameTitle(wxDocument* doc)
1450{
1451 wxString appName = wxTheApp->GetAppName();
1452 wxString title;
1453 if (!doc)
1454 title = appName;
1455 else
1456 {
724b119a 1457 wxString docName = doc->GetUserReadableName();
f2506310
JS
1458 title = docName + wxString(_(" - ")) + appName;
1459 }
1460 return title;
1461}
1462
1463
c801d85f
KB
1464// Not yet implemented
1465wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path))
1466{
0fb67cd1 1467 return (wxDocTemplate *) NULL;
c801d85f
KB
1468}
1469
1470// File history management
1471void wxDocManager::AddFileToHistory(const wxString& file)
1472{
0fb67cd1
VZ
1473 if (m_fileHistory)
1474 m_fileHistory->AddFileToHistory(file);
c801d85f
KB
1475}
1476
e49c85af 1477void wxDocManager::RemoveFileFromHistory(size_t i)
0c5d3e1c
VZ
1478{
1479 if (m_fileHistory)
1480 m_fileHistory->RemoveFileFromHistory(i);
1481}
1482
e49c85af 1483wxString wxDocManager::GetHistoryFile(size_t i) const
c801d85f 1484{
0fb67cd1
VZ
1485 wxString histFile;
1486
1487 if (m_fileHistory)
1488 histFile = m_fileHistory->GetHistoryFile(i);
1489
1490 return histFile;
c801d85f
KB
1491}
1492
1493void wxDocManager::FileHistoryUseMenu(wxMenu *menu)
1494{
0fb67cd1
VZ
1495 if (m_fileHistory)
1496 m_fileHistory->UseMenu(menu);
c801d85f
KB
1497}
1498
7f555861 1499void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu)
c801d85f 1500{
0fb67cd1
VZ
1501 if (m_fileHistory)
1502 m_fileHistory->RemoveMenu(menu);
c801d85f
KB
1503}
1504
702ca7c0 1505#if wxUSE_CONFIG
7f555861 1506void wxDocManager::FileHistoryLoad(wxConfigBase& config)
c801d85f 1507{
0fb67cd1
VZ
1508 if (m_fileHistory)
1509 m_fileHistory->Load(config);
7f555861
JS
1510}
1511
1512void wxDocManager::FileHistorySave(wxConfigBase& config)
1513{
0fb67cd1
VZ
1514 if (m_fileHistory)
1515 m_fileHistory->Save(config);
7f555861 1516}
ac57418f 1517#endif
7f555861
JS
1518
1519void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu)
1520{
0fb67cd1
VZ
1521 if (m_fileHistory)
1522 m_fileHistory->AddFilesToMenu(menu);
7f555861
JS
1523}
1524
1525void wxDocManager::FileHistoryAddFilesToMenu()
1526{
0fb67cd1
VZ
1527 if (m_fileHistory)
1528 m_fileHistory->AddFilesToMenu();
c801d85f
KB
1529}
1530
7af6b69e 1531size_t wxDocManager::GetHistoryFilesCount() const
c801d85f 1532{
7af6b69e 1533 return m_fileHistory ? m_fileHistory->GetCount() : 0;
c801d85f
KB
1534}
1535
1536
6de2f8b9
VZ
1537// Find out the document template via matching in the document file format
1538// against that of the template
c801d85f
KB
1539wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path)
1540{
0fb67cd1 1541 wxDocTemplate *theTemplate = (wxDocTemplate *) NULL;
c801d85f 1542
0fb67cd1 1543 // Find the template which this extension corresponds to
b1d4dd7a 1544 for (size_t i = 0; i < m_templates.GetCount(); i++)
c801d85f 1545 {
b1d4dd7a 1546 wxDocTemplate *temp = (wxDocTemplate *)m_templates.Item(i)->GetData();
6de2f8b9 1547 if ( temp->FileMatchesTemplate(path) )
0fb67cd1
VZ
1548 {
1549 theTemplate = temp;
1550 break;
1551 }
c801d85f 1552 }
0fb67cd1 1553 return theTemplate;
c801d85f
KB
1554}
1555
f6bcfd97
BP
1556// Try to get a more suitable parent frame than the top window,
1557// for selection dialogs. Otherwise you may get an unexpected
1558// window being activated when a dialog is shown.
1559static wxWindow* wxFindSuitableParent()
1560{
1561 wxWindow* parent = wxTheApp->GetTopWindow();
1562
1563 wxWindow* focusWindow = wxWindow::FindFocus();
1564 if (focusWindow)
1565 {
1566 while (focusWindow &&
1567 !focusWindow->IsKindOf(CLASSINFO(wxDialog)) &&
1568 !focusWindow->IsKindOf(CLASSINFO(wxFrame)))
1569
1570 focusWindow = focusWindow->GetParent();
1571
1572 if (focusWindow)
1573 parent = focusWindow;
1574 }
1575 return parent;
1576}
1577
c801d85f 1578// Prompts user to open a file, using file specs in templates.
9d4a05be
JS
1579// Must extend the file selector dialog or implement own; OR
1580// match the extension to the template extension.
df875e59 1581
c801d85f 1582wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates,
ce68ad25 1583#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__)
0fb67cd1 1584 int noTemplates,
f6147cfc
VZ
1585#else
1586 int WXUNUSED(noTemplates),
1587#endif
0fb67cd1
VZ
1588 wxString& path,
1589 long WXUNUSED(flags),
1590 bool WXUNUSED(save))
c801d85f 1591{
bf9e3e73 1592 // We can only have multiple filters in Windows and GTK
ce68ad25 1593#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__)
ba681060
VZ
1594 wxString descrBuf;
1595
1596 int i;
1597 for (i = 0; i < noTemplates; i++)
c801d85f 1598 {
ba681060
VZ
1599 if (templates[i]->IsVisible())
1600 {
1601 // add a '|' to separate this filter from the previous one
b494c48b 1602 if ( !descrBuf.empty() )
223d09f6 1603 descrBuf << wxT('|');
ba681060
VZ
1604
1605 descrBuf << templates[i]->GetDescription()
223d09f6 1606 << wxT(" (") << templates[i]->GetFileFilter() << wxT(") |")
0fb67cd1 1607 << templates[i]->GetFileFilter();
ba681060 1608 }
c801d85f 1609 }
a4294b78 1610#else
223d09f6 1611 wxString descrBuf = wxT("*.*");
a4294b78 1612#endif
c801d85f 1613
3ca6a5f0 1614 int FilterIndex = -1;
f6bcfd97
BP
1615
1616 wxWindow* parent = wxFindSuitableParent();
1617
6de2f8b9 1618 wxString pathTmp = wxFileSelectorEx(_("Select a file"),
ac0ac824 1619 m_lastDirectory,
b494c48b 1620 wxEmptyString,
6de2f8b9 1621 &FilterIndex,
caf0debf
VZ
1622 descrBuf,
1623 0,
f6bcfd97 1624 parent);
ba681060 1625
3ca6a5f0 1626 wxDocTemplate *theTemplate = (wxDocTemplate *)NULL;
b494c48b 1627 if (!pathTmp.empty())
0fb67cd1 1628 {
f6bcfd97
BP
1629 if (!wxFileExists(pathTmp))
1630 {
1631 wxString msgTitle;
b494c48b 1632 if (!wxTheApp->GetAppName().empty())
f6bcfd97
BP
1633 msgTitle = wxTheApp->GetAppName();
1634 else
1635 msgTitle = wxString(_("File error"));
02718e6a 1636
f6bcfd97
BP
1637 (void)wxMessageBox(_("Sorry, could not open this file."), msgTitle, wxOK | wxICON_EXCLAMATION,
1638 parent);
1639
b494c48b 1640 path = wxEmptyString;
f6bcfd97
BP
1641 return (wxDocTemplate *) NULL;
1642 }
ac0ac824
JS
1643 m_lastDirectory = wxPathOnly(pathTmp);
1644
0fb67cd1 1645 path = pathTmp;
0fb67cd1 1646
3ca6a5f0
BP
1647 // first choose the template using the extension, if this fails (i.e.
1648 // wxFileSelectorEx() didn't fill it), then use the path
1649 if ( FilterIndex != -1 )
6de2f8b9 1650 theTemplate = templates[FilterIndex];
3ca6a5f0
BP
1651 if ( !theTemplate )
1652 theTemplate = FindTemplateForPath(path);
9d4a05be
JS
1653 if ( !theTemplate )
1654 {
42771621 1655 // Since we do not add files with non-default extensions to the FileHistory this
9d4a05be
JS
1656 // can only happen if the application changes the allowed templates in runtime.
1657 (void)wxMessageBox(_("Sorry, the format for this file is unknown."),
42771621 1658 _("Open File"),
9d4a05be
JS
1659 wxOK | wxICON_EXCLAMATION, wxFindSuitableParent());
1660 }
0fb67cd1
VZ
1661 }
1662 else
1663 {
b494c48b 1664 path = wxEmptyString;
0fb67cd1 1665 }
3ca6a5f0
BP
1666
1667 return theTemplate;
c801d85f
KB
1668}
1669
1670wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates,
52b9ca21 1671 int noTemplates, bool sort)
0fb67cd1 1672{
222ed1d6 1673 wxArrayString strings;
17260efd 1674 wxDocTemplate **data = new wxDocTemplate *[noTemplates];
0fb67cd1
VZ
1675 int i;
1676 int n = 0;
42771621
VZ
1677
1678 for (i = 0; i < noTemplates; i++)
1679 {
1680 if (templates[i]->IsVisible())
1681 {
1682 int j;
68379eaf 1683 bool want = true;
42771621
VZ
1684 for (j = 0; j < n; j++)
1685 {
bb28b477 1686 //filter out NOT unique documents + view combinations
42771621 1687 if ( templates[i]->m_docTypeName == data[j]->m_docTypeName &&
bb28b477
JS
1688 templates[i]->m_viewTypeName == data[j]->m_viewTypeName
1689 )
68379eaf 1690 want = false;
42771621 1691 }
bb28b477
JS
1692
1693 if ( want )
42771621
VZ
1694 {
1695 strings.Add(templates[i]->m_description);
1696
1697 data[n] = templates[i];
1698 n ++;
1699 }
1700 }
1701 } // for
1702
1703 if (sort)
1704 {
a2a03d78 1705 strings.Sort(); // ascending sort
42771621
VZ
1706 // Yes, this will be slow, but template lists
1707 // are typically short.
1708 int j;
1709 n = strings.Count();
1710 for (i = 0; i < n; i++)
1711 {
1712 for (j = 0; j < noTemplates; j++)
1713 {
1714 if (strings[i] == templates[j]->m_description)
1715 data[i] = templates[j];
1716 }
1717 }
1718 }
17260efd
VZ
1719
1720 wxDocTemplate *theTemplate;
1721
1722 switch ( n )
0fb67cd1 1723 {
17260efd
VZ
1724 case 0:
1725 // no visible templates, hence nothing to choose from
1726 theTemplate = NULL;
1727 break;
0fb67cd1 1728
17260efd
VZ
1729 case 1:
1730 // don't propose the user to choose if he heas no choice
1731 theTemplate = data[0];
1732 break;
1733
1734 default:
1735 // propose the user to choose one of several
1736 theTemplate = (wxDocTemplate *)wxGetSingleChoiceData
1737 (
1738 _("Select a document template"),
1739 _("Templates"),
1740 strings,
1741 (void **)data,
1742 wxFindSuitableParent()
1743 );
1744 }
f6bcfd97 1745
c801d85f 1746 delete[] data;
17260efd 1747
0fb67cd1 1748 return theTemplate;
c801d85f
KB
1749}
1750
1751wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates,
52b9ca21 1752 int noTemplates, bool sort)
c801d85f 1753{
222ed1d6 1754 wxArrayString strings;
17260efd 1755 wxDocTemplate **data = new wxDocTemplate *[noTemplates];
0fb67cd1
VZ
1756 int i;
1757 int n = 0;
42771621 1758
0fb67cd1 1759 for (i = 0; i < noTemplates; i++)
c801d85f 1760 {
17260efd
VZ
1761 wxDocTemplate *templ = templates[i];
1762 if ( templ->IsVisible() && !templ->GetViewName().empty() )
0fb67cd1 1763 {
42771621 1764 int j;
68379eaf 1765 bool want = true;
42771621
VZ
1766 for (j = 0; j < n; j++)
1767 {
bb28b477 1768 //filter out NOT unique views
42771621 1769 if ( templates[i]->m_viewTypeName == data[j]->m_viewTypeName )
68379eaf 1770 want = false;
42771621 1771 }
bb28b477
JS
1772
1773 if ( want )
1774 {
42771621
VZ
1775 strings.Add(templ->m_viewTypeName);
1776 data[n] = templ;
1777 n ++;
1778 }
0fb67cd1 1779 }
c801d85f 1780 }
f6bcfd97 1781
42771621
VZ
1782 if (sort)
1783 {
a2a03d78 1784 strings.Sort(); // ascending sort
42771621
VZ
1785 // Yes, this will be slow, but template lists
1786 // are typically short.
1787 int j;
1788 n = strings.Count();
1789 for (i = 0; i < n; i++)
1790 {
1791 for (j = 0; j < noTemplates; j++)
1792 {
1793 if (strings[i] == templates[j]->m_viewTypeName)
1794 data[i] = templates[j];
1795 }
1796 }
1797 }
8658ef93 1798
17260efd
VZ
1799 wxDocTemplate *theTemplate;
1800
1801 // the same logic as above
1802 switch ( n )
1803 {
1804 case 0:
1805 theTemplate = (wxDocTemplate *)NULL;
1806 break;
1807
1808 case 1:
1809 theTemplate = data[0];
1810 break;
1811
1812 default:
1813 theTemplate = (wxDocTemplate *)wxGetSingleChoiceData
1814 (
1815 _("Select a document view"),
1816 _("Views"),
1817 strings,
1818 (void **)data,
1819 wxFindSuitableParent()
1820 );
1821
1822 }
1823
0fb67cd1
VZ
1824 delete[] data;
1825 return theTemplate;
c801d85f
KB
1826}
1827
1828void wxDocManager::AssociateTemplate(wxDocTemplate *temp)
1829{
0fb67cd1
VZ
1830 if (!m_templates.Member(temp))
1831 m_templates.Append(temp);
c801d85f
KB
1832}
1833
1834void wxDocManager::DisassociateTemplate(wxDocTemplate *temp)
1835{
0fb67cd1 1836 m_templates.DeleteObject(temp);
c801d85f
KB
1837}
1838
1839// Add and remove a document from the manager's list
1840void wxDocManager::AddDocument(wxDocument *doc)
1841{
0fb67cd1
VZ
1842 if (!m_docs.Member(doc))
1843 m_docs.Append(doc);
c801d85f
KB
1844}
1845
1846void wxDocManager::RemoveDocument(wxDocument *doc)
1847{
0fb67cd1 1848 m_docs.DeleteObject(doc);
c801d85f
KB
1849}
1850
1851// Views or windows should inform the document manager
1852// when a view is going in or out of focus
18759f78
VZ
1853void wxDocManager::ActivateView(wxView *view, bool activate)
1854{
1855 if ( activate )
0fb67cd1 1856 {
18759f78
VZ
1857 m_currentView = view;
1858 }
1859 else // deactivate
1860 {
1861 if ( m_currentView == view )
1862 {
1863 // don't keep stale pointer
0fb67cd1 1864 m_currentView = (wxView *) NULL;
18759f78 1865 }
0fb67cd1 1866 }
c801d85f
KB
1867}
1868
0fb67cd1
VZ
1869// ----------------------------------------------------------------------------
1870// Default document child frame
1871// ----------------------------------------------------------------------------
c801d85f
KB
1872
1873BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame)
1874 EVT_ACTIVATE(wxDocChildFrame::OnActivate)
387a3b02 1875 EVT_CLOSE(wxDocChildFrame::OnCloseWindow)
c801d85f
KB
1876END_EVENT_TABLE()
1877
0fb67cd1
VZ
1878wxDocChildFrame::wxDocChildFrame(wxDocument *doc,
1879 wxView *view,
1880 wxFrame *frame,
1881 wxWindowID id,
1882 const wxString& title,
1883 const wxPoint& pos,
1884 const wxSize& size,
1885 long style,
1886 const wxString& name)
1887 : wxFrame(frame, id, title, pos, size, style, name)
1888{
1889 m_childDocument = doc;
1890 m_childView = view;
1891 if (view)
1892 view->SetFrame(this);
c801d85f
KB
1893}
1894
c801d85f
KB
1895// Extend event processing to search the view's event table
1896bool wxDocChildFrame::ProcessEvent(wxEvent& event)
1897{
1898 if (m_childView)
68379eaf 1899 m_childView->Activate(true);
c801d85f 1900
0fb67cd1 1901 if ( !m_childView || ! m_childView->ProcessEvent(event) )
c801d85f
KB
1902 {
1903 // Only hand up to the parent if it's a menu command
1904 if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event))
0fb67cd1 1905 return wxEvtHandler::ProcessEvent(event);
c801d85f 1906 else
68379eaf 1907 return true;
c801d85f 1908 }
0fb67cd1 1909 else
68379eaf 1910 return true;
c801d85f
KB
1911}
1912
c801d85f
KB
1913void wxDocChildFrame::OnActivate(wxActivateEvent& event)
1914{
0fb67cd1 1915 wxFrame::OnActivate(event);
c801d85f 1916
0fb67cd1
VZ
1917 if (m_childView)
1918 m_childView->Activate(event.GetActive());
c801d85f
KB
1919}
1920
387a3b02 1921void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event)
c801d85f 1922{
0fb67cd1 1923 if (m_childView)
c801d85f 1924 {
999836aa 1925 bool ans = event.CanVeto()
68379eaf
WS
1926 ? m_childView->Close(false) // false means don't delete associated window
1927 : true; // Must delete.
387a3b02 1928
0fb67cd1
VZ
1929 if (ans)
1930 {
68379eaf 1931 m_childView->Activate(false);
0fb67cd1
VZ
1932 delete m_childView;
1933 m_childView = (wxView *) NULL;
1934 m_childDocument = (wxDocument *) NULL;
1935
1936 this->Destroy();
1937 }
1938 else
1939 event.Veto();
c801d85f 1940 }
387a3b02 1941 else
0fb67cd1 1942 event.Veto();
c801d85f
KB
1943}
1944
0fb67cd1
VZ
1945// ----------------------------------------------------------------------------
1946// Default parent frame
1947// ----------------------------------------------------------------------------
c801d85f
KB
1948
1949BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame)
1950 EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit)
f7bd2698 1951 EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile)
387a3b02 1952 EVT_CLOSE(wxDocParentFrame::OnCloseWindow)
c801d85f
KB
1953END_EVENT_TABLE()
1954
0c246b3c
PC
1955wxDocParentFrame::wxDocParentFrame()
1956{
1957 m_docManager = NULL;
1958}
1959
0fb67cd1
VZ
1960wxDocParentFrame::wxDocParentFrame(wxDocManager *manager,
1961 wxFrame *frame,
1962 wxWindowID id,
1963 const wxString& title,
1964 const wxPoint& pos,
1965 const wxSize& size,
1966 long style,
1967 const wxString& name)
1968 : wxFrame(frame, id, title, pos, size, style, name)
c801d85f 1969{
0fb67cd1 1970 m_docManager = manager;
c801d85f
KB
1971}
1972
0c246b3c
PC
1973bool wxDocParentFrame::Create(wxDocManager *manager,
1974 wxFrame *frame,
1975 wxWindowID id,
1976 const wxString& title,
1977 const wxPoint& pos,
1978 const wxSize& size,
1979 long style,
1980 const wxString& name)
1981{
1982 m_docManager = manager;
1983 return base_type::Create(frame, id, title, pos, size, style, name);
1984}
1985
c801d85f
KB
1986void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event))
1987{
1988 Close();
1989}
1990
1991void wxDocParentFrame::OnMRUFile(wxCommandEvent& event)
1992{
1fc88785 1993 int n = event.GetId() - wxID_FILE1; // the index in MRU list
0c5d3e1c 1994 wxString filename(m_docManager->GetHistoryFile(n));
b494c48b 1995 if ( !filename.empty() )
0c5d3e1c
VZ
1996 {
1997 // verify that the file exists before doing anything else
1998 if ( wxFile::Exists(filename) )
1999 {
2000 // try to open it
9d4a05be
JS
2001 if (!m_docManager->CreateDocument(filename, wxDOC_SILENT))
2002 {
2003 // remove the file from the MRU list. The user should already be notified.
2004 m_docManager->RemoveFileFromHistory(n);
42771621 2005
9d4a05be
JS
2006 wxLogError(_("The file '%s' couldn't be opened.\nIt has been removed from the most recently used files list."),
2007 filename.c_str());
2008 }
0c5d3e1c
VZ
2009 }
2010 else
2011 {
2012 // remove the bogus filename from the MRU list and notify the user
2013 // about it
2014 m_docManager->RemoveFileFromHistory(n);
2015
9806a0e7 2016 wxLogError(_("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list."),
0c5d3e1c
VZ
2017 filename.c_str());
2018 }
2019 }
c801d85f
KB
2020}
2021
2022// Extend event processing to search the view's event table
2023bool wxDocParentFrame::ProcessEvent(wxEvent& event)
2024{
2025 // Try the document manager, then do default processing
2026 if (!m_docManager || !m_docManager->ProcessEvent(event))
2027 return wxEvtHandler::ProcessEvent(event);
2028 else
68379eaf 2029 return true;
c801d85f
KB
2030}
2031
c801d85f
KB
2032// Define the behaviour for the frame closing
2033// - must delete all frames except for the main one.
387a3b02 2034void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event)
c801d85f 2035{
0fb67cd1
VZ
2036 if (m_docManager->Clear(!event.CanVeto()))
2037 {
2038 this->Destroy();
2039 }
2040 else
2041 event.Veto();
c801d85f
KB
2042}
2043
47d67540 2044#if wxUSE_PRINTING_ARCHITECTURE
c801d85f 2045
0fb67cd1 2046wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title)
e90c1d2a 2047 : wxPrintout(title)
c801d85f 2048{
0fb67cd1 2049 m_printoutView = view;
c801d85f
KB
2050}
2051
2052bool wxDocPrintout::OnPrintPage(int WXUNUSED(page))
2053{
0fb67cd1
VZ
2054 wxDC *dc = GetDC();
2055
2056 // Get the logical pixels per inch of screen and printer
2057 int ppiScreenX, ppiScreenY;
2058 GetPPIScreen(&ppiScreenX, &ppiScreenY);
999836aa 2059 wxUnusedVar(ppiScreenY);
0fb67cd1
VZ
2060 int ppiPrinterX, ppiPrinterY;
2061 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
999836aa 2062 wxUnusedVar(ppiPrinterY);
0fb67cd1
VZ
2063
2064 // This scales the DC so that the printout roughly represents the
2065 // the screen scaling. The text point size _should_ be the right size
2066 // but in fact is too small for some reason. This is a detail that will
2067 // need to be addressed at some point but can be fudged for the
2068 // moment.
2069 float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
2070
2071 // Now we have to check in case our real page size is reduced
2072 // (e.g. because we're drawing to a print preview memory DC)
2073 int pageWidth, pageHeight;
2074 int w, h;
2075 dc->GetSize(&w, &h);
2076 GetPageSizePixels(&pageWidth, &pageHeight);
999836aa 2077 wxUnusedVar(pageHeight);
0fb67cd1
VZ
2078
2079 // If printer pageWidth == current DC width, then this doesn't
2080 // change. But w might be the preview bitmap width, so scale down.
2081 float overallScale = scale * (float)(w/(float)pageWidth);
2082 dc->SetUserScale(overallScale, overallScale);
2083
2084 if (m_printoutView)
2085 {
2086 m_printoutView->OnDraw(dc);
2087 }
68379eaf 2088 return true;
c801d85f
KB
2089}
2090
2091bool wxDocPrintout::HasPage(int pageNum)
2092{
0fb67cd1 2093 return (pageNum == 1);
c801d85f
KB
2094}
2095
2096bool wxDocPrintout::OnBeginDocument(int startPage, int endPage)
2097{
0fb67cd1 2098 if (!wxPrintout::OnBeginDocument(startPage, endPage))
68379eaf 2099 return false;
c801d85f 2100
68379eaf 2101 return true;
c801d85f
KB
2102}
2103
2104void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
2105{
0fb67cd1
VZ
2106 *minPage = 1;
2107 *maxPage = 1;
2108 *selPageFrom = 1;
2109 *selPageTo = 1;
c801d85f
KB
2110}
2111
0fb67cd1 2112#endif // wxUSE_PRINTING_ARCHITECTURE
c801d85f 2113
0fb67cd1
VZ
2114// ----------------------------------------------------------------------------
2115// File history processor
2116// ----------------------------------------------------------------------------
c801d85f 2117
e49c85af 2118wxFileHistory::wxFileHistory(size_t maxFiles, wxWindowID idBase)
c801d85f 2119{
0fb67cd1 2120 m_fileMaxFiles = maxFiles;
e49c85af 2121 m_idBase = idBase;
c801d85f
KB
2122}
2123
0fb67cd1 2124wxFileHistory::~wxFileHistory()
c801d85f 2125{
c801d85f
KB
2126}
2127
c801d85f
KB
2128void wxFileHistory::AddFileToHistory(const wxString& file)
2129{
b4a980f4 2130 wxFileName fn(file);
e49c85af 2131 size_t i;
02718e6a 2132
0fb67cd1 2133 // Check we don't already have this file
b4a980f4 2134 for (i = 0; i < m_fileHistory.GetCount(); i++)
7f555861 2135 {
b4a980f4
VZ
2136 // we need to do a comparison using wxFileNames because it knows
2137 // how to exactly compare files on the different platforms
2138 // (e.g. handle case [in]sensitive filesystems)
2139 if ( fn == wxFileName(m_fileHistory[i]) )
02718e6a
VZ
2140 {
2141 // we do have it, move it to the top of the history
2142 RemoveFileFromHistory (i);
2143 AddFileToHistory (file);
0fb67cd1 2144 return;
02718e6a 2145 }
7f555861 2146 }
0fb67cd1 2147
02718e6a 2148 // if we already have a full history, delete the one at the end
b4a980f4 2149 if ( m_fileMaxFiles == m_fileHistory.GetCount() )
0fb67cd1 2150 {
b4a980f4 2151 RemoveFileFromHistory (m_fileHistory.GetCount() - 1);
02718e6a
VZ
2152 AddFileToHistory (file);
2153 return;
c801d85f 2154 }
02718e6a
VZ
2155
2156 // Add to the project file history:
2157 // Move existing files (if any) down so we can insert file at beginning.
b4a980f4 2158 if (m_fileHistory.GetCount() < m_fileMaxFiles)
0fb67cd1 2159 {
222ed1d6 2160 wxList::compatibility_iterator node = m_fileMenus.GetFirst();
0fb67cd1
VZ
2161 while (node)
2162 {
b1d4dd7a 2163 wxMenu* menu = (wxMenu*) node->GetData();
b4a980f4 2164 if ( m_fileHistory.IsEmpty() && menu->GetMenuItemCount() )
c8c5c7f6 2165 {
0fb67cd1 2166 menu->AppendSeparator();
c8c5c7f6 2167 }
b4a980f4 2168 menu->Append(m_idBase+m_fileHistory.GetCount(), _("[EMPTY]"));
b1d4dd7a 2169 node = node->GetNext();
0fb67cd1 2170 }
0fb67cd1 2171 }
b4a980f4
VZ
2172
2173 m_fileHistory.Insert(file, 0);
0fb67cd1 2174
02718e6a
VZ
2175 // this is the directory of the last opened file
2176 wxString pathCurrent;
2177 wxSplitPath( m_fileHistory[0], &pathCurrent, NULL, NULL );
b4a980f4 2178 for (i = 0; i < m_fileHistory.GetCount(); i++)
0fb67cd1 2179 {
02718e6a
VZ
2180 // if in same directory just show the filename; otherwise the full
2181 // path
2182 wxString pathInMenu, path, filename, ext;
2183 wxSplitPath( m_fileHistory[i], &path, &filename, &ext );
2184 if ( path == pathCurrent )
2185 {
2186 pathInMenu = filename;
2187 if ( !ext.empty() )
2188 pathInMenu = pathInMenu + wxFILE_SEP_EXT + ext;
2189 }
2190 else
2191 {
2192 // absolute path; could also set relative path
2193 pathInMenu = m_fileHistory[i];
2194 }
2195
28ea89b6
VZ
2196 // we need to quote '&' characters which are used for mnemonics
2197 pathInMenu.Replace(_T("&"), _T("&&"));
b4a980f4 2198
0fb67cd1 2199 wxString buf;
02718e6a 2200 buf.Printf(s_MRUEntryFormat, i + 1, pathInMenu.c_str());
b4a980f4 2201
222ed1d6 2202 wxList::compatibility_iterator node = m_fileMenus.GetFirst();
0fb67cd1
VZ
2203 while (node)
2204 {
b1d4dd7a 2205 wxMenu* menu = (wxMenu*) node->GetData();
e49c85af 2206 menu->SetLabel(m_idBase + i, buf);
b1d4dd7a 2207 node = node->GetNext();
0fb67cd1
VZ
2208 }
2209 }
c801d85f
KB
2210}
2211
e49c85af 2212void wxFileHistory::RemoveFileFromHistory(size_t i)
0c5d3e1c 2213{
b4a980f4 2214 wxCHECK_RET( i < m_fileHistory.GetCount(),
223d09f6 2215 wxT("invalid index in wxFileHistory::RemoveFileFromHistory") );
0c5d3e1c 2216
b4a980f4
VZ
2217 // delete the element from the array
2218 m_fileHistory.RemoveAt(i);
0c5d3e1c 2219
222ed1d6 2220 wxList::compatibility_iterator node = m_fileMenus.GetFirst();
00e6d8ab
VZ
2221 while ( node )
2222 {
4a10ea8b 2223 wxMenu* menu = (wxMenu*) node->GetData();
00e6d8ab 2224
4a10ea8b
MW
2225 // shuffle filenames up
2226 wxString buf;
b4a980f4 2227 for ( size_t j = i; j < m_fileHistory.GetCount(); j++ )
4a10ea8b 2228 {
b4a980f4 2229 buf.Printf(s_MRUEntryFormat, j + 1, m_fileHistory[j].c_str());
4a10ea8b
MW
2230 menu->SetLabel(m_idBase + j, buf);
2231 }
0c5d3e1c 2232
4a10ea8b 2233 node = node->GetNext();
2b273975
VZ
2234
2235 // delete the last menu item which is unused now
b4a980f4 2236 wxWindowID lastItemId = m_idBase + wx_truncate_cast(wxWindowID, m_fileHistory.GetCount());
e49c85af
VZ
2237 if (menu->FindItem(lastItemId))
2238 {
2239 menu->Delete(lastItemId);
2240 }
2b273975 2241
717a57c2 2242 // delete the last separator too if no more files are left
b4a980f4 2243 if ( m_fileHistory.GetCount() == 0 )
717a57c2 2244 {
f1afd2e0
VZ
2245 wxMenuItemList::compatibility_iterator nodeLast = menu->GetMenuItems().GetLast();
2246 if ( nodeLast )
717a57c2 2247 {
f1afd2e0 2248 wxMenuItem *menuItem = nodeLast->GetData();
717a57c2
VZ
2249 if ( menuItem->IsSeparator() )
2250 {
2251 menu->Delete(menuItem);
2252 }
2253 //else: should we search backwards for the last separator?
2254 }
2255 //else: menu is empty somehow
2256 }
0c5d3e1c 2257 }
c801d85f
KB
2258}
2259
7f555861 2260void wxFileHistory::UseMenu(wxMenu *menu)
c801d85f 2261{
0fb67cd1
VZ
2262 if (!m_fileMenus.Member(menu))
2263 m_fileMenus.Append(menu);
c801d85f
KB
2264}
2265
7f555861
JS
2266void wxFileHistory::RemoveMenu(wxMenu *menu)
2267{
0fb67cd1 2268 m_fileMenus.DeleteObject(menu);
7f555861
JS
2269}
2270
702ca7c0 2271#if wxUSE_CONFIG
7f555861 2272void wxFileHistory::Load(wxConfigBase& config)
c801d85f 2273{
b4a980f4
VZ
2274 m_fileHistory.Clear();
2275
0fb67cd1 2276 wxString buf;
b4a980f4
VZ
2277 buf.Printf(wxT("file%d"), 1);
2278
0fb67cd1 2279 wxString historyFile;
b4a980f4
VZ
2280 while ((m_fileHistory.GetCount() < m_fileMaxFiles) &&
2281 config.Read(buf, &historyFile) && !historyFile.empty())
0fb67cd1 2282 {
b4a980f4
VZ
2283 m_fileHistory.Add(historyFile);
2284
2285 buf.Printf(wxT("file%d"), (int)m_fileHistory.GetCount()+1);
b494c48b 2286 historyFile = wxEmptyString;
0fb67cd1 2287 }
b4a980f4 2288
0fb67cd1 2289 AddFilesToMenu();
c801d85f
KB
2290}
2291
7f555861 2292void wxFileHistory::Save(wxConfigBase& config)
c801d85f 2293{
e49c85af 2294 size_t i;
9d4a05be 2295 for (i = 0; i < m_fileMaxFiles; i++)
0fb67cd1
VZ
2296 {
2297 wxString buf;
8c9564b3 2298 buf.Printf(wxT("file%d"), (int)i+1);
b4a980f4 2299 if (i < m_fileHistory.GetCount())
9d4a05be
JS
2300 config.Write(buf, wxString(m_fileHistory[i]));
2301 else
42771621 2302 config.Write(buf, wxEmptyString);
0fb67cd1 2303 }
7f555861 2304}
0fb67cd1 2305#endif // wxUSE_CONFIG
7f555861
JS
2306
2307void wxFileHistory::AddFilesToMenu()
2308{
b4a980f4 2309 if (m_fileHistory.GetCount() > 0)
7f555861 2310 {
222ed1d6 2311 wxList::compatibility_iterator node = m_fileMenus.GetFirst();
7f555861
JS
2312 while (node)
2313 {
b1d4dd7a 2314 wxMenu* menu = (wxMenu*) node->GetData();
c8c5c7f6
JS
2315 if (menu->GetMenuItemCount())
2316 {
2317 menu->AppendSeparator();
2318 }
2319
e49c85af 2320 size_t i;
b4a980f4 2321 for (i = 0; i < m_fileHistory.GetCount(); i++)
7f555861
JS
2322 {
2323 wxString buf;
b4a980f4 2324 buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i].c_str());
e49c85af 2325 menu->Append(m_idBase+i, buf);
7f555861 2326 }
b1d4dd7a 2327 node = node->GetNext();
7f555861
JS
2328 }
2329 }
2330}
2331
2332void wxFileHistory::AddFilesToMenu(wxMenu* menu)
2333{
b4a980f4 2334 if (m_fileHistory.GetCount() > 0)
7f555861 2335 {
c8c5c7f6
JS
2336 if (menu->GetMenuItemCount())
2337 {
2338 menu->AppendSeparator();
2339 }
2340
e49c85af 2341 size_t i;
b4a980f4 2342 for (i = 0; i < m_fileHistory.GetCount(); i++)
7f555861
JS
2343 {
2344 wxString buf;
b4a980f4 2345 buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i].c_str());
e49c85af 2346 menu->Append(m_idBase+i, buf);
7f555861
JS
2347 }
2348 }
c801d85f
KB
2349}
2350
0fb67cd1
VZ
2351// ----------------------------------------------------------------------------
2352// Permits compatibility with existing file formats and functions that
2353// manipulate files directly
2354// ----------------------------------------------------------------------------
c801d85f 2355
a533f5c1 2356#if wxUSE_STD_IOSTREAM
fb6e5b17 2357
dd107c50 2358bool wxTransferFileToStream(const wxString& filename, wxSTD ostream& stream)
c801d85f 2359{
fb6e5b17
VZ
2360 wxFFile file(filename, _T("rb"));
2361 if ( !file.IsOpened() )
68379eaf 2362 return false;
c801d85f 2363
fb6e5b17
VZ
2364 char buf[4096];
2365
2366 size_t nRead;
2367 do
2368 {
2369 nRead = file.Read(buf, WXSIZEOF(buf));
2370 if ( file.Error() )
68379eaf 2371 return false;
fb6e5b17
VZ
2372
2373 stream.write(buf, nRead);
2374 if ( !stream )
68379eaf 2375 return false;
fb6e5b17
VZ
2376 }
2377 while ( !file.Eof() );
c801d85f 2378
68379eaf 2379 return true;
c801d85f
KB
2380}
2381
dd107c50 2382bool wxTransferStreamToFile(wxSTD istream& stream, const wxString& filename)
c801d85f 2383{
fb6e5b17
VZ
2384 wxFFile file(filename, _T("wb"));
2385 if ( !file.IsOpened() )
68379eaf 2386 return false;
c801d85f 2387
fb6e5b17
VZ
2388 char buf[4096];
2389 do
0fb67cd1 2390 {
fb6e5b17
VZ
2391 stream.read(buf, WXSIZEOF(buf));
2392 if ( !stream.bad() ) // fail may be set on EOF, don't use operator!()
2393 {
2394 if ( !file.Write(buf, stream.gcount()) )
68379eaf 2395 return false;
fb6e5b17 2396 }
0fb67cd1 2397 }
fb6e5b17
VZ
2398 while ( !stream.eof() );
2399
68379eaf 2400 return true;
c801d85f 2401}
fb6e5b17
VZ
2402
2403#else // !wxUSE_STD_IOSTREAM
2404
dc1efb1d
JS
2405bool wxTransferFileToStream(const wxString& filename, wxOutputStream& stream)
2406{
fb6e5b17
VZ
2407 wxFFile file(filename, _T("rb"));
2408 if ( !file.IsOpened() )
68379eaf 2409 return false;
dc1efb1d 2410
fb6e5b17
VZ
2411 char buf[4096];
2412
2413 size_t nRead;
2414 do
2415 {
2416 nRead = file.Read(buf, WXSIZEOF(buf));
2417 if ( file.Error() )
68379eaf 2418 return false;
fb6e5b17
VZ
2419
2420 stream.Write(buf, nRead);
2421 if ( !stream )
68379eaf 2422 return false;
fb6e5b17
VZ
2423 }
2424 while ( !file.Eof() );
dc1efb1d 2425
68379eaf 2426 return true;
dc1efb1d
JS
2427}
2428
2429bool wxTransferStreamToFile(wxInputStream& stream, const wxString& filename)
2430{
fb6e5b17
VZ
2431 wxFFile file(filename, _T("wb"));
2432 if ( !file.IsOpened() )
68379eaf 2433 return false;
dc1efb1d 2434
fb6e5b17
VZ
2435 char buf[4096];
2436 do
dc1efb1d 2437 {
fb6e5b17
VZ
2438 stream.Read(buf, WXSIZEOF(buf));
2439
2440 const size_t nRead = stream.LastRead();
2441 if ( !nRead || !file.Write(buf, nRead) )
68379eaf 2442 return false;
dc1efb1d 2443 }
fb6e5b17
VZ
2444 while ( !stream.Eof() );
2445
68379eaf 2446 return true;
dc1efb1d 2447}
fb6e5b17
VZ
2448
2449#endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM
c801d85f 2450
0fb67cd1 2451#endif // wxUSE_DOC_VIEW_ARCHITECTURE