1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Document/view classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "docview.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
35 #if wxUSE_DOC_VIEW_ARCHITECTURE
38 #include "wx/string.h"
42 #include "wx/dialog.h"
45 #include "wx/filedlg.h"
53 #include "wx/msgdlg.h"
54 #include "wx/choicdlg.h"
55 #include "wx/docview.h"
56 #include "wx/printdlg.h"
57 #include "wx/confbase.h"
62 #include "wx/ioswrap.h"
70 // ----------------------------------------------------------------------------
72 // ----------------------------------------------------------------------------
74 #if !USE_SHARED_LIBRARY
75 IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler)
76 IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler)
77 IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject)
78 IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler)
79 IMPLEMENT_CLASS(wxDocChildFrame, wxFrame)
80 IMPLEMENT_CLASS(wxDocParentFrame, wxFrame)
82 #if wxUSE_PRINTING_ARCHITECTURE
83 IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout)
86 IMPLEMENT_CLASS(wxCommand, wxObject)
87 IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject)
88 IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
91 // ----------------------------------------------------------------------------
92 // function prototypes
93 // ----------------------------------------------------------------------------
95 static inline wxString FindExtension(const wxChar *path);
97 // ============================================================================
99 // ============================================================================
101 // ----------------------------------------------------------------------------
103 // ----------------------------------------------------------------------------
105 static wxString FindExtension(const wxChar *path)
108 wxSplitPath(path, NULL, NULL, &ext);
110 // VZ: extensions are considered not case sensitive - is this really a good
112 return ext.MakeLower();
115 // ----------------------------------------------------------------------------
116 // Definition of wxDocument
117 // ----------------------------------------------------------------------------
119 wxDocument::wxDocument(wxDocument *parent)
121 m_documentModified = FALSE;
122 m_documentParent = parent;
123 m_documentTemplate = (wxDocTemplate *) NULL;
127 bool wxDocument::DeleteContents()
132 wxDocument::~wxDocument()
136 if (m_commandProcessor)
137 delete m_commandProcessor;
139 GetDocumentManager()->RemoveDocument(this);
141 // Not safe to do here, since it'll invoke virtual view functions
142 // expecting to see valid derived objects: and by the time we get here,
143 // we've called destructors higher up.
147 bool wxDocument::Close()
149 if (OnSaveModified())
150 return OnCloseDocument();
155 bool wxDocument::OnCloseDocument()
162 // Note that this implicitly deletes the document when the last view is
164 bool wxDocument::DeleteAllViews()
166 wxNode *node = m_documentViews.First();
169 wxView *view = (wxView *)node->Data();
173 wxNode *next = node->Next();
175 delete view; // Deletes node implicitly
181 wxView *wxDocument::GetFirstView() const
183 if (m_documentViews.Number() == 0)
184 return (wxView *) NULL;
185 return (wxView *)m_documentViews.First()->Data();
188 wxDocManager *wxDocument::GetDocumentManager() const
190 return m_documentTemplate->GetDocumentManager();
193 bool wxDocument::OnNewDocument()
195 if (!OnSaveModified())
198 if (OnCloseDocument()==FALSE) return FALSE;
201 SetDocumentSaved(FALSE);
204 GetDocumentManager()->MakeDefaultName(name);
206 SetFilename(name, TRUE);
211 bool wxDocument::Save()
215 if (!IsModified()) return TRUE;
216 if (m_documentFile == _T("") || !m_savedYet)
219 ret = OnSaveDocument(m_documentFile);
221 SetDocumentSaved(TRUE);
225 bool wxDocument::SaveAs()
227 wxDocTemplate *docTemplate = GetDocumentTemplate();
231 wxString tmp = wxFileSelector(_("Save as"),
232 docTemplate->GetDirectory(),
234 docTemplate->GetDefaultExtension(),
235 docTemplate->GetFileFilter(),
236 wxSAVE | wxOVERWRITE_PROMPT,
237 GetDocumentWindow());
242 wxString fileName(tmp);
246 wxSplitPath(fileName, & path, & name, & ext);
248 if (ext.IsEmpty() || ext == _T(""))
251 fileName += docTemplate->GetDefaultExtension();
254 SetFilename(fileName);
255 SetTitle(wxFileNameFromPath(fileName));
257 GetDocumentManager()->AddFileToHistory(fileName);
259 // Notify the views that the filename has changed
260 wxNode *node = m_documentViews.First();
263 wxView *view = (wxView *)node->Data();
264 view->OnChangeFilename();
268 return OnSaveDocument(m_documentFile);
271 bool wxDocument::OnSaveDocument(const wxString& file)
277 if (wxTheApp->GetAppName() != _T(""))
278 msgTitle = wxTheApp->GetAppName();
280 msgTitle = wxString(_("File error"));
282 ofstream store(file.fn_str());
283 if (store.fail() || store.bad())
285 (void)wxMessageBox(_("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION,
286 GetDocumentWindow());
290 if (SaveObject(store)==FALSE)
292 (void)wxMessageBox(_("Sorry, could not save this file."), msgTitle, wxOK | wxICON_EXCLAMATION,
293 GetDocumentWindow());
302 bool wxDocument::OnOpenDocument(const wxString& file)
304 if (!OnSaveModified())
308 if (wxTheApp->GetAppName() != _T(""))
309 msgTitle = wxTheApp->GetAppName();
311 msgTitle = wxString(_("File error"));
313 ifstream store(file.fn_str());
314 if (store.fail() || store.bad())
316 (void)wxMessageBox(_("Sorry, could not open this file."), msgTitle, wxOK|wxICON_EXCLAMATION,
317 GetDocumentWindow());
320 if (LoadObject(store)==FALSE)
322 (void)wxMessageBox(_("Sorry, could not open this file."), msgTitle, wxOK|wxICON_EXCLAMATION,
323 GetDocumentWindow());
326 SetFilename(file, TRUE);
335 istream& wxDocument::LoadObject(istream& stream)
337 // wxObject::LoadObject(stream);
342 ostream& wxDocument::SaveObject(ostream& stream)
344 // wxObject::SaveObject(stream);
349 bool wxDocument::Revert()
355 // Get title, or filename if no title, else unnamed
356 bool wxDocument::GetPrintableName(wxString& buf) const
358 if (m_documentTitle != _T(""))
360 buf = m_documentTitle;
363 else if (m_documentFile != _T(""))
365 buf = wxFileNameFromPath(m_documentFile);
375 wxWindow *wxDocument::GetDocumentWindow() const
377 wxView *view = GetFirstView();
379 return view->GetFrame();
381 return wxTheApp->GetTopWindow();
384 wxCommandProcessor *wxDocument::OnCreateCommandProcessor()
386 return new wxCommandProcessor;
389 // TRUE if safe to close
390 bool wxDocument::OnSaveModified()
395 GetPrintableName(title);
398 if (wxTheApp->GetAppName() != _T(""))
399 msgTitle = wxTheApp->GetAppName();
401 msgTitle = wxString(_("Warning"));
404 prompt.Printf(_("Do you want to save changes to document %s?"),
405 (const wxChar *)title);
406 int res = wxMessageBox(prompt, msgTitle,
407 wxYES_NO|wxCANCEL|wxICON_QUESTION,
408 GetDocumentWindow());
414 else if (res == wxYES)
416 else if (res == wxCANCEL)
422 bool wxDocument::Draw(wxDC& WXUNUSED(context))
427 bool wxDocument::AddView(wxView *view)
429 if (!m_documentViews.Member(view))
431 m_documentViews.Append(view);
437 bool wxDocument::RemoveView(wxView *view)
439 (void)m_documentViews.DeleteObject(view);
444 bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags)
446 if (GetDocumentTemplate()->CreateView(this, flags))
452 // Called after a view is added or removed.
453 // The default implementation deletes the document if
454 // there are no more views.
455 void wxDocument::OnChangedViewList()
457 if (m_documentViews.Number() == 0)
459 if (OnSaveModified())
466 void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint)
468 wxNode *node = m_documentViews.First();
471 wxView *view = (wxView *)node->Data();
472 view->OnUpdate(sender, hint);
477 void wxDocument::SetFilename(const wxString& filename, bool notifyViews)
479 m_documentFile = filename;
482 // Notify the views that the filename has changed
483 wxNode *node = m_documentViews.First();
486 wxView *view = (wxView *)node->Data();
487 view->OnChangeFilename();
493 // ----------------------------------------------------------------------------
495 // ----------------------------------------------------------------------------
500 m_viewDocument = (wxDocument*) NULL;
503 m_viewFrame = (wxFrame *) NULL;
508 GetDocumentManager()->ActivateView(this, FALSE, TRUE);
509 m_viewDocument->RemoveView(this);
512 // Extend event processing to search the document's event table
513 bool wxView::ProcessEvent(wxEvent& event)
515 if ( !GetDocument() || !GetDocument()->ProcessEvent(event) )
516 return wxEvtHandler::ProcessEvent(event);
521 void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView))
525 void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info))
530 void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
534 void wxView::OnChangeFilename()
536 if (GetFrame() && GetDocument())
539 GetDocument()->GetPrintableName(name);
541 GetFrame()->SetTitle(name);
545 void wxView::SetDocument(wxDocument *doc)
547 m_viewDocument = doc;
552 bool wxView::Close(bool deleteWindow)
554 if (OnClose(deleteWindow))
560 void wxView::Activate(bool activate)
562 if (GetDocumentManager())
564 OnActivateView(activate, this, GetDocumentManager()->GetCurrentView());
565 GetDocumentManager()->ActivateView(this, activate);
569 bool wxView::OnClose(bool WXUNUSED(deleteWindow))
571 return GetDocument() ? GetDocument()->Close() : TRUE;
574 #if wxUSE_PRINTING_ARCHITECTURE
575 wxPrintout *wxView::OnCreatePrintout()
577 return new wxDocPrintout(this);
579 #endif // wxUSE_PRINTING_ARCHITECTURE
581 // ----------------------------------------------------------------------------
583 // ----------------------------------------------------------------------------
585 wxDocTemplate::wxDocTemplate(wxDocManager *manager,
586 const wxString& descr,
587 const wxString& filter,
590 const wxString& docTypeName,
591 const wxString& viewTypeName,
592 wxClassInfo *docClassInfo,
593 wxClassInfo *viewClassInfo,
596 m_documentManager = manager;
597 m_description = descr;
600 m_fileFilter = filter;
602 m_docTypeName = docTypeName;
603 m_viewTypeName = viewTypeName;
604 m_documentManager->AssociateTemplate(this);
606 m_docClassInfo = docClassInfo;
607 m_viewClassInfo = viewClassInfo;
610 wxDocTemplate::~wxDocTemplate()
612 m_documentManager->DisassociateTemplate(this);
615 // Tries to dynamically construct an object of the right class.
616 wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags)
619 return (wxDocument *) NULL;
620 wxDocument *doc = (wxDocument *)m_docClassInfo->CreateObject();
621 doc->SetFilename(path);
622 doc->SetDocumentTemplate(this);
623 GetDocumentManager()->AddDocument(doc);
624 doc->SetCommandProcessor(doc->OnCreateCommandProcessor());
626 if (doc->OnCreate(path, flags))
631 return (wxDocument *) NULL;
635 wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags)
637 if (!m_viewClassInfo)
638 return (wxView *) NULL;
639 wxView *view = (wxView *)m_viewClassInfo->CreateObject();
640 view->SetDocument(doc);
641 if (view->OnCreate(doc, flags))
648 return (wxView *) NULL;
652 // The default (very primitive) format detection: check is the extension is
653 // that of the template
654 bool wxDocTemplate::FileMatchesTemplate(const wxString& path)
656 return GetDefaultExtension().IsSameAs(FindExtension(path));
659 // ----------------------------------------------------------------------------
661 // ----------------------------------------------------------------------------
663 BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler)
664 EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen)
665 EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose)
666 EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert)
667 EVT_MENU(wxID_NEW, wxDocManager::OnFileNew)
668 EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave)
669 EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs)
670 EVT_MENU(wxID_UNDO, wxDocManager::OnUndo)
671 EVT_MENU(wxID_REDO, wxDocManager::OnRedo)
672 EVT_MENU(wxID_PRINT, wxDocManager::OnPrint)
673 EVT_MENU(wxID_PRINT_SETUP, wxDocManager::OnPrintSetup)
674 EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview)
677 wxDocManager::wxDocManager(long flags, bool initialize)
679 m_defaultDocumentNameCounter = 1;
681 m_currentView = (wxView *) NULL;
682 m_maxDocsOpen = 10000;
683 m_fileHistory = (wxFileHistory *) NULL;
688 wxDocManager::~wxDocManager()
692 delete m_fileHistory;
695 bool wxDocManager::Clear(bool force)
697 wxNode *node = m_docs.First();
700 wxDocument *doc = (wxDocument *)node->Data();
701 wxNode *next = node->Next();
703 if (!doc->Close() && !force)
706 // Implicitly deletes the document when the last
707 // view is removed (deleted)
708 doc->DeleteAllViews();
710 // Check document is deleted
711 if (m_docs.Member(doc))
714 // This assumes that documents are not connected in
715 // any way, i.e. deleting one document does NOT
719 node = m_templates.First();
722 wxDocTemplate *templ = (wxDocTemplate*) node->Data();
723 wxNode* next = node->Next();
730 bool wxDocManager::Initialize()
732 m_fileHistory = OnCreateFileHistory();
736 wxFileHistory *wxDocManager::OnCreateFileHistory()
738 return new wxFileHistory;
741 void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event))
743 wxDocument *doc = GetCurrentDocument();
748 doc->DeleteAllViews();
749 if (m_docs.Member(doc))
754 void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event))
756 CreateDocument(wxString(""), wxDOC_NEW);
759 void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event))
761 CreateDocument(wxString(""), 0);
764 void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event))
766 wxDocument *doc = GetCurrentDocument();
772 void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event))
774 wxDocument *doc = GetCurrentDocument();
780 void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event))
782 wxDocument *doc = GetCurrentDocument();
788 void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event))
790 wxView *view = GetCurrentView();
794 wxPrintout *printout = view->OnCreatePrintout();
798 printer.Print(view->GetFrame(), printout, TRUE);
804 void wxDocManager::OnPrintSetup(wxCommandEvent& WXUNUSED(event))
806 wxWindow *parentWin = wxTheApp->GetTopWindow();
807 wxView *view = GetCurrentView();
809 parentWin = view->GetFrame();
811 wxPrintDialogData data;
813 wxPrintDialog printerDialog(parentWin, & data);
814 printerDialog.GetPrintDialogData().SetSetupDialog(TRUE);
815 printerDialog.ShowModal();
818 void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event))
820 wxView *view = GetCurrentView();
824 wxPrintout *printout = view->OnCreatePrintout();
827 // Pass two printout objects: for preview, and possible printing.
828 wxPrintPreviewBase *preview = (wxPrintPreviewBase *) NULL;
829 preview = new wxPrintPreview(printout, view->OnCreatePrintout());
831 wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), _("Print Preview"),
832 wxPoint(100, 100), wxSize(600, 650));
833 frame->Centre(wxBOTH);
839 void wxDocManager::OnUndo(wxCommandEvent& WXUNUSED(event))
841 wxDocument *doc = GetCurrentDocument();
844 if (doc->GetCommandProcessor())
845 doc->GetCommandProcessor()->Undo();
848 void wxDocManager::OnRedo(wxCommandEvent& WXUNUSED(event))
850 wxDocument *doc = GetCurrentDocument();
853 if (doc->GetCommandProcessor())
854 doc->GetCommandProcessor()->Redo();
857 wxView *wxDocManager::GetCurrentView() const
860 return m_currentView;
861 if (m_docs.Number() == 1)
863 wxDocument* doc = (wxDocument*) m_docs.First()->Data();
864 return doc->GetFirstView();
866 return (wxView *) NULL;
869 // Extend event processing to search the view's event table
870 bool wxDocManager::ProcessEvent(wxEvent& event)
872 wxView* view = GetCurrentView();
875 if (view->ProcessEvent(event))
878 return wxEvtHandler::ProcessEvent(event);
881 wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags)
883 wxDocTemplate **templates = new wxDocTemplate *[m_templates.Number()];
886 for (i = 0; i < m_templates.Number(); i++)
888 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Nth(i)->Data());
889 if (temp->IsVisible())
898 return (wxDocument *) NULL;
901 // If we've reached the max number of docs, close the
903 if (GetDocuments().Number() >= m_maxDocsOpen)
905 wxDocument *doc = (wxDocument *)GetDocuments().First()->Data();
908 // Implicitly deletes the document when
909 // the last view is deleted
910 doc->DeleteAllViews();
912 // Check we're really deleted
913 if (m_docs.Member(doc))
917 return (wxDocument *) NULL;
920 // New document: user chooses a template, unless there's only one.
921 if (flags & wxDOC_NEW)
925 wxDocTemplate *temp = templates[0];
927 wxDocument *newDoc = temp->CreateDocument(path, flags);
930 newDoc->SetDocumentName(temp->GetDocumentName());
931 newDoc->SetDocumentTemplate(temp);
932 newDoc->OnNewDocument();
937 wxDocTemplate *temp = SelectDocumentType(templates, n);
941 wxDocument *newDoc = temp->CreateDocument(path, flags);
944 newDoc->SetDocumentName(temp->GetDocumentName());
945 newDoc->SetDocumentTemplate(temp);
946 newDoc->OnNewDocument();
951 return (wxDocument *) NULL;
955 wxDocTemplate *temp = (wxDocTemplate *) NULL;
957 wxString path2(_T(""));
961 if (flags & wxDOC_SILENT)
962 temp = FindTemplateForPath(path2);
964 temp = SelectDocumentPath(templates, n, path2, flags);
970 wxDocument *newDoc = temp->CreateDocument(path2, flags);
973 newDoc->SetDocumentName(temp->GetDocumentName());
974 newDoc->SetDocumentTemplate(temp);
975 if (!newDoc->OnOpenDocument(path2))
978 return (wxDocument *) NULL;
980 AddFileToHistory(path2);
985 return (wxDocument *) NULL;
988 wxView *wxDocManager::CreateView(wxDocument *doc, long flags)
990 wxDocTemplate **templates = new wxDocTemplate *[m_templates.Number()];
993 for (i = 0; i < m_templates.Number(); i++)
995 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Nth(i)->Data());
996 if (temp->IsVisible())
998 if (temp->GetDocumentName() == doc->GetDocumentName())
1000 templates[n] = temp;
1008 return (wxView *) NULL;
1012 wxDocTemplate *temp = templates[0];
1014 wxView *view = temp->CreateView(doc, flags);
1016 view->SetViewName(temp->GetViewName());
1020 wxDocTemplate *temp = SelectViewType(templates, n);
1024 wxView *view = temp->CreateView(doc, flags);
1026 view->SetViewName(temp->GetViewName());
1030 return (wxView *) NULL;
1033 // Not yet implemented
1034 void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags))
1038 // Not yet implemented
1039 bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc))
1044 wxDocument *wxDocManager::GetCurrentDocument() const
1047 return m_currentView->GetDocument();
1049 return (wxDocument *) NULL;
1052 // Make a default document name
1053 bool wxDocManager::MakeDefaultName(wxString& name)
1055 name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter);
1056 m_defaultDocumentNameCounter++;
1061 // Not yet implemented
1062 wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path))
1064 return (wxDocTemplate *) NULL;
1067 // File history management
1068 void wxDocManager::AddFileToHistory(const wxString& file)
1071 m_fileHistory->AddFileToHistory(file);
1074 wxString wxDocManager::GetHistoryFile(int i) const
1079 histFile = m_fileHistory->GetHistoryFile(i);
1084 void wxDocManager::FileHistoryUseMenu(wxMenu *menu)
1087 m_fileHistory->UseMenu(menu);
1090 void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu)
1093 m_fileHistory->RemoveMenu(menu);
1097 void wxDocManager::FileHistoryLoad(wxConfigBase& config)
1100 m_fileHistory->Load(config);
1103 void wxDocManager::FileHistorySave(wxConfigBase& config)
1106 m_fileHistory->Save(config);
1110 void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu)
1113 m_fileHistory->AddFilesToMenu(menu);
1116 void wxDocManager::FileHistoryAddFilesToMenu()
1119 m_fileHistory->AddFilesToMenu();
1122 int wxDocManager::GetNoHistoryFiles() const
1125 return m_fileHistory->GetNoHistoryFiles();
1131 // Find out the document template via matching in the document file format
1132 // against that of the template
1133 wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path)
1135 wxDocTemplate *theTemplate = (wxDocTemplate *) NULL;
1137 // Find the template which this extension corresponds to
1139 for (i = 0; i < m_templates.Number(); i++)
1141 wxDocTemplate *temp = (wxDocTemplate *)m_templates.Nth(i)->Data();
1142 if ( temp->FileMatchesTemplate(path) )
1151 // Prompts user to open a file, using file specs in templates.
1152 // How to implement in wxWindows? Must extend the file selector
1153 // dialog or implement own; OR match the extension to the
1154 // template extension.
1156 wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates,
1160 int WXUNUSED(noTemplates),
1163 long WXUNUSED(flags),
1164 bool WXUNUSED(save))
1166 // We can only have multiple filters in Windows
1171 for (i = 0; i < noTemplates; i++)
1173 if (templates[i]->IsVisible())
1175 // add a '|' to separate this filter from the previous one
1176 if ( !descrBuf.IsEmpty() )
1177 descrBuf << _T('|');
1179 descrBuf << templates[i]->GetDescription()
1180 << _T(" (") << templates[i]->GetFileFilter() << _T(") |")
1181 << templates[i]->GetFileFilter();
1185 wxString descrBuf = _T("*.*");
1188 int FilterIndex = 0;
1189 wxString pathTmp = wxFileSelectorEx(_("Select a file"),
1195 wxTheApp->GetTopWindow());
1197 if (!pathTmp.IsEmpty())
1200 wxString theExt = FindExtension(path);
1202 return (wxDocTemplate *) NULL;
1204 // This is dodgy in that we're selecting the template on the
1205 // basis of the file extension, which may not be a standard
1206 // one. We really want to know exactly which template was
1207 // chosen by using a more advanced file selector.
1208 wxDocTemplate *theTemplate = FindTemplateForPath(path);
1210 theTemplate = templates[FilterIndex];
1217 return (wxDocTemplate *) NULL;
1220 // In all other windowing systems, until we have more advanced
1221 // file selectors, we must select the document type (template) first, and
1222 // _then_ pop up the file selector.
1223 wxDocTemplate *temp = SelectDocumentType(templates, noTemplates);
1225 return (wxDocTemplate *) NULL;
1227 wxChar *pathTmp = wxFileSelector(_("Select a file"), _T(""), _T(""),
1228 temp->GetDefaultExtension(),
1229 temp->GetFileFilter(),
1230 0, wxTheApp->GetTopWindow());
1238 return (wxDocTemplate *) NULL;
1242 wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates,
1245 wxChar **strings = new wxChar *[noTemplates];
1246 wxChar **data = new wxChar *[noTemplates];
1249 for (i = 0; i < noTemplates; i++)
1251 if (templates[i]->IsVisible())
1253 strings[n] = WXSTRINGCAST templates[i]->m_description;
1254 data[n] = (wxChar *)templates[i];
1262 return (wxDocTemplate *) NULL;
1266 wxDocTemplate *temp = (wxDocTemplate *)data[0];
1272 wxDocTemplate *theTemplate = (wxDocTemplate *)wxGetSingleChoiceData(_("Select a document template"), _("Templates"), n,
1279 wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates,
1282 wxChar **strings = new wxChar *[noTemplates];
1283 wxChar **data = new wxChar *[noTemplates];
1286 for (i = 0; i < noTemplates; i++)
1288 if (templates[i]->IsVisible() && (templates[i]->GetViewName() != _T("")))
1290 strings[n] = WXSTRINGCAST templates[i]->m_viewTypeName;
1291 data[n] = (wxChar *)templates[i];
1295 wxDocTemplate *theTemplate = (wxDocTemplate *)wxGetSingleChoiceData(_("Select a document view"), _("Views"), n,
1302 void wxDocManager::AssociateTemplate(wxDocTemplate *temp)
1304 if (!m_templates.Member(temp))
1305 m_templates.Append(temp);
1308 void wxDocManager::DisassociateTemplate(wxDocTemplate *temp)
1310 m_templates.DeleteObject(temp);
1313 // Add and remove a document from the manager's list
1314 void wxDocManager::AddDocument(wxDocument *doc)
1316 if (!m_docs.Member(doc))
1320 void wxDocManager::RemoveDocument(wxDocument *doc)
1322 m_docs.DeleteObject(doc);
1325 // Views or windows should inform the document manager
1326 // when a view is going in or out of focus
1327 void wxDocManager::ActivateView(wxView *view, bool activate, bool WXUNUSED(deleting))
1329 // If we're deactiving, and if we're not actually deleting the view, then
1330 // don't reset the current view because we may be going to
1331 // a window without a view.
1332 // WHAT DID I MEAN BY THAT EXACTLY?
1336 if (m_currentView == view)
1337 m_currentView = NULL;
1343 m_currentView = view;
1345 m_currentView = (wxView *) NULL;
1349 // ----------------------------------------------------------------------------
1350 // Default document child frame
1351 // ----------------------------------------------------------------------------
1353 BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame)
1354 EVT_ACTIVATE(wxDocChildFrame::OnActivate)
1355 EVT_CLOSE(wxDocChildFrame::OnCloseWindow)
1358 wxDocChildFrame::wxDocChildFrame(wxDocument *doc,
1362 const wxString& title,
1366 const wxString& name)
1367 : wxFrame(frame, id, title, pos, size, style, name)
1369 m_childDocument = doc;
1372 view->SetFrame(this);
1375 wxDocChildFrame::~wxDocChildFrame()
1379 // Extend event processing to search the view's event table
1380 bool wxDocChildFrame::ProcessEvent(wxEvent& event)
1383 m_childView->Activate(TRUE);
1385 if ( !m_childView || ! m_childView->ProcessEvent(event) )
1387 // Only hand up to the parent if it's a menu command
1388 if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event))
1389 return wxEvtHandler::ProcessEvent(event);
1397 void wxDocChildFrame::OnActivate(wxActivateEvent& event)
1399 wxFrame::OnActivate(event);
1402 m_childView->Activate(event.GetActive());
1405 void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event)
1410 if (!event.CanVeto())
1411 ans = TRUE; // Must delete.
1413 ans = m_childView->Close(FALSE); // FALSE means don't delete associated window
1417 m_childView->Activate(FALSE);
1419 m_childView = (wxView *) NULL;
1420 m_childDocument = (wxDocument *) NULL;
1431 // ----------------------------------------------------------------------------
1432 // Default parent frame
1433 // ----------------------------------------------------------------------------
1435 BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame)
1436 EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit)
1437 EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile)
1438 EVT_CLOSE(wxDocParentFrame::OnCloseWindow)
1441 wxDocParentFrame::wxDocParentFrame(wxDocManager *manager,
1444 const wxString& title,
1448 const wxString& name)
1449 : wxFrame(frame, id, title, pos, size, style, name)
1451 m_docManager = manager;
1454 void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event))
1459 void wxDocParentFrame::OnMRUFile(wxCommandEvent& event)
1461 wxString f(m_docManager->GetHistoryFile(event.GetSelection() - wxID_FILE1));
1463 (void)m_docManager->CreateDocument(f, wxDOC_SILENT);
1466 // Extend event processing to search the view's event table
1467 bool wxDocParentFrame::ProcessEvent(wxEvent& event)
1469 // Try the document manager, then do default processing
1470 if (!m_docManager || !m_docManager->ProcessEvent(event))
1471 return wxEvtHandler::ProcessEvent(event);
1476 // Define the behaviour for the frame closing
1477 // - must delete all frames except for the main one.
1478 void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event)
1480 if (m_docManager->Clear(!event.CanVeto()))
1488 #if wxUSE_PRINTING_ARCHITECTURE
1490 wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title)
1491 : wxPrintout(WXSTRINGCAST title)
1493 m_printoutView = view;
1496 bool wxDocPrintout::OnPrintPage(int WXUNUSED(page))
1500 // Get the logical pixels per inch of screen and printer
1501 int ppiScreenX, ppiScreenY;
1502 GetPPIScreen(&ppiScreenX, &ppiScreenY);
1503 int ppiPrinterX, ppiPrinterY;
1504 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
1506 // This scales the DC so that the printout roughly represents the
1507 // the screen scaling. The text point size _should_ be the right size
1508 // but in fact is too small for some reason. This is a detail that will
1509 // need to be addressed at some point but can be fudged for the
1511 float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
1513 // Now we have to check in case our real page size is reduced
1514 // (e.g. because we're drawing to a print preview memory DC)
1515 int pageWidth, pageHeight;
1517 dc->GetSize(&w, &h);
1518 GetPageSizePixels(&pageWidth, &pageHeight);
1520 // If printer pageWidth == current DC width, then this doesn't
1521 // change. But w might be the preview bitmap width, so scale down.
1522 float overallScale = scale * (float)(w/(float)pageWidth);
1523 dc->SetUserScale(overallScale, overallScale);
1527 m_printoutView->OnDraw(dc);
1532 bool wxDocPrintout::HasPage(int pageNum)
1534 return (pageNum == 1);
1537 bool wxDocPrintout::OnBeginDocument(int startPage, int endPage)
1539 if (!wxPrintout::OnBeginDocument(startPage, endPage))
1545 void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
1553 #endif // wxUSE_PRINTING_ARCHITECTURE
1555 // ----------------------------------------------------------------------------
1556 // Command processing framework
1557 // ----------------------------------------------------------------------------
1559 wxCommand::wxCommand(bool canUndoIt, const wxString& name)
1561 m_canUndo = canUndoIt;
1562 m_commandName = name;
1565 wxCommand::~wxCommand()
1569 // Command processor
1570 wxCommandProcessor::wxCommandProcessor(int maxCommands)
1572 m_maxNoCommands = maxCommands;
1573 m_currentCommand = (wxNode *) NULL;
1574 m_commandEditMenu = (wxMenu *) NULL;
1577 wxCommandProcessor::~wxCommandProcessor()
1582 // Pass a command to the processor. The processor calls Do();
1583 // if successful, is appended to the command history unless
1584 // storeIt is FALSE.
1585 bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt)
1587 bool success = command->Do();
1588 if (success && storeIt)
1590 if (m_commands.Number() == m_maxNoCommands)
1592 wxNode *firstNode = m_commands.First();
1593 wxCommand *firstCommand = (wxCommand *)firstNode->Data();
1594 delete firstCommand;
1598 // Correct a bug: we must chop off the current 'branch'
1599 // so that we're at the end of the command list.
1600 if (!m_currentCommand)
1604 wxNode *node = m_currentCommand->Next();
1607 wxNode *next = node->Next();
1608 delete (wxCommand *)node->Data();
1614 m_commands.Append(command);
1615 m_currentCommand = m_commands.Last();
1621 bool wxCommandProcessor::Undo()
1623 if (m_currentCommand)
1625 wxCommand *command = (wxCommand *)m_currentCommand->Data();
1626 if (command->CanUndo())
1628 bool success = command->Undo();
1631 m_currentCommand = m_currentCommand->Previous();
1640 bool wxCommandProcessor::Redo()
1642 wxCommand *redoCommand = (wxCommand *) NULL;
1643 wxNode *redoNode = (wxNode *) NULL;
1644 if (m_currentCommand && m_currentCommand->Next())
1646 redoCommand = (wxCommand *)m_currentCommand->Next()->Data();
1647 redoNode = m_currentCommand->Next();
1651 if (m_commands.Number() > 0)
1653 redoCommand = (wxCommand *)m_commands.First()->Data();
1654 redoNode = m_commands.First();
1660 bool success = redoCommand->Do();
1663 m_currentCommand = redoNode;
1671 bool wxCommandProcessor::CanUndo() const
1673 if (m_currentCommand)
1674 return ((wxCommand *)m_currentCommand->Data())->CanUndo();
1678 bool wxCommandProcessor::CanRedo() const
1680 if ((m_currentCommand != (wxNode*) NULL) && (m_currentCommand->Next() == (wxNode*) NULL))
1683 if ((m_currentCommand != (wxNode*) NULL) && (m_currentCommand->Next() != (wxNode*) NULL))
1686 if ((m_currentCommand == (wxNode*) NULL) && (m_commands.Number() > 0))
1692 void wxCommandProcessor::Initialize()
1694 m_currentCommand = m_commands.Last();
1698 void wxCommandProcessor::SetMenuStrings()
1700 if (m_commandEditMenu)
1703 if (m_currentCommand)
1705 wxCommand *command = (wxCommand *)m_currentCommand->Data();
1706 wxString commandName(command->GetName());
1707 if (commandName == _T("")) commandName = _("Unnamed command");
1708 bool canUndo = command->CanUndo();
1710 buf = wxString(_("&Undo ")) + commandName;
1712 buf = wxString(_("Can't &Undo ")) + commandName;
1714 m_commandEditMenu->SetLabel(wxID_UNDO, buf);
1715 m_commandEditMenu->Enable(wxID_UNDO, canUndo);
1717 // We can redo, if we're not at the end of the history.
1718 if (m_currentCommand->Next())
1720 wxCommand *redoCommand = (wxCommand *)m_currentCommand->Next()->Data();
1721 wxString redoCommandName(redoCommand->GetName());
1722 if (redoCommandName == _T("")) redoCommandName = _("Unnamed command");
1723 buf = wxString(_("&Redo ")) + redoCommandName;
1724 m_commandEditMenu->SetLabel(wxID_REDO, buf);
1725 m_commandEditMenu->Enable(wxID_REDO, TRUE);
1729 m_commandEditMenu->SetLabel(wxID_REDO, _("&Redo"));
1730 m_commandEditMenu->Enable(wxID_REDO, FALSE);
1735 m_commandEditMenu->SetLabel(wxID_UNDO, _("&Undo"));
1736 m_commandEditMenu->Enable(wxID_UNDO, FALSE);
1738 if (m_commands.Number() == 0)
1740 m_commandEditMenu->SetLabel(wxID_REDO, _("&Redo"));
1741 m_commandEditMenu->Enable(wxID_REDO, FALSE);
1745 // currentCommand is NULL but there are commands: this means that
1746 // we've undone to the start of the list, but can redo the first.
1747 wxCommand *redoCommand = (wxCommand *)m_commands.First()->Data();
1748 wxString redoCommandName(redoCommand->GetName());
1749 if (redoCommandName == _T("")) redoCommandName = _("Unnamed command");
1750 buf = wxString(_("&Redo ")) + redoCommandName;
1751 m_commandEditMenu->SetLabel(wxID_REDO, buf);
1752 m_commandEditMenu->Enable(wxID_REDO, TRUE);
1758 void wxCommandProcessor::ClearCommands()
1760 wxNode *node = m_commands.First();
1763 wxCommand *command = (wxCommand *)node->Data();
1766 node = m_commands.First();
1768 m_currentCommand = (wxNode *) NULL;
1771 // ----------------------------------------------------------------------------
1772 // File history processor
1773 // ----------------------------------------------------------------------------
1775 wxFileHistory::wxFileHistory(int maxFiles)
1777 m_fileMaxFiles = maxFiles;
1779 m_fileHistory = new wxChar *[m_fileMaxFiles];
1782 wxFileHistory::~wxFileHistory()
1785 for (i = 0; i < m_fileHistoryN; i++)
1786 delete[] m_fileHistory[i];
1787 delete[] m_fileHistory;
1790 // File history management
1791 void wxFileHistory::AddFileToHistory(const wxString& file)
1794 // Check we don't already have this file
1795 for (i = 0; i < m_fileHistoryN; i++)
1797 if (m_fileHistory[i] && wxString(m_fileHistory[i]) == file)
1801 // Add to the project file history:
1802 // Move existing files (if any) down so we can insert file at beginning.
1804 // First delete filename that has popped off the end of the array (if any)
1805 if (m_fileHistoryN == m_fileMaxFiles)
1807 delete[] m_fileHistory[m_fileMaxFiles-1];
1808 m_fileHistory[m_fileMaxFiles-1] = (wxChar *) NULL;
1810 if (m_fileHistoryN < m_fileMaxFiles)
1812 wxNode* node = m_fileMenus.First();
1815 wxMenu* menu = (wxMenu*) node->Data();
1816 if (m_fileHistoryN == 0)
1817 menu->AppendSeparator();
1818 menu->Append(wxID_FILE1+m_fileHistoryN, _("[EMPTY]"));
1819 node = node->Next();
1823 // Shuffle filenames down
1824 for (i = (m_fileHistoryN-1); i > 0; i--)
1826 m_fileHistory[i] = m_fileHistory[i-1];
1828 m_fileHistory[0] = copystring(file);
1830 for (i = 0; i < m_fileHistoryN; i++)
1831 if (m_fileHistory[i])
1834 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
1835 wxNode* node = m_fileMenus.First();
1838 wxMenu* menu = (wxMenu*) node->Data();
1839 menu->SetLabel(wxID_FILE1+i, buf);
1840 node = node->Next();
1845 wxString wxFileHistory::GetHistoryFile(int i) const
1847 if (i < m_fileHistoryN)
1848 return wxString(m_fileHistory[i]);
1850 return wxString("");
1853 void wxFileHistory::UseMenu(wxMenu *menu)
1855 if (!m_fileMenus.Member(menu))
1856 m_fileMenus.Append(menu);
1859 void wxFileHistory::RemoveMenu(wxMenu *menu)
1861 m_fileMenus.DeleteObject(menu);
1865 void wxFileHistory::Load(wxConfigBase& config)
1869 buf.Printf(_T("file%d"), m_fileHistoryN+1);
1870 wxString historyFile;
1871 while ((m_fileHistoryN <= m_fileMaxFiles) && config.Read(buf, &historyFile) && (historyFile != _T("")))
1873 m_fileHistory[m_fileHistoryN] = copystring((const wxChar*) historyFile);
1875 buf.Printf(_T("file%d"), m_fileHistoryN+1);
1881 void wxFileHistory::Save(wxConfigBase& config)
1884 for (i = 0; i < m_fileHistoryN; i++)
1887 buf.Printf(_T("file%d"), i+1);
1888 config.Write(buf, wxString(m_fileHistory[i]));
1891 #endif // wxUSE_CONFIG
1893 void wxFileHistory::AddFilesToMenu()
1895 if (m_fileHistoryN > 0)
1897 wxNode* node = m_fileMenus.First();
1900 wxMenu* menu = (wxMenu*) node->Data();
1901 menu->AppendSeparator();
1903 for (i = 0; i < m_fileHistoryN; i++)
1905 if (m_fileHistory[i])
1908 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
1909 menu->Append(wxID_FILE1+i, buf);
1912 node = node->Next();
1917 void wxFileHistory::AddFilesToMenu(wxMenu* menu)
1919 if (m_fileHistoryN > 0)
1921 menu->AppendSeparator();
1923 for (i = 0; i < m_fileHistoryN; i++)
1925 if (m_fileHistory[i])
1928 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
1929 menu->Append(wxID_FILE1+i, buf);
1935 // ----------------------------------------------------------------------------
1936 // Permits compatibility with existing file formats and functions that
1937 // manipulate files directly
1938 // ----------------------------------------------------------------------------
1940 bool wxTransferFileToStream(const wxString& filename, ostream& stream)
1945 if ((fd1 = fopen (filename.fn_str(), "rb")) == NULL)
1948 while ((ch = getc (fd1)) != EOF)
1949 stream << (unsigned char)ch;
1955 bool wxTransferStreamToFile(istream& stream, const wxString& filename)
1960 if ((fd1 = fopen (filename.fn_str(), "wb")) == NULL)
1965 while (!stream.eof())
1975 #endif // wxUSE_DOC_VIEW_ARCHITECTURE