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