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