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