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