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