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