Compilation fix for wxUSE_STL == 1.
[wxWidgets.git] / src / common / docview.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/docview.cpp
3 // Purpose: Document/view classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "docview.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_DOC_VIEW_ARCHITECTURE
32
33 #ifndef WX_PRECOMP
34 #include "wx/string.h"
35 #include "wx/utils.h"
36 #include "wx/app.h"
37 #include "wx/dc.h"
38 #include "wx/dialog.h"
39 #include "wx/menu.h"
40 #include "wx/list.h"
41 #include "wx/filedlg.h"
42 #include "wx/intl.h"
43 #include "wx/log.h"
44 #endif
45
46 #include "wx/ffile.h"
47
48 #ifdef __WXMAC__
49 #include "wx/filename.h"
50 #endif
51
52 #ifdef __WXGTK__
53 #include "wx/mdi.h"
54 #endif
55
56 #if wxUSE_PRINTING_ARCHITECTURE
57 #include "wx/prntbase.h"
58 #include "wx/printdlg.h"
59 #endif
60
61 #include "wx/msgdlg.h"
62 #include "wx/choicdlg.h"
63 #include "wx/docview.h"
64 #include "wx/confbase.h"
65 #include "wx/file.h"
66 #include "wx/cmdproc.h"
67
68 #include <stdio.h>
69 #include <string.h>
70
71 #if wxUSE_STD_IOSTREAM
72 #include "wx/ioswrap.h"
73 #if wxUSE_IOSTREAMH
74 #include <fstream.h>
75 #else
76 #include <fstream>
77 #endif
78 #else
79 #include "wx/wfstream.h"
80 #endif
81
82 // ----------------------------------------------------------------------------
83 // wxWidgets macros
84 // ----------------------------------------------------------------------------
85
86 IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler)
87 IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler)
88 IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject)
89 IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler)
90 IMPLEMENT_CLASS(wxDocChildFrame, wxFrame)
91 IMPLEMENT_CLASS(wxDocParentFrame, wxFrame)
92
93 #if wxUSE_PRINTING_ARCHITECTURE
94 IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout)
95 #endif
96
97 IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
98
99 // ----------------------------------------------------------------------------
100 // function prototypes
101 // ----------------------------------------------------------------------------
102
103 static inline wxString FindExtension(const wxChar *path);
104 static wxWindow* wxFindSuitableParent(void);
105
106 // ----------------------------------------------------------------------------
107 // local constants
108 // ----------------------------------------------------------------------------
109
110 static const wxChar *s_MRUEntryFormat = wxT("&%d %s");
111
112 // ============================================================================
113 // implementation
114 // ============================================================================
115
116 // ----------------------------------------------------------------------------
117 // local functions
118 // ----------------------------------------------------------------------------
119
120 static wxString FindExtension(const wxChar *path)
121 {
122 wxString ext;
123 wxSplitPath(path, NULL, NULL, &ext);
124
125 // VZ: extensions are considered not case sensitive - is this really a good
126 // idea?
127 return ext.MakeLower();
128 }
129
130 // ----------------------------------------------------------------------------
131 // Definition of wxDocument
132 // ----------------------------------------------------------------------------
133
134 wxDocument::wxDocument(wxDocument *parent)
135 {
136 m_documentModified = FALSE;
137 m_documentParent = parent;
138 m_documentTemplate = (wxDocTemplate *) NULL;
139 m_commandProcessor = (wxCommandProcessor*) NULL;
140 m_savedYet = FALSE;
141 }
142
143 bool wxDocument::DeleteContents()
144 {
145 return TRUE;
146 }
147
148 wxDocument::~wxDocument()
149 {
150 DeleteContents();
151
152 if (m_commandProcessor)
153 delete m_commandProcessor;
154
155 if (GetDocumentManager())
156 GetDocumentManager()->RemoveDocument(this);
157
158 // Not safe to do here, since it'll invoke virtual view functions
159 // expecting to see valid derived objects: and by the time we get here,
160 // we've called destructors higher up.
161 //DeleteAllViews();
162 }
163
164 bool wxDocument::Close()
165 {
166 if (OnSaveModified())
167 return OnCloseDocument();
168 else
169 return FALSE;
170 }
171
172 bool wxDocument::OnCloseDocument()
173 {
174 // Tell all views that we're about to close
175 NotifyClosing();
176 DeleteContents();
177 Modify(FALSE);
178 return TRUE;
179 }
180
181 // Note that this implicitly deletes the document when the last view is
182 // deleted.
183 bool wxDocument::DeleteAllViews()
184 {
185 wxDocManager* manager = GetDocumentManager();
186 wxList::iterator it, en;
187
188 for ( it = m_documentViews.begin(), en = m_documentViews.end();
189 it != en;
190 )
191 {
192 wxView *view = (wxView *)*it;
193 if (!view->Close())
194 return FALSE;
195
196 wxList::iterator next = it; ++next;
197
198 delete view; // Deletes node implicitly
199 it = next;
200 }
201 // If we haven't yet deleted the document (for example
202 // if there were no views) then delete it.
203 if (manager && manager->GetDocuments().Member(this))
204 delete this;
205
206 return TRUE;
207 }
208
209 wxView *wxDocument::GetFirstView() const
210 {
211 if (m_documentViews.GetCount() == 0)
212 return (wxView *) NULL;
213 return (wxView *)m_documentViews.GetFirst()->GetData();
214 }
215
216 wxDocManager *wxDocument::GetDocumentManager() const
217 {
218 return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL);
219 }
220
221 bool wxDocument::OnNewDocument()
222 {
223 if (!OnSaveModified())
224 return FALSE;
225
226 if (OnCloseDocument()==FALSE) return FALSE;
227 DeleteContents();
228 Modify(FALSE);
229 SetDocumentSaved(FALSE);
230
231 wxString name;
232 GetDocumentManager()->MakeDefaultName(name);
233 SetTitle(name);
234 SetFilename(name, TRUE);
235
236 return TRUE;
237 }
238
239 bool wxDocument::Save()
240 {
241 if (!IsModified() && m_savedYet)
242 return TRUE;
243
244 if ( m_documentFile.empty() || !m_savedYet )
245 return SaveAs();
246
247 return OnSaveDocument(m_documentFile);
248 }
249
250 bool wxDocument::SaveAs()
251 {
252 wxDocTemplate *docTemplate = GetDocumentTemplate();
253 if (!docTemplate)
254 return FALSE;
255
256 #if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__)
257 wxString filter = docTemplate->GetDescription() + wxT(" (") + docTemplate->GetFileFilter() + wxT(")|") + docTemplate->GetFileFilter();
258
259 // Now see if there are some other template with identical view and document
260 // classes, whose filters may also be used.
261
262 if (docTemplate->GetViewClassInfo() && docTemplate->GetDocClassInfo())
263 {
264 wxList::compatibility_iterator node = wxDocManager::GetDocumentManager()->GetTemplates().GetFirst();
265 while (node)
266 {
267 wxDocTemplate *t = (wxDocTemplate*) node->GetData();
268
269 if (t->IsVisible() && t != docTemplate &&
270 t->GetViewClassInfo() == docTemplate->GetViewClassInfo() &&
271 t->GetDocClassInfo() == docTemplate->GetDocClassInfo())
272 {
273 // add a '|' to separate this filter from the previous one
274 if ( !filter.IsEmpty() )
275 filter << wxT('|');
276
277 filter << t->GetDescription() << wxT(" (") << t->GetFileFilter() << wxT(") |")
278 << t->GetFileFilter();
279 }
280
281 node = node->GetNext();
282 }
283 }
284 #else
285 wxString filter = docTemplate->GetFileFilter() ;
286 #endif
287 wxString tmp = wxFileSelector(_("Save as"),
288 docTemplate->GetDirectory(),
289 wxFileNameFromPath(GetFilename()),
290 docTemplate->GetDefaultExtension(),
291 filter,
292 wxSAVE | wxOVERWRITE_PROMPT,
293 GetDocumentWindow());
294
295 if (tmp.IsEmpty())
296 return FALSE;
297
298 wxString fileName(tmp);
299 wxString path, name, ext;
300 wxSplitPath(fileName, & path, & name, & ext);
301
302 if (ext.IsEmpty() || ext == wxT(""))
303 {
304 fileName += wxT(".");
305 fileName += docTemplate->GetDefaultExtension();
306 }
307
308 SetFilename(fileName);
309 SetTitle(wxFileNameFromPath(fileName));
310
311 // Notify the views that the filename has changed
312 wxList::compatibility_iterator node = m_documentViews.GetFirst();
313 while (node)
314 {
315 wxView *view = (wxView *)node->GetData();
316 view->OnChangeFilename();
317 node = node->GetNext();
318 }
319
320 // Files that were not saved correctly are not added to the FileHistory.
321 if (!OnSaveDocument(m_documentFile))
322 return FALSE;
323
324 // A file that doesn't use the default extension of its document template cannot be opened
325 // via the FileHistory, so we do not add it.
326 if (docTemplate->FileMatchesTemplate(fileName))
327 {
328 GetDocumentManager()->AddFileToHistory(fileName);
329 }
330 else
331 {
332 // The user will probably not be able to open the file again, so
333 // we could warn about the wrong file-extension here.
334 }
335 return TRUE;
336 }
337
338 bool wxDocument::OnSaveDocument(const wxString& file)
339 {
340 if ( !file )
341 return FALSE;
342
343 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
379 bool 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
425 wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream)
426 #else
427 wxInputStream& wxDocument::LoadObject(wxInputStream& stream)
428 #endif
429 {
430 return stream;
431 }
432
433 #if wxUSE_STD_IOSTREAM
434 wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream)
435 #else
436 wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream)
437 #endif
438 {
439 return stream;
440 }
441
442 bool wxDocument::Revert()
443 {
444 return FALSE;
445 }
446
447
448 // Get title, or filename if no title, else unnamed
449 bool 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
468 wxWindow *wxDocument::GetDocumentWindow() const
469 {
470 wxView *view = GetFirstView();
471 if (view)
472 return view->GetFrame();
473 else
474 return wxTheApp->GetTopWindow();
475 }
476
477 wxCommandProcessor *wxDocument::OnCreateCommandProcessor()
478 {
479 return new wxCommandProcessor;
480 }
481
482 // TRUE if safe to close
483 bool 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
515 bool wxDocument::Draw(wxDC& WXUNUSED(context))
516 {
517 return TRUE;
518 }
519
520 bool 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
530 bool wxDocument::RemoveView(wxView *view)
531 {
532 (void)m_documentViews.DeleteObject(view);
533 OnChangedViewList();
534 return TRUE;
535 }
536
537 bool 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.
548 void wxDocument::OnChangedViewList()
549 {
550 if (m_documentViews.GetCount() == 0)
551 {
552 if (OnSaveModified())
553 {
554 delete this;
555 }
556 }
557 }
558
559 void 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
571 void 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
582 void 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
602 wxView::wxView()
603 {
604 m_viewDocument = (wxDocument*) NULL;
605
606 m_viewFrame = (wxFrame *) NULL;
607 }
608
609 wxView::~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
616 bool wxView::ProcessEvent(wxEvent& event)
617 {
618 if ( !GetDocument() || !GetDocument()->ProcessEvent(event) )
619 return wxEvtHandler::ProcessEvent(event);
620
621 return TRUE;
622 }
623
624 void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView))
625 {
626 }
627
628 void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info))
629 {
630 OnDraw(dc);
631 }
632
633 void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
634 {
635 }
636
637 void wxView::OnChangeFilename()
638 {
639 if (GetFrame() && GetDocument())
640 {
641 wxString title;
642
643 GetDocument()->GetPrintableName(title);
644
645 GetFrame()->SetTitle(title);
646 }
647 }
648
649 void wxView::SetDocument(wxDocument *doc)
650 {
651 m_viewDocument = doc;
652 if (doc)
653 doc->AddView(this);
654 }
655
656 bool wxView::Close(bool deleteWindow)
657 {
658 if (OnClose(deleteWindow))
659 return TRUE;
660 else
661 return FALSE;
662 }
663
664 void wxView::Activate(bool activate)
665 {
666 if (GetDocument() && GetDocumentManager())
667 {
668 OnActivateView(activate, this, GetDocumentManager()->GetCurrentView());
669 GetDocumentManager()->ActivateView(this, activate);
670 }
671 }
672
673 bool wxView::OnClose(bool WXUNUSED(deleteWindow))
674 {
675 return GetDocument() ? GetDocument()->Close() : TRUE;
676 }
677
678 #if wxUSE_PRINTING_ARCHITECTURE
679 wxPrintout *wxView::OnCreatePrintout()
680 {
681 return new wxDocPrintout(this);
682 }
683 #endif // wxUSE_PRINTING_ARCHITECTURE
684
685 // ----------------------------------------------------------------------------
686 // wxDocTemplate
687 // ----------------------------------------------------------------------------
688
689 wxDocTemplate::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
714 wxDocTemplate::~wxDocTemplate()
715 {
716 m_documentManager->DisassociateTemplate(this);
717 }
718
719 // Tries to dynamically construct an object of the right class.
720 wxDocument *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
736 bool 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
753 wxView *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
772 bool wxDocTemplate::FileMatchesTemplate(const wxString& path)
773 {
774 return GetDefaultExtension().IsSameAs(FindExtension(path));
775 }
776
777 // ----------------------------------------------------------------------------
778 // wxDocManager
779 // ----------------------------------------------------------------------------
780
781 BEGIN_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
811 END_EVENT_TABLE()
812
813 wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL;
814
815 wxDocManager::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
827 wxDocManager::~wxDocManager()
828 {
829 Clear();
830 if (m_fileHistory)
831 delete m_fileHistory;
832 sm_docManager = (wxDocManager*) NULL;
833 }
834
835 // closes the specified document
836 bool 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
853 bool 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
872 bool 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
888 bool wxDocManager::Initialize()
889 {
890 m_fileHistory = OnCreateFileHistory();
891 return TRUE;
892 }
893
894 wxFileHistory *wxDocManager::OnCreateFileHistory()
895 {
896 return new wxFileHistory;
897 }
898
899 void 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
912 void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event))
913 {
914 CloseDocuments(FALSE);
915 }
916
917 void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event))
918 {
919 CreateDocument( wxT(""), wxDOC_NEW );
920 }
921
922 void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event))
923 {
924 if ( !CreateDocument( wxT(""), 0) )
925 {
926 OnOpenFileFailure();
927 }
928 }
929
930 void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event))
931 {
932 wxDocument *doc = GetCurrentDocument();
933 if (!doc)
934 return;
935 doc->Revert();
936 }
937
938 void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event))
939 {
940 wxDocument *doc = GetCurrentDocument();
941 if (!doc)
942 return;
943 doc->Save();
944 }
945
946 void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event))
947 {
948 wxDocument *doc = GetCurrentDocument();
949 if (!doc)
950 return;
951 doc->SaveAs();
952 }
953
954 void 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
972 void 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
988 void 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
1016 void 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
1027 void 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
1040 void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event)
1041 {
1042 event.Enable( TRUE );
1043 }
1044
1045 void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event)
1046 {
1047 wxDocument *doc = GetCurrentDocument();
1048 event.Enable( (doc != (wxDocument*) NULL) );
1049 }
1050
1051 void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event)
1052 {
1053 wxDocument *doc = GetCurrentDocument();
1054 event.Enable( (doc != (wxDocument*) NULL) );
1055 }
1056
1057 void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event)
1058 {
1059 event.Enable( TRUE );
1060 }
1061
1062 void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event)
1063 {
1064 wxDocument *doc = GetCurrentDocument();
1065 event.Enable( doc && doc->IsModified() );
1066 }
1067
1068 void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event)
1069 {
1070 wxDocument *doc = GetCurrentDocument();
1071 event.Enable( (doc != (wxDocument*) NULL) );
1072 }
1073
1074 void 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
1088 void 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
1102 void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event)
1103 {
1104 wxDocument *doc = GetCurrentDocument();
1105 event.Enable( (doc != (wxDocument*) NULL) );
1106 }
1107
1108 void wxDocManager::OnUpdatePrintSetup(wxUpdateUIEvent& event)
1109 {
1110 event.Enable( TRUE );
1111 }
1112
1113 void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event)
1114 {
1115 wxDocument *doc = GetCurrentDocument();
1116 event.Enable( (doc != (wxDocument*) NULL) );
1117 }
1118
1119 wxView *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
1132 bool 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
1143 wxDocument *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
1283 wxView *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
1329 void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags))
1330 {
1331 }
1332
1333 // Not yet implemented
1334 bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc))
1335 {
1336 return FALSE;
1337 }
1338
1339 wxDocument *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
1349 bool 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.
1359 wxString 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
1376 wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path))
1377 {
1378 return (wxDocTemplate *) NULL;
1379 }
1380
1381 // File history management
1382 void wxDocManager::AddFileToHistory(const wxString& file)
1383 {
1384 if (m_fileHistory)
1385 m_fileHistory->AddFileToHistory(file);
1386 }
1387
1388 void wxDocManager::RemoveFileFromHistory(size_t i)
1389 {
1390 if (m_fileHistory)
1391 m_fileHistory->RemoveFileFromHistory(i);
1392 }
1393
1394 wxString 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
1404 void wxDocManager::FileHistoryUseMenu(wxMenu *menu)
1405 {
1406 if (m_fileHistory)
1407 m_fileHistory->UseMenu(menu);
1408 }
1409
1410 void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu)
1411 {
1412 if (m_fileHistory)
1413 m_fileHistory->RemoveMenu(menu);
1414 }
1415
1416 #if wxUSE_CONFIG
1417 void wxDocManager::FileHistoryLoad(wxConfigBase& config)
1418 {
1419 if (m_fileHistory)
1420 m_fileHistory->Load(config);
1421 }
1422
1423 void wxDocManager::FileHistorySave(wxConfigBase& config)
1424 {
1425 if (m_fileHistory)
1426 m_fileHistory->Save(config);
1427 }
1428 #endif
1429
1430 void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu)
1431 {
1432 if (m_fileHistory)
1433 m_fileHistory->AddFilesToMenu(menu);
1434 }
1435
1436 void wxDocManager::FileHistoryAddFilesToMenu()
1437 {
1438 if (m_fileHistory)
1439 m_fileHistory->AddFilesToMenu();
1440 }
1441
1442 size_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
1450 wxDocTemplate *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.
1470 static 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
1493 wxDocTemplate *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
1581 wxDocTemplate *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
1662 wxDocTemplate *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
1739 void wxDocManager::AssociateTemplate(wxDocTemplate *temp)
1740 {
1741 if (!m_templates.Member(temp))
1742 m_templates.Append(temp);
1743 }
1744
1745 void wxDocManager::DisassociateTemplate(wxDocTemplate *temp)
1746 {
1747 m_templates.DeleteObject(temp);
1748 }
1749
1750 // Add and remove a document from the manager's list
1751 void wxDocManager::AddDocument(wxDocument *doc)
1752 {
1753 if (!m_docs.Member(doc))
1754 m_docs.Append(doc);
1755 }
1756
1757 void 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
1764 void 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
1784 BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame)
1785 EVT_ACTIVATE(wxDocChildFrame::OnActivate)
1786 EVT_CLOSE(wxDocChildFrame::OnCloseWindow)
1787 END_EVENT_TABLE()
1788
1789 wxDocChildFrame::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
1806 wxDocChildFrame::~wxDocChildFrame()
1807 {
1808 }
1809
1810 // Extend event processing to search the view's event table
1811 bool 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
1828 void wxDocChildFrame::OnActivate(wxActivateEvent& event)
1829 {
1830 wxFrame::OnActivate(event);
1831
1832 if (m_childView)
1833 m_childView->Activate(event.GetActive());
1834 }
1835
1836 void 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
1864 BEGIN_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)
1868 END_EVENT_TABLE()
1869
1870 wxDocParentFrame::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
1883 void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event))
1884 {
1885 Close();
1886 }
1887
1888 void 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
1920 bool 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.
1931 void 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
1943 wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title)
1944 : wxPrintout(title)
1945 {
1946 m_printoutView = view;
1947 }
1948
1949 bool 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
1988 bool wxDocPrintout::HasPage(int pageNum)
1989 {
1990 return (pageNum == 1);
1991 }
1992
1993 bool wxDocPrintout::OnBeginDocument(int startPage, int endPage)
1994 {
1995 if (!wxPrintout::OnBeginDocument(startPage, endPage))
1996 return FALSE;
1997
1998 return TRUE;
1999 }
2000
2001 void 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
2015 static inline wxChar* MYcopystring(const wxString& s)
2016 {
2017 wxChar* copy = new wxChar[s.length() + 1];
2018 return wxStrcpy(copy, s.c_str());
2019 }
2020
2021 static inline wxChar* MYcopystring(const wxChar* s)
2022 {
2023 wxChar* copy = new wxChar[wxStrlen(s) + 1];
2024 return wxStrcpy(copy, s);
2025 }
2026
2027 wxFileHistory::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
2035 wxFileHistory::~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
2044 void 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
2135 void 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
2191 wxString 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
2206 void wxFileHistory::UseMenu(wxMenu *menu)
2207 {
2208 if (!m_fileMenus.Member(menu))
2209 m_fileMenus.Append(menu);
2210 }
2211
2212 void wxFileHistory::RemoveMenu(wxMenu *menu)
2213 {
2214 m_fileMenus.DeleteObject(menu);
2215 }
2216
2217 #if wxUSE_CONFIG
2218 void 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
2234 void 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
2249 void 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
2277 void 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
2306 bool 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
2330 bool 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
2353 bool 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
2377 bool 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