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