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