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 
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 
FindExtension(const wxChar * path)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 
wxDocument(wxDocument * parent)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 
DeleteContents()137 bool wxDocument::DeleteContents()
138 {
139     return true;
140 }
141 
~wxDocument()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 
Close()158 bool wxDocument::Close()
159 {
160     if (OnSaveModified())
161         return OnCloseDocument();
162     else
163         return false;
164 }
165 
OnCloseDocument()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.
DeleteAllViews()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 
GetFirstView() const221 wxView *wxDocument::GetFirstView() const
222 {
223     if (m_documentViews.GetCount() == 0)
224         return (wxView *) NULL;
225     return (wxView *)m_documentViews.GetFirst()->GetData();
226 }
227 
GetDocumentManager() const228 wxDocManager *wxDocument::GetDocumentManager() const
229 {
230     return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL);
231 }
232 
OnNewDocument()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 
Save()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 
SaveAs()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     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 
OnSaveDocument(const wxString & file)354 bool 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 
OnOpenDocument(const wxString & file)372 bool 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
LoadObject(wxSTD istream & stream)390 wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream)
391 #else
392 wxInputStream& wxDocument::LoadObject(wxInputStream& stream)
393 #endif
394 {
395     return stream;
396 }
397 
398 #if wxUSE_STD_IOSTREAM
SaveObject(wxSTD ostream & stream)399 wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream)
400 #else
401 wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream)
402 #endif
403 {
404     return stream;
405 }
406 
Revert()407 bool wxDocument::Revert()
408 {
409     return false;
410 }
411 
412 
413 // Get title, or filename if no title, else unnamed
GetPrintableName(wxString & buf) const414 bool 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 
GetDocumentWindow() const433 wxWindow *wxDocument::GetDocumentWindow() const
434 {
435     wxView *view = GetFirstView();
436     if (view)
437         return view->GetFrame();
438     else
439         return wxTheApp->GetTopWindow();
440 }
441 
OnCreateCommandProcessor()442 wxCommandProcessor *wxDocument::OnCreateCommandProcessor()
443 {
444     return new wxCommandProcessor;
445 }
446 
447 // true if safe to close
OnSaveModified()448 bool 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 
Draw(wxDC & WXUNUSED (context))480 bool wxDocument::Draw(wxDC& WXUNUSED(context))
481 {
482     return true;
483 }
484 
AddView(wxView * view)485 bool 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 
RemoveView(wxView * view)495 bool wxDocument::RemoveView(wxView *view)
496 {
497     (void)m_documentViews.DeleteObject(view);
498     OnChangedViewList();
499     return true;
500 }
501 
OnCreate(const wxString & WXUNUSED (path),long flags)502 bool 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.
OnChangedViewList()513 void wxDocument::OnChangedViewList()
514 {
515     if (m_documentViews.GetCount() == 0)
516     {
517         if (OnSaveModified())
518         {
519             delete this;
520         }
521     }
522 }
523 
UpdateAllViews(wxView * sender,wxObject * hint)524 void 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 
NotifyClosing()536 void 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 
SetFilename(const wxString & filename,bool notifyViews)547 void 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 
DoSaveDocument(const wxString & file)563 bool 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 
DoOpenDocument(const wxString & file)595 bool 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 
wxView()624 wxView::wxView()
625 {
626     m_viewDocument = (wxDocument*) NULL;
627 
628     m_viewFrame = (wxFrame *) NULL;
629 }
630 
~wxView()631 wxView::~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
ProcessEvent(wxEvent & event)640 bool wxView::ProcessEvent(wxEvent& event)
641 {
642     if ( !GetDocument() || !GetDocument()->ProcessEvent(event) )
643         return wxEvtHandler::ProcessEvent(event);
644 
645     return true;
646 }
647 
OnActivateView(bool WXUNUSED (activate),wxView * WXUNUSED (activeView),wxView * WXUNUSED (deactiveView))648 void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView))
649 {
650 }
651 
OnPrint(wxDC * dc,wxObject * WXUNUSED (info))652 void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info))
653 {
654     OnDraw(dc);
655 }
656 
OnUpdate(wxView * WXUNUSED (sender),wxObject * WXUNUSED (hint))657 void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
658 {
659 }
660 
OnChangeFilename()661 void 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 
SetDocument(wxDocument * doc)677 void wxView::SetDocument(wxDocument *doc)
678 {
679     m_viewDocument = doc;
680     if (doc)
681         doc->AddView(this);
682 }
683 
Close(bool deleteWindow)684 bool wxView::Close(bool deleteWindow)
685 {
686     if (OnClose(deleteWindow))
687         return true;
688     else
689         return false;
690 }
691 
Activate(bool activate)692 void wxView::Activate(bool activate)
693 {
694     if (GetDocument() && GetDocumentManager())
695     {
696         OnActivateView(activate, this, GetDocumentManager()->GetCurrentView());
697         GetDocumentManager()->ActivateView(this, activate);
698     }
699 }
700 
OnClose(bool WXUNUSED (deleteWindow))701 bool wxView::OnClose(bool WXUNUSED(deleteWindow))
702 {
703     return GetDocument() ? GetDocument()->Close() : true;
704 }
705 
706 #if wxUSE_PRINTING_ARCHITECTURE
OnCreatePrintout()707 wxPrintout *wxView::OnCreatePrintout()
708 {
709     return new wxDocPrintout(this);
710 }
711 #endif // wxUSE_PRINTING_ARCHITECTURE
712 
713 // ----------------------------------------------------------------------------
714 // wxDocTemplate
715 // ----------------------------------------------------------------------------
716 
wxDocTemplate(wxDocManager * manager,const wxString & descr,const wxString & filter,const wxString & dir,const wxString & ext,const wxString & docTypeName,const wxString & viewTypeName,wxClassInfo * docClassInfo,wxClassInfo * viewClassInfo,long flags)717 wxDocTemplate::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 
~wxDocTemplate()742 wxDocTemplate::~wxDocTemplate()
743 {
744     m_documentManager->DisassociateTemplate(this);
745 }
746 
747 // Tries to dynamically construct an object of the right class.
CreateDocument(const wxString & path,long flags)748 wxDocument *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 
InitDocument(wxDocument * doc,const wxString & path,long flags)764 bool 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 
CreateView(wxDocument * doc,long flags)781 wxView *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
FileMatchesTemplate(const wxString & path)801 bool 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 
DoCreateDocument()817 wxDocument *wxDocTemplate::DoCreateDocument()
818 {
819     if (!m_docClassInfo)
820         return (wxDocument *) NULL;
821 
822     return (wxDocument *)m_docClassInfo->CreateObject();
823 }
824 
DoCreateView()825 wxView *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 
837 BEGIN_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
865 END_EVENT_TABLE()
866 
867 wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL;
868 
wxDocManager(long flags,bool initialize)869 wxDocManager::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 
~wxDocManager()881 wxDocManager::~wxDocManager()
882 {
883     Clear();
884     if (m_fileHistory)
885         delete m_fileHistory;
886     sm_docManager = (wxDocManager*) NULL;
887 }
888 
889 // closes the specified document
CloseDocument(wxDocument * doc,bool force)890 bool 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 
CloseDocuments(bool force)907 bool 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 
Clear(bool force)926 bool 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 
Initialize()944 bool wxDocManager::Initialize()
945 {
946     m_fileHistory = OnCreateFileHistory();
947     return true;
948 }
949 
OnCreateFileHistory()950 wxFileHistory *wxDocManager::OnCreateFileHistory()
951 {
952     return new wxFileHistory;
953 }
954 
OnFileClose(wxCommandEvent & WXUNUSED (event))955 void 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 
OnFileCloseAll(wxCommandEvent & WXUNUSED (event))968 void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event))
969 {
970     CloseDocuments(false);
971 }
972 
OnFileNew(wxCommandEvent & WXUNUSED (event))973 void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event))
974 {
975     CreateDocument( wxEmptyString, wxDOC_NEW );
976 }
977 
OnFileOpen(wxCommandEvent & WXUNUSED (event))978 void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event))
979 {
980     if ( !CreateDocument( wxEmptyString, 0) )
981     {
982         OnOpenFileFailure();
983     }
984 }
985 
OnFileRevert(wxCommandEvent & WXUNUSED (event))986 void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event))
987 {
988     wxDocument *doc = GetCurrentDocument();
989     if (!doc)
990         return;
991     doc->Revert();
992 }
993 
OnFileSave(wxCommandEvent & WXUNUSED (event))994 void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event))
995 {
996     wxDocument *doc = GetCurrentDocument();
997     if (!doc)
998         return;
999     doc->Save();
1000 }
1001 
OnFileSaveAs(wxCommandEvent & WXUNUSED (event))1002 void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event))
1003 {
1004     wxDocument *doc = GetCurrentDocument();
1005     if (!doc)
1006         return;
1007     doc->SaveAs();
1008 }
1009 
OnPrint(wxCommandEvent & WXUNUSED (event))1010 void 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 
OnPreview(wxCommandEvent & WXUNUSED (event))1028 void 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 
OnUndo(wxCommandEvent & event)1057 void 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 
OnRedo(wxCommandEvent & event)1068 void 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 
OnUpdateFileOpen(wxUpdateUIEvent & event)1081 void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event)
1082 {
1083     event.Enable( true );
1084 }
1085 
OnUpdateFileClose(wxUpdateUIEvent & event)1086 void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event)
1087 {
1088     wxDocument *doc = GetCurrentDocument();
1089     event.Enable( (doc != (wxDocument*) NULL) );
1090 }
1091 
OnUpdateFileRevert(wxUpdateUIEvent & event)1092 void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event)
1093 {
1094     wxDocument *doc = GetCurrentDocument();
1095     event.Enable( (doc != (wxDocument*) NULL) );
1096 }
1097 
OnUpdateFileNew(wxUpdateUIEvent & event)1098 void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event)
1099 {
1100     event.Enable( true );
1101 }
1102 
OnUpdateFileSave(wxUpdateUIEvent & event)1103 void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event)
1104 {
1105     wxDocument *doc = GetCurrentDocument();
1106     event.Enable( doc && doc->IsModified() );
1107 }
1108 
OnUpdateFileSaveAs(wxUpdateUIEvent & event)1109 void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event)
1110 {
1111     wxDocument *doc = GetCurrentDocument();
1112     event.Enable( (doc != (wxDocument*) NULL) );
1113 }
1114 
OnUpdateUndo(wxUpdateUIEvent & event)1115 void 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 
OnUpdateRedo(wxUpdateUIEvent & event)1129 void 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 
OnUpdatePrint(wxUpdateUIEvent & event)1143 void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event)
1144 {
1145     wxDocument *doc = GetCurrentDocument();
1146     event.Enable( (doc != (wxDocument*) NULL) );
1147 }
1148 
OnUpdatePreview(wxUpdateUIEvent & event)1149 void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event)
1150 {
1151     wxDocument *doc = GetCurrentDocument();
1152     event.Enable( (doc != (wxDocument*) NULL) );
1153 }
1154 
GetCurrentView() const1155 wxView *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
ProcessEvent(wxEvent & event)1168 bool 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 
CreateDocument(const wxString & path,long flags)1179 wxDocument *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 
CreateView(wxDocument * doc,long flags)1349 wxView *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
DeleteTemplate(wxDocTemplate * WXUNUSED (temp),long WXUNUSED (flags))1395 void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags))
1396 {
1397 }
1398 
1399 // Not yet implemented
FlushDoc(wxDocument * WXUNUSED (doc))1400 bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc))
1401 {
1402     return false;
1403 }
1404 
GetCurrentDocument() const1405 wxDocument *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
MakeDefaultName(wxString & name)1415 bool 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.
MakeFrameTitle(wxDocument * doc)1425 wxString 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
MatchTemplate(const wxString & WXUNUSED (path))1442 wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path))
1443 {
1444     return (wxDocTemplate *) NULL;
1445 }
1446 
1447 // File history management
AddFileToHistory(const wxString & file)1448 void wxDocManager::AddFileToHistory(const wxString& file)
1449 {
1450     if (m_fileHistory)
1451         m_fileHistory->AddFileToHistory(file);
1452 }
1453 
RemoveFileFromHistory(size_t i)1454 void wxDocManager::RemoveFileFromHistory(size_t i)
1455 {
1456     if (m_fileHistory)
1457         m_fileHistory->RemoveFileFromHistory(i);
1458 }
1459 
GetHistoryFile(size_t i) const1460 wxString 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 
FileHistoryUseMenu(wxMenu * menu)1470 void wxDocManager::FileHistoryUseMenu(wxMenu *menu)
1471 {
1472     if (m_fileHistory)
1473         m_fileHistory->UseMenu(menu);
1474 }
1475 
FileHistoryRemoveMenu(wxMenu * menu)1476 void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu)
1477 {
1478     if (m_fileHistory)
1479         m_fileHistory->RemoveMenu(menu);
1480 }
1481 
1482 #if wxUSE_CONFIG
FileHistoryLoad(wxConfigBase & config)1483 void wxDocManager::FileHistoryLoad(wxConfigBase& config)
1484 {
1485     if (m_fileHistory)
1486         m_fileHistory->Load(config);
1487 }
1488 
FileHistorySave(wxConfigBase & config)1489 void wxDocManager::FileHistorySave(wxConfigBase& config)
1490 {
1491     if (m_fileHistory)
1492         m_fileHistory->Save(config);
1493 }
1494 #endif
1495 
FileHistoryAddFilesToMenu(wxMenu * menu)1496 void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu)
1497 {
1498     if (m_fileHistory)
1499         m_fileHistory->AddFilesToMenu(menu);
1500 }
1501 
FileHistoryAddFilesToMenu()1502 void wxDocManager::FileHistoryAddFilesToMenu()
1503 {
1504     if (m_fileHistory)
1505         m_fileHistory->AddFilesToMenu();
1506 }
1507 
GetHistoryFilesCount() const1508 size_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
FindTemplateForPath(const wxString & path)1516 wxDocTemplate *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.
wxFindSuitableParent()1536 static 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 
SelectDocumentPath(wxDocTemplate ** templates,int noTemplates,wxString & path,long WXUNUSED (flags),bool WXUNUSED (save))1559 wxDocTemplate *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 
SelectDocumentType(wxDocTemplate ** templates,int noTemplates,bool sort)1647 wxDocTemplate *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 
SelectViewType(wxDocTemplate ** templates,int noTemplates,bool sort)1728 wxDocTemplate *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 
AssociateTemplate(wxDocTemplate * temp)1805 void wxDocManager::AssociateTemplate(wxDocTemplate *temp)
1806 {
1807     if (!m_templates.Member(temp))
1808         m_templates.Append(temp);
1809 }
1810 
DisassociateTemplate(wxDocTemplate * temp)1811 void wxDocManager::DisassociateTemplate(wxDocTemplate *temp)
1812 {
1813     m_templates.DeleteObject(temp);
1814 }
1815 
1816 // Add and remove a document from the manager's list
AddDocument(wxDocument * doc)1817 void wxDocManager::AddDocument(wxDocument *doc)
1818 {
1819     if (!m_docs.Member(doc))
1820         m_docs.Append(doc);
1821 }
1822 
RemoveDocument(wxDocument * doc)1823 void 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
ActivateView(wxView * view,bool activate)1830 void 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 
BEGIN_EVENT_TABLE(wxDocChildFrame,wxFrame)1850 BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame)
1851     EVT_ACTIVATE(wxDocChildFrame::OnActivate)
1852     EVT_CLOSE(wxDocChildFrame::OnCloseWindow)
1853 END_EVENT_TABLE()
1854 
1855 wxDocChildFrame::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
ProcessEvent(wxEvent & event)1873 bool 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 
OnActivate(wxActivateEvent & event)1890 void wxDocChildFrame::OnActivate(wxActivateEvent& event)
1891 {
1892     wxFrame::OnActivate(event);
1893 
1894     if (m_childView)
1895         m_childView->Activate(event.GetActive());
1896 }
1897 
OnCloseWindow(wxCloseEvent & event)1898 void 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 
BEGIN_EVENT_TABLE(wxDocParentFrame,wxFrame)1926 BEGIN_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)
1930 END_EVENT_TABLE()
1931 
1932 wxDocParentFrame::wxDocParentFrame()
1933 {
1934     m_docManager = NULL;
1935 }
1936 
wxDocParentFrame(wxDocManager * manager,wxFrame * frame,wxWindowID id,const wxString & title,const wxPoint & pos,const wxSize & size,long style,const wxString & name)1937 wxDocParentFrame::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 
Create(wxDocManager * manager,wxFrame * frame,wxWindowID id,const wxString & title,const wxPoint & pos,const wxSize & size,long style,const wxString & name)1950 bool 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 
OnExit(wxCommandEvent & WXUNUSED (event))1963 void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event))
1964 {
1965     Close();
1966 }
1967 
OnMRUFile(wxCommandEvent & event)1968 void 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
ProcessEvent(wxEvent & event)2000 bool 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.
OnCloseWindow(wxCloseEvent & event)2011 void 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 
wxDocPrintout(wxView * view,const wxString & title)2026 wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title)
2027              : wxPrintout(title)
2028 {
2029     m_printoutView = view;
2030 }
2031 
OnPrintPage(int WXUNUSED (page))2032 bool 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 
HasPage(int pageNum)2071 bool wxDocPrintout::HasPage(int pageNum)
2072 {
2073     return (pageNum == 1);
2074 }
2075 
OnBeginDocument(int startPage,int endPage)2076 bool wxDocPrintout::OnBeginDocument(int startPage, int endPage)
2077 {
2078     if (!wxPrintout::OnBeginDocument(startPage, endPage))
2079         return false;
2080 
2081     return true;
2082 }
2083 
GetPageInfo(int * minPage,int * maxPage,int * selPageFrom,int * selPageTo)2084 void 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 
MYcopystring(const wxString & s)2098 static inline wxChar* MYcopystring(const wxString& s)
2099 {
2100     wxChar* copy = new wxChar[s.length() + 1];
2101     return wxStrcpy(copy, s.c_str());
2102 }
2103 
MYcopystring(const wxChar * s)2104 static inline wxChar* MYcopystring(const wxChar* s)
2105 {
2106     wxChar* copy = new wxChar[wxStrlen(s) + 1];
2107     return wxStrcpy(copy, s);
2108 }
2109 
wxFileHistory(size_t maxFiles,wxWindowID idBase)2110 wxFileHistory::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 
~wxFileHistory()2118 wxFileHistory::~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
AddFileToHistory(const wxString & file)2127 void 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 
RemoveFileFromHistory(size_t i)2220 void 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 
GetHistoryFile(size_t i) const2276 wxString 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 
UseMenu(wxMenu * menu)2291 void wxFileHistory::UseMenu(wxMenu *menu)
2292 {
2293     if (!m_fileMenus.Member(menu))
2294         m_fileMenus.Append(menu);
2295 }
2296 
RemoveMenu(wxMenu * menu)2297 void wxFileHistory::RemoveMenu(wxMenu *menu)
2298 {
2299     m_fileMenus.DeleteObject(menu);
2300 }
2301 
2302 #if wxUSE_CONFIG
Load(wxConfigBase & config)2303 void 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 
Save(wxConfigBase & config)2319 void 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 
AddFilesToMenu()2334 void 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 
AddFilesToMenu(wxMenu * menu)2362 void 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 
wxTransferFileToStream(const wxString & filename,wxSTD ostream & stream)2391 bool 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 
wxTransferStreamToFile(wxSTD istream & stream,const wxString & filename)2415 bool 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 
wxTransferFileToStream(const wxString & filename,wxOutputStream & stream)2438 bool 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 
wxTransferStreamToFile(wxInputStream & stream,const wxString & filename)2462 bool 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