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