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