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