]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/docview.cpp
src/common/strconv.cpps/wcslen/wxWcslen/g
[wxWidgets.git] / src / common / docview.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/docview.cpp
3// Purpose: Document/view classes
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart 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
81IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler)
82IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler)
83IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject)
84IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler)
85IMPLEMENT_CLASS(wxDocChildFrame, wxFrame)
86IMPLEMENT_CLASS(wxDocParentFrame, wxFrame)
87
88#if wxUSE_PRINTING_ARCHITECTURE
89 IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout)
90#endif
91
92IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
93
94// ----------------------------------------------------------------------------
95// function prototypes
96// ----------------------------------------------------------------------------
97
98static inline wxString FindExtension(const wxChar *path);
99
100// ----------------------------------------------------------------------------
101// local constants
102// ----------------------------------------------------------------------------
103
104static const wxChar *s_MRUEntryFormat = wxT("&%d %s");
105
106// ============================================================================
107// implementation
108// ============================================================================
109
110// ----------------------------------------------------------------------------
111// local functions
112// ----------------------------------------------------------------------------
113
114static 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
128wxDocument::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
137bool wxDocument::DeleteContents()
138{
139 return TRUE;
140}
141
142wxDocument::~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
158bool wxDocument::Close()
159{
160 if (OnSaveModified())
161 return OnCloseDocument();
162 else
163 return FALSE;
164}
165
166bool 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.
177bool 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
201wxView *wxDocument::GetFirstView() const
202{
203 if (m_documentViews.Number() == 0)
204 return (wxView *) NULL;
205 return (wxView *)m_documentViews.First()->Data();
206}
207
208wxDocManager *wxDocument::GetDocumentManager() const
209{
210 return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL);
211}
212
213bool 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
231bool 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
242bool 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
286bool 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
323bool 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
369wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream)
370#else
371wxInputStream& wxDocument::LoadObject(wxInputStream& stream)
372#endif
373{
374 return stream;
375}
376
377#if wxUSE_STD_IOSTREAM
378wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream)
379#else
380wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream)
381#endif
382{
383 return stream;
384}
385
386bool wxDocument::Revert()
387{
388 return FALSE;
389}
390
391
392// Get title, or filename if no title, else unnamed
393bool 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
412wxWindow *wxDocument::GetDocumentWindow() const
413{
414 wxView *view = GetFirstView();
415 if (view)
416 return view->GetFrame();
417 else
418 return wxTheApp->GetTopWindow();
419}
420
421wxCommandProcessor *wxDocument::OnCreateCommandProcessor()
422{
423 return new wxCommandProcessor;
424}
425
426// TRUE if safe to close
427bool 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
459bool wxDocument::Draw(wxDC& WXUNUSED(context))
460{
461 return TRUE;
462}
463
464bool 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
474bool wxDocument::RemoveView(wxView *view)
475{
476 (void)m_documentViews.DeleteObject(view);
477 OnChangedViewList();
478 return TRUE;
479}
480
481bool 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.
492void wxDocument::OnChangedViewList()
493{
494 if (m_documentViews.Number() == 0)
495 {
496 if (OnSaveModified())
497 {
498 delete this;
499 }
500 }
501}
502
503void 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
514void 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
525void 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
545wxView::wxView()
546{
547 // SetDocument(doc);
548 m_viewDocument = (wxDocument*) NULL;
549
550 m_viewTypeName = wxT("");
551 m_viewFrame = (wxFrame *) NULL;
552}
553
554wxView::~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
561bool wxView::ProcessEvent(wxEvent& event)
562{
563 if ( !GetDocument() || !GetDocument()->ProcessEvent(event) )
564 return wxEvtHandler::ProcessEvent(event);
565 else
566 return TRUE;
567}
568
569void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView))
570{
571}
572
573void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info))
574{
575 OnDraw(dc);
576}
577
578void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
579{
580}
581
582void wxView::OnChangeFilename()
583{
584 if (GetFrame() && GetDocument())
585 {
586 wxString title;
587
588 GetDocument()->GetPrintableName(title);
589
590 GetFrame()->SetTitle(title);
591 }
592}
593
594void wxView::SetDocument(wxDocument *doc)
595{
596 m_viewDocument = doc;
597 if (doc)
598 doc->AddView(this);
599}
600
601bool wxView::Close(bool deleteWindow)
602{
603 if (OnClose(deleteWindow))
604 return TRUE;
605 else
606 return FALSE;
607}
608
609void wxView::Activate(bool activate)
610{
611 if (GetDocument() && GetDocumentManager())
612 {
613 OnActivateView(activate, this, GetDocumentManager()->GetCurrentView());
614 GetDocumentManager()->ActivateView(this, activate);
615 }
616}
617
618bool wxView::OnClose(bool WXUNUSED(deleteWindow))
619{
620 return GetDocument() ? GetDocument()->Close() : TRUE;
621}
622
623#if wxUSE_PRINTING_ARCHITECTURE
624wxPrintout *wxView::OnCreatePrintout()
625{
626 return new wxDocPrintout(this);
627}
628#endif // wxUSE_PRINTING_ARCHITECTURE
629
630// ----------------------------------------------------------------------------
631// wxDocTemplate
632// ----------------------------------------------------------------------------
633
634wxDocTemplate::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
659wxDocTemplate::~wxDocTemplate()
660{
661 m_documentManager->DisassociateTemplate(this);
662}
663
664// Tries to dynamically construct an object of the right class.
665wxDocument *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
685wxView *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
704bool wxDocTemplate::FileMatchesTemplate(const wxString& path)
705{
706 return GetDefaultExtension().IsSameAs(FindExtension(path));
707}
708
709// ----------------------------------------------------------------------------
710// wxDocManager
711// ----------------------------------------------------------------------------
712
713BEGIN_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
743END_EVENT_TABLE()
744
745wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL;
746
747wxDocManager::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
759wxDocManager::~wxDocManager()
760{
761 Clear();
762 if (m_fileHistory)
763 delete m_fileHistory;
764 sm_docManager = (wxDocManager*) NULL;
765}
766
767bool 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
794bool 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
810bool wxDocManager::Initialize()
811{
812 m_fileHistory = OnCreateFileHistory();
813 return TRUE;
814}
815
816wxFileHistory *wxDocManager::OnCreateFileHistory()
817{
818 return new wxFileHistory;
819}
820
821void 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
834void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event))
835{
836 CloseDocuments(FALSE);
837}
838
839void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event))
840{
841 CreateDocument(wxString(""), wxDOC_NEW);
842}
843
844void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event))
845{
846 if ( !CreateDocument(wxString(""), 0) )
847 {
848 OnOpenFileFailure();
849 }
850}
851
852void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event))
853{
854 wxDocument *doc = GetCurrentDocument();
855 if (!doc)
856 return;
857 doc->Revert();
858}
859
860void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event))
861{
862 wxDocument *doc = GetCurrentDocument();
863 if (!doc)
864 return;
865 doc->Save();
866}
867
868void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event))
869{
870 wxDocument *doc = GetCurrentDocument();
871 if (!doc)
872 return;
873 doc->SaveAs();
874}
875
876void 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
894void 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
910void 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
933void 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
942void 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
953void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event)
954{
955 event.Enable( TRUE );
956}
957
958void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event)
959{
960 wxDocument *doc = GetCurrentDocument();
961 event.Enable( (doc != (wxDocument*) NULL) );
962}
963
964void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event)
965{
966 wxDocument *doc = GetCurrentDocument();
967 event.Enable( (doc != (wxDocument*) NULL) );
968}
969
970void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event)
971{
972 event.Enable( TRUE );
973}
974
975void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event)
976{
977 wxDocument *doc = GetCurrentDocument();
978 event.Enable( doc && doc->IsModified() );
979}
980
981void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event)
982{
983 wxDocument *doc = GetCurrentDocument();
984 event.Enable( (doc != (wxDocument*) NULL) );
985}
986
987void 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
995void 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
1003void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event)
1004{
1005 wxDocument *doc = GetCurrentDocument();
1006 event.Enable( (doc != (wxDocument*) NULL) );
1007}
1008
1009void wxDocManager::OnUpdatePrintSetup(wxUpdateUIEvent& event)
1010{
1011 event.Enable( TRUE );
1012}
1013
1014void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event)
1015{
1016 wxDocument *doc = GetCurrentDocument();
1017 event.Enable( (doc != (wxDocument*) NULL) );
1018}
1019
1020wxView *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
1033bool 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
1044wxDocument *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
1155wxView *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
1201void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags))
1202{
1203}
1204
1205// Not yet implemented
1206bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc))
1207{
1208 return FALSE;
1209}
1210
1211wxDocument *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
1221bool 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.
1231wxString 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
1248wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path))
1249{
1250 return (wxDocTemplate *) NULL;
1251}
1252
1253// File history management
1254void wxDocManager::AddFileToHistory(const wxString& file)
1255{
1256 if (m_fileHistory)
1257 m_fileHistory->AddFileToHistory(file);
1258}
1259
1260void wxDocManager::RemoveFileFromHistory(int i)
1261{
1262 if (m_fileHistory)
1263 m_fileHistory->RemoveFileFromHistory(i);
1264}
1265
1266wxString 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
1276void wxDocManager::FileHistoryUseMenu(wxMenu *menu)
1277{
1278 if (m_fileHistory)
1279 m_fileHistory->UseMenu(menu);
1280}
1281
1282void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu)
1283{
1284 if (m_fileHistory)
1285 m_fileHistory->RemoveMenu(menu);
1286}
1287
1288#if wxUSE_CONFIG
1289void wxDocManager::FileHistoryLoad(wxConfigBase& config)
1290{
1291 if (m_fileHistory)
1292 m_fileHistory->Load(config);
1293}
1294
1295void wxDocManager::FileHistorySave(wxConfigBase& config)
1296{
1297 if (m_fileHistory)
1298 m_fileHistory->Save(config);
1299}
1300#endif
1301
1302void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu)
1303{
1304 if (m_fileHistory)
1305 m_fileHistory->AddFilesToMenu(menu);
1306}
1307
1308void wxDocManager::FileHistoryAddFilesToMenu()
1309{
1310 if (m_fileHistory)
1311 m_fileHistory->AddFilesToMenu();
1312}
1313
1314int 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
1325wxDocTemplate *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.
1346static 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
1370wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates,
1371#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__)
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__) || defined(__WXMAC__)
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
1472wxDocTemplate *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
1552wxDocTemplate *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
1628void wxDocManager::AssociateTemplate(wxDocTemplate *temp)
1629{
1630 if (!m_templates.Member(temp))
1631 m_templates.Append(temp);
1632}
1633
1634void wxDocManager::DisassociateTemplate(wxDocTemplate *temp)
1635{
1636 m_templates.DeleteObject(temp);
1637}
1638
1639// Add and remove a document from the manager's list
1640void wxDocManager::AddDocument(wxDocument *doc)
1641{
1642 if (!m_docs.Member(doc))
1643 m_docs.Append(doc);
1644}
1645
1646void 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
1653void 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
1679BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame)
1680 EVT_ACTIVATE(wxDocChildFrame::OnActivate)
1681 EVT_CLOSE(wxDocChildFrame::OnCloseWindow)
1682END_EVENT_TABLE()
1683
1684wxDocChildFrame::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
1701wxDocChildFrame::~wxDocChildFrame()
1702{
1703}
1704
1705// Extend event processing to search the view's event table
1706bool 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
1723void wxDocChildFrame::OnActivate(wxActivateEvent& event)
1724{
1725 wxFrame::OnActivate(event);
1726
1727 if (m_childView)
1728 m_childView->Activate(event.GetActive());
1729}
1730
1731void 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
1761BEGIN_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)
1765END_EVENT_TABLE()
1766
1767wxDocParentFrame::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
1780void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event))
1781{
1782 Close();
1783}
1784
1785void 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
1810bool 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.
1821void 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
1833wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title)
1834 : wxPrintout(title)
1835{
1836 m_printoutView = view;
1837}
1838
1839bool 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
1875bool wxDocPrintout::HasPage(int pageNum)
1876{
1877 return (pageNum == 1);
1878}
1879
1880bool wxDocPrintout::OnBeginDocument(int startPage, int endPage)
1881{
1882 if (!wxPrintout::OnBeginDocument(startPage, endPage))
1883 return FALSE;
1884
1885 return TRUE;
1886}
1887
1888void 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
1902wxFileHistory::wxFileHistory(int maxFiles)
1903{
1904 m_fileMaxFiles = maxFiles;
1905 m_fileHistoryN = 0;
1906 m_fileHistory = new wxChar *[m_fileMaxFiles];
1907}
1908
1909wxFileHistory::~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
1918void 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
2000void 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
2054wxString 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
2069void wxFileHistory::UseMenu(wxMenu *menu)
2070{
2071 if (!m_fileMenus.Member(menu))
2072 m_fileMenus.Append(menu);
2073}
2074
2075void wxFileHistory::RemoveMenu(wxMenu *menu)
2076{
2077 m_fileMenus.DeleteObject(menu);
2078}
2079
2080#if wxUSE_CONFIG
2081void 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
2097void 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
2109void 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
2133void 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
2157bool 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
2172bool 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
2192bool 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
2207bool 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