OSDN Git Service

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