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