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