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