1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Document/view classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "docview.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #if USE_DOC_VIEW_ARCHITECTURE
33 #include "wx/dialog.h"
36 #include "wx/filedlg.h"
43 #include "wx/msgdlg.h"
44 #include "wx/choicdlg.h"
45 #include "wx/docview.h"
46 #include "wx/printdlg.h"
47 #include "wx/generic/prntdlgg.h"
48 #include "wx/generic/printps.h"
61 #if !USE_SHARED_LIBRARY
62 IMPLEMENT_ABSTRACT_CLASS(wxDocument
, wxEvtHandler
)
63 IMPLEMENT_ABSTRACT_CLASS(wxView
, wxEvtHandler
)
64 IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate
, wxObject
)
65 IMPLEMENT_DYNAMIC_CLASS(wxDocManager
, wxEvtHandler
)
66 IMPLEMENT_CLASS(wxDocChildFrame
, wxFrame
)
67 IMPLEMENT_CLASS(wxDocParentFrame
, wxFrame
)
68 #if USE_PRINTING_ARCHITECTURE
69 IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout
, wxPrintout
)
71 IMPLEMENT_CLASS(wxCommand
, wxObject
)
72 IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor
, wxObject
)
73 IMPLEMENT_DYNAMIC_CLASS(wxFileHistory
, wxObject
)
74 // IMPLEMENT_DYNAMIC_CLASS(wxPrintInfo, wxObject)
78 * Definition of wxDocument
81 wxDocument::wxDocument(wxDocument
*parent
)
83 m_documentModified
=FALSE
;
86 m_documentParent
=parent
;
87 m_documentTemplate
= NULL
;
88 m_documentTypeName
= "";
92 bool wxDocument::DeleteContents(void)
97 wxDocument::~wxDocument(void)
101 if (m_commandProcessor
)
102 delete m_commandProcessor
;
104 GetDocumentManager()->RemoveDocument(this);
106 // Not safe to do here, since it'll
107 // invoke virtual view functions expecting to see
108 // valid derived objects: and by the time we get
109 // here, we've called destructors higher up.
113 bool wxDocument::Close(void)
115 if (OnSaveModified())
116 return OnCloseDocument();
121 bool wxDocument::OnCloseDocument(void)
128 // Note that this implicitly deletes the document when
129 // the last view is deleted.
130 bool wxDocument::DeleteAllViews(void)
132 wxNode
*node
= m_documentViews
.First();
135 wxView
*view
= (wxView
*)node
->Data();
139 wxNode
*next
= node
->Next();
141 delete view
; // Deletes node implicitly
147 wxView
*wxDocument::GetFirstView(void) const
149 if (m_documentViews
.Number() == 0)
151 return (wxView
*)m_documentViews
.First()->Data();
154 wxDocManager
*wxDocument::GetDocumentManager(void) const
156 return m_documentTemplate
->GetDocumentManager();
159 bool wxDocument::OnNewDocument(void)
161 if (!OnSaveModified())
164 if (OnCloseDocument()==FALSE
) return FALSE
;
167 SetDocumentSaved(FALSE
);
170 GetDocumentManager()->MakeDefaultName(name
);
172 SetFilename(name
, TRUE
);
177 bool wxDocument::Save(void)
181 if (!IsModified()) return TRUE
;
182 if (m_documentFile
== "" || !m_savedYet
)
185 ret
= OnSaveDocument(m_documentFile
);
187 SetDocumentSaved(TRUE
);
191 bool wxDocument::SaveAs(void)
193 wxDocTemplate
*docTemplate
= GetDocumentTemplate();
197 char *tmp
= wxFileSelector("Save as", docTemplate
->GetDirectory(), GetFilename(),
198 docTemplate
->GetDefaultExtension(), docTemplate
->GetFileFilter(),
199 wxSAVE
|wxOVERWRITE_PROMPT
, GetDocumentWindow());
205 wxString
fileName(tmp
);
209 wxSplitPath(fileName
, & path
, & name
, & ext
);
211 if (ext
.IsEmpty() || ext
== "")
214 fileName
+= docTemplate
->GetDefaultExtension();
217 SetFilename(fileName
);
218 SetTitle(wxFileNameFromPath(fileName
));
220 GetDocumentManager()->AddFileToHistory(fileName
);
222 // Notify the views that the filename has changed
223 wxNode
*node
= m_documentViews
.First();
226 wxView
*view
= (wxView
*)node
->Data();
227 view
->OnChangeFilename();
231 return OnSaveDocument(m_documentFile
);
234 bool wxDocument::OnSaveDocument(const wxString
& file
)
240 if (wxTheApp
->GetAppName() != "")
241 msgTitle
= wxTheApp
->GetAppName();
243 msgTitle
= wxString("File error");
245 ofstream
store(file
);
246 if (store
.fail() || store
.bad())
248 (void)wxMessageBox("Sorry, could not open this file for saving.", msgTitle
, wxOK
| wxICON_EXCLAMATION
,
249 GetDocumentWindow());
253 if (SaveObject(store
)==FALSE
)
255 (void)wxMessageBox("Sorry, could not save this file.", msgTitle
, wxOK
| wxICON_EXCLAMATION
,
256 GetDocumentWindow());
265 bool wxDocument::OnOpenDocument(const wxString
& file
)
267 if (!OnSaveModified())
271 if (wxTheApp
->GetAppName() != "")
272 msgTitle
= wxTheApp
->GetAppName();
274 msgTitle
= wxString("File error");
276 ifstream
store(file
);
277 if (store
.fail() || store
.bad())
279 (void)wxMessageBox("Sorry, could not open this file.", msgTitle
, wxOK
|wxICON_EXCLAMATION
,
280 GetDocumentWindow());
283 if (LoadObject(store
)==FALSE
)
285 (void)wxMessageBox("Sorry, could not open this file.", msgTitle
, wxOK
|wxICON_EXCLAMATION
,
286 GetDocumentWindow());
289 SetFilename(file
, TRUE
);
297 istream
& wxDocument::LoadObject(istream
& stream
)
299 // wxObject::LoadObject(stream);
304 ostream
& wxDocument::SaveObject(ostream
& stream
)
306 // wxObject::SaveObject(stream);
311 bool wxDocument::Revert(void)
317 // Get title, or filename if no title, else unnamed
318 bool wxDocument::GetPrintableName(wxString
& buf
) const
320 if (m_documentTitle
!= "")
322 buf
= m_documentTitle
;
325 else if (m_documentFile
!= "")
327 buf
= wxFileNameFromPath(m_documentFile
);
337 wxWindow
*wxDocument::GetDocumentWindow(void) const
339 wxView
*view
= GetFirstView();
341 return view
->GetFrame();
343 return wxTheApp
->GetTopWindow();
346 wxCommandProcessor
*wxDocument::OnCreateCommandProcessor(void)
348 return new wxCommandProcessor
;
351 // TRUE if safe to close
352 bool wxDocument::OnSaveModified(void)
358 GetPrintableName(title
);
361 if (wxTheApp
->GetAppName() != "")
362 msgTitle
= wxTheApp
->GetAppName();
364 msgTitle
= wxString("Warning");
366 sprintf(buf
, "Do you want to save changes to document %s?", (const char *)title
);
367 int res
= wxMessageBox(buf
, msgTitle
, wxYES_NO
|wxCANCEL
|wxICON_QUESTION
,
368 GetDocumentWindow());
374 else if (res
== wxYES
)
376 else if (res
== wxCANCEL
)
382 bool wxDocument::Draw(wxDC
& WXUNUSED(context
))
387 bool wxDocument::AddView(wxView
*view
)
389 if (!m_documentViews
.Member(view
))
391 m_documentViews
.Append(view
);
397 bool wxDocument::RemoveView(wxView
*view
)
399 (void)m_documentViews
.DeleteObject(view
);
404 bool wxDocument::OnCreate(const wxString
& WXUNUSED(path
), long flags
)
406 if (GetDocumentTemplate()->CreateView(this, flags
))
412 // Called after a view is added or removed.
413 // The default implementation deletes the document if
414 // there are no more views.
415 void wxDocument::OnChangedViewList(void)
417 if (m_documentViews
.Number() == 0)
419 if (OnSaveModified())
426 void wxDocument::UpdateAllViews(wxView
*sender
, wxObject
*hint
)
428 wxNode
*node
= m_documentViews
.First();
431 wxView
*view
= (wxView
*)node
->Data();
432 view
->OnUpdate(sender
, hint
);
437 void wxDocument::SetFilename(const wxString
& filename
, bool notifyViews
)
439 m_documentFile
= filename
;
442 // Notify the views that the filename has changed
443 wxNode
*node
= m_documentViews
.First();
446 wxView
*view
= (wxView
*)node
->Data();
447 view
->OnChangeFilename();
458 wxView::wxView(wxDocument
*doc
)
466 wxView::~wxView(void)
468 GetDocumentManager()->ActivateView(this, FALSE
, TRUE
);
469 m_viewDocument
->RemoveView(this);
472 // Extend event processing to search the document's event table
473 bool wxView::ProcessEvent(wxEvent
& event
)
475 if ( !GetDocument() || !GetDocument()->ProcessEvent(event
) )
476 return wxEvtHandler::ProcessEvent(event
);
481 void wxView::OnActivateView(bool WXUNUSED(activate
), wxView
*WXUNUSED(activeView
), wxView
*WXUNUSED(deactiveView
))
485 void wxView::OnPrint(wxDC
*dc
, wxObject
*WXUNUSED(info
))
490 void wxView::OnUpdate(wxView
*WXUNUSED(sender
), wxObject
*WXUNUSED(hint
))
494 void wxView::OnChangeFilename(void)
496 if (GetFrame() && GetDocument())
499 GetDocument()->GetPrintableName(name
);
501 GetFrame()->SetTitle(name
);
505 void wxView::SetDocument(wxDocument
*doc
)
507 m_viewDocument
= doc
;
512 bool wxView::Close(bool deleteWindow
)
514 if (OnClose(deleteWindow
))
520 void wxView::Activate(bool activate
)
522 if (GetDocumentManager())
524 OnActivateView(activate
, this, GetDocumentManager()->GetCurrentView());
525 GetDocumentManager()->ActivateView(this, activate
);
529 bool wxView::OnClose(bool WXUNUSED(deleteWindow
))
531 return GetDocument() ? GetDocument()->Close() : TRUE
;
534 #if USE_PRINTING_ARCHITECTURE
535 wxPrintout
*wxView::OnCreatePrintout(void)
537 return new wxDocPrintout(this);
546 wxDocTemplate::wxDocTemplate(wxDocManager
*manager
, const wxString
& descr
,
547 const wxString
& filter
, const wxString
& dir
, const wxString
& ext
,
548 const wxString
& docTypeName
, const wxString
& viewTypeName
,
549 wxClassInfo
*docClassInfo
, wxClassInfo
*viewClassInfo
, long flags
)
551 m_documentManager
= manager
;
553 m_description
= descr
;
556 m_fileFilter
= filter
;
558 m_docTypeName
= docTypeName
;
559 m_viewTypeName
= viewTypeName
;
560 m_documentManager
->AssociateTemplate(this);
562 m_docClassInfo
= docClassInfo
;
563 m_viewClassInfo
= viewClassInfo
;
566 wxDocTemplate::~wxDocTemplate(void)
568 m_documentManager
->DisassociateTemplate(this);
571 // Tries to dynamically construct an object of the right
573 wxDocument
*wxDocTemplate::CreateDocument(const wxString
& path
, long flags
)
577 wxDocument
*doc
= (wxDocument
*)m_docClassInfo
->CreateObject();
578 doc
->SetFilename(path
);
579 doc
->SetDocumentTemplate(this);
580 GetDocumentManager()->AddDocument(doc
);
581 doc
->SetCommandProcessor(doc
->OnCreateCommandProcessor());
583 if (doc
->OnCreate(path
, flags
))
592 wxView
*wxDocTemplate::CreateView(wxDocument
*doc
, long flags
)
594 if (!m_viewClassInfo
)
596 wxView
*view
= (wxView
*)m_viewClassInfo
->CreateObject();
597 view
->SetDocument(doc
);
598 if (view
->OnCreate(doc
, flags
))
609 BEGIN_EVENT_TABLE(wxDocManager
, wxEvtHandler
)
610 EVT_MENU(wxID_OPEN
, wxDocManager::OnFileOpen
)
611 EVT_MENU(wxID_CLOSE
, wxDocManager::OnFileClose
)
612 EVT_MENU(wxID_REVERT
, wxDocManager::OnFileRevert
)
613 EVT_MENU(wxID_NEW
, wxDocManager::OnFileNew
)
614 EVT_MENU(wxID_SAVE
, wxDocManager::OnFileSave
)
615 EVT_MENU(wxID_SAVEAS
, wxDocManager::OnFileSaveAs
)
616 EVT_MENU(wxID_UNDO
, wxDocManager::OnUndo
)
617 EVT_MENU(wxID_REDO
, wxDocManager::OnRedo
)
618 EVT_MENU(wxID_PRINT
, wxDocManager::OnPrint
)
619 EVT_MENU(wxID_PRINT_SETUP
, wxDocManager::OnPrintSetup
)
620 EVT_MENU(wxID_PREVIEW
, wxDocManager::OnPreview
)
623 wxDocManager::wxDocManager(long flags
, bool initialize
)
625 m_defaultDocumentNameCounter
= 1;
627 m_currentView
= NULL
;
628 m_maxDocsOpen
= 10000;
629 m_fileHistory
= NULL
;
634 wxDocManager::~wxDocManager(void)
638 delete m_fileHistory
;
641 bool wxDocManager::Clear(bool force
)
643 wxNode
*node
= m_docs
.First();
646 wxDocument
*doc
= (wxDocument
*)node
->Data();
647 wxNode
*next
= node
->Next();
649 if (!doc
->Close() && !force
)
652 // Implicitly deletes the document when the last
653 // view is removed (deleted)
654 doc
->DeleteAllViews();
656 // Check document is deleted
657 if (m_docs
.Member(doc
))
660 // This assumes that documents are not connected in
661 // any way, i.e. deleting one document does NOT
665 node
= m_templates
.First();
668 wxDocTemplate
*templ
= (wxDocTemplate
*) node
->Data();
669 wxNode
* next
= node
->Next();
676 bool wxDocManager::Initialize(void)
678 m_fileHistory
= OnCreateFileHistory();
682 wxFileHistory
*wxDocManager::OnCreateFileHistory(void)
684 return new wxFileHistory
;
687 void wxDocManager::OnFileClose(wxCommandEvent
& WXUNUSED(event
))
689 wxDocument
*doc
= GetCurrentDocument();
694 doc
->DeleteAllViews();
695 if (m_docs
.Member(doc
))
700 void wxDocManager::OnFileNew(wxCommandEvent
& WXUNUSED(event
))
702 CreateDocument(wxString(""), wxDOC_NEW
);
705 void wxDocManager::OnFileOpen(wxCommandEvent
& WXUNUSED(event
))
707 CreateDocument(wxString(""), 0);
710 void wxDocManager::OnFileRevert(wxCommandEvent
& WXUNUSED(event
))
712 wxDocument
*doc
= GetCurrentDocument();
718 void wxDocManager::OnFileSave(wxCommandEvent
& WXUNUSED(event
))
720 wxDocument
*doc
= GetCurrentDocument();
726 void wxDocManager::OnFileSaveAs(wxCommandEvent
& WXUNUSED(event
))
728 wxDocument
*doc
= GetCurrentDocument();
734 void wxDocManager::OnPrint(wxCommandEvent
& WXUNUSED(event
))
736 wxView
*view
= GetCurrentView();
740 wxPrintout
*printout
= view
->OnCreatePrintout();
743 // TODO: trouble about this is that it pulls in the postscript
746 if ( wxTheApp
->GetPrintMode() == wxPRINT_WINDOWS
)
748 wxWindowsPrinter printer
;
749 printer
.Print(view
->GetFrame(), printout
, TRUE
);
754 wxPostScriptPrinter printer
;
755 printer
.Print(view
->GetFrame(), printout
, TRUE
);
762 void wxDocManager::OnPrintSetup(wxCommandEvent
& WXUNUSED(event
))
764 wxWindow
*parentWin
= wxTheApp
->GetTopWindow();
765 wxView
*view
= GetCurrentView();
767 parentWin
= view
->GetFrame();
772 if ( wxTheApp
->GetPrintMode() == wxPRINT_WINDOWS
)
774 wxPrintDialog
printerDialog(parentWin
, & data
);
775 printerDialog
.GetPrintData().SetSetupDialog(TRUE
);
776 printerDialog
.ShowModal();
781 wxGenericPrintDialog
printerDialog(parentWin
, & data
);
782 printerDialog
.GetPrintData().SetSetupDialog(TRUE
);
783 printerDialog
.ShowModal();
787 void wxDocManager::OnPreview(wxCommandEvent
& WXUNUSED(event
))
789 wxView
*view
= GetCurrentView();
793 wxPrintout
*printout
= view
->OnCreatePrintout();
796 // Pass two printout objects: for preview, and possible printing.
797 wxPrintPreviewBase
*preview
= NULL
;
799 if ( wxTheApp
->GetPrintMode() == wxPRINT_WINDOWS
)
800 preview
= new wxWindowsPrintPreview(printout
, view
->OnCreatePrintout());
803 preview
= new wxPostScriptPrintPreview(printout
, view
->OnCreatePrintout());
805 wxPreviewFrame
*frame
= new wxPreviewFrame(preview
, (wxFrame
*)wxTheApp
->GetTopWindow(), "Print Preview",
806 wxPoint(100, 100), wxSize(600, 650));
807 frame
->Centre(wxBOTH
);
813 void wxDocManager::OnUndo(wxCommandEvent
& WXUNUSED(event
))
815 wxDocument
*doc
= GetCurrentDocument();
818 if (doc
->GetCommandProcessor())
819 doc
->GetCommandProcessor()->Undo();
822 void wxDocManager::OnRedo(wxCommandEvent
& WXUNUSED(event
))
824 wxDocument
*doc
= GetCurrentDocument();
827 if (doc
->GetCommandProcessor())
828 doc
->GetCommandProcessor()->Redo();
831 wxView
*wxDocManager::GetCurrentView(void) const
834 return m_currentView
;
835 if (m_docs
.Number() == 1)
837 wxDocument
* doc
= (wxDocument
*) m_docs
.First()->Data();
838 return doc
->GetFirstView();
843 // Extend event processing to search the view's event table
844 bool wxDocManager::ProcessEvent(wxEvent
& event
)
846 wxView
* view
= GetCurrentView();
849 if (view
->ProcessEvent(event
))
852 return wxEvtHandler::ProcessEvent(event
);
855 wxDocument
*wxDocManager::CreateDocument(const wxString
& path
, long flags
)
857 wxDocTemplate
**templates
= new wxDocTemplate
*[m_templates
.Number()];
860 for (i
= 0; i
< m_templates
.Number(); i
++)
862 wxDocTemplate
*temp
= (wxDocTemplate
*)(m_templates
.Nth(i
)->Data());
863 if (temp
->IsVisible())
875 // If we've reached the max number of docs, close the
877 if (GetDocuments().Number() >= m_maxDocsOpen
)
879 wxDocument
*doc
= (wxDocument
*)GetDocuments().First()->Data();
882 // Implicitly deletes the document when
883 // the last view is deleted
884 doc
->DeleteAllViews();
886 // Check we're really deleted
887 if (m_docs
.Member(doc
))
894 // New document: user chooses a template, unless there's only one.
895 if (flags
& wxDOC_NEW
)
899 wxDocTemplate
*temp
= templates
[0];
901 wxDocument
*newDoc
= temp
->CreateDocument(path
, flags
);
904 newDoc
->SetDocumentName(temp
->GetDocumentName());
905 newDoc
->SetDocumentTemplate(temp
);
906 newDoc
->OnNewDocument();
911 wxDocTemplate
*temp
= SelectDocumentType(templates
, n
);
915 wxDocument
*newDoc
= temp
->CreateDocument(path
, flags
);
918 newDoc
->SetDocumentName(temp
->GetDocumentName());
919 newDoc
->SetDocumentTemplate(temp
);
920 newDoc
->OnNewDocument();
929 wxDocTemplate
*temp
= NULL
;
935 if (flags
& wxDOC_SILENT
)
936 temp
= FindTemplateForPath(path2
);
938 temp
= SelectDocumentPath(templates
, n
, path2
, flags
);
944 wxDocument
*newDoc
= temp
->CreateDocument(path2
, flags
);
947 newDoc
->SetDocumentName(temp
->GetDocumentName());
948 newDoc
->SetDocumentTemplate(temp
);
949 if (!newDoc
->OnOpenDocument(path2
))
954 AddFileToHistory(path2
);
962 wxView
*wxDocManager::CreateView(wxDocument
*doc
, long flags
)
964 wxDocTemplate
**templates
= new wxDocTemplate
*[m_templates
.Number()];
967 for (i
= 0; i
< m_templates
.Number(); i
++)
969 wxDocTemplate
*temp
= (wxDocTemplate
*)(m_templates
.Nth(i
)->Data());
970 if (temp
->IsVisible())
972 if (temp
->GetDocumentName() == doc
->GetDocumentName())
986 wxDocTemplate
*temp
= templates
[0];
988 wxView
*view
= temp
->CreateView(doc
, flags
);
990 view
->SetViewName(temp
->GetViewName());
994 wxDocTemplate
*temp
= SelectViewType(templates
, n
);
998 wxView
*view
= temp
->CreateView(doc
, flags
);
1000 view
->SetViewName(temp
->GetViewName());
1007 // Not yet implemented
1008 void wxDocManager::DeleteTemplate(wxDocTemplate
*WXUNUSED(temp
), long WXUNUSED(flags
))
1012 // Not yet implemented
1013 bool wxDocManager::FlushDoc(wxDocument
*WXUNUSED(doc
))
1018 wxDocument
*wxDocManager::GetCurrentDocument(void) const
1021 return m_currentView
->GetDocument();
1026 // Make a default document name
1027 bool wxDocManager::MakeDefaultName(wxString
& name
)
1030 sprintf(buf
, "unnamed%d", m_defaultDocumentNameCounter
);
1031 m_defaultDocumentNameCounter
++;
1036 // Not yet implemented
1037 wxDocTemplate
*wxDocManager::MatchTemplate(const wxString
& WXUNUSED(path
))
1042 // File history management
1043 void wxDocManager::AddFileToHistory(const wxString
& file
)
1046 m_fileHistory
->AddFileToHistory(file
);
1049 wxString
wxDocManager::GetHistoryFile(int i
) const
1052 return wxString(m_fileHistory
->GetHistoryFile(i
));
1054 return wxString("");
1057 void wxDocManager::FileHistoryUseMenu(wxMenu
*menu
)
1060 m_fileHistory
->FileHistoryUseMenu(menu
);
1063 void wxDocManager::FileHistoryLoad(const wxString
& resourceFile
, const wxString
& section
)
1066 m_fileHistory
->FileHistoryLoad(resourceFile
, section
);
1069 void wxDocManager::FileHistorySave(const wxString
& resourceFile
, const wxString
& section
)
1072 m_fileHistory
->FileHistorySave(resourceFile
, section
);
1075 int wxDocManager::GetNoHistoryFiles(void) const
1078 return m_fileHistory
->GetNoHistoryFiles();
1083 static char *FindExtension(char *path
)
1085 static char ext
[10];
1086 int len
= strlen(path
);
1090 for (i
= (len
-1); i
> 0; i
--)
1096 for (j
= i
+1; j
< len
; j
++)
1097 ext
[(int)(j
-(i
+1))] = (char)wxToLower(path
[j
]); // NOTE Should not use tolower under UNIX
1108 // Given a path, try to find a matching template. Won't
1109 // always work, of course.
1110 wxDocTemplate
*wxDocManager::FindTemplateForPath(const wxString
& path
)
1112 char *theExt
= FindExtension((char *)(const char *)path
);
1115 wxDocTemplate
*theTemplate
= NULL
;
1117 if (m_templates
.Number() == 1)
1118 return (wxDocTemplate
*)m_templates
.First()->Data();
1120 // Find the template which this extension corresponds to
1122 for (i
= 0; i
< m_templates
.Number(); i
++)
1124 wxDocTemplate
*temp
= (wxDocTemplate
*)m_templates
.Nth(i
)->Data();
1125 if (strcmp(temp
->GetDefaultExtension(), theExt
) == 0)
1134 // Prompts user to open a file, using file specs in templates.
1135 // How to implement in wxWindows? Must extend the file selector
1136 // dialog or implement own; OR match the extension to the
1137 // template extension.
1138 wxDocTemplate
*wxDocManager::SelectDocumentPath(wxDocTemplate
**templates
,
1139 int noTemplates
, wxString
& path
, long WXUNUSED(flags
), bool WXUNUSED(save
))
1141 // We can only have multiple filters in Windows
1143 char *descrBuf
= new char[1000];
1146 for (i
= 0; i
< noTemplates
; i
++)
1148 if (templates
[i
]->IsVisible())
1150 strcat(descrBuf
, templates
[i
]->GetDescription());
1151 strcat(descrBuf
, " (");
1152 strcat(descrBuf
, templates
[i
]->GetFileFilter());
1153 strcat(descrBuf
, ") ");
1154 strcat(descrBuf
, "|");
1155 strcat(descrBuf
, templates
[i
]->GetFileFilter());
1156 strcat(descrBuf
, "|");
1159 int len
= strlen(descrBuf
);
1162 descrBuf
[len
-1] = 0;
1164 char *pathTmp
= wxFileSelector("Select a file", "", "", "", descrBuf
, 0, wxTheApp
->GetTopWindow());
1169 char *theExt
= FindExtension((char *)(const char *)path
);
1173 // This is dodgy in that we're selecting the template on the
1174 // basis of the file extension, which may not be a standard
1175 // one. We really want to know exactly which template was
1176 // chosen by using a more advanced file selector.
1177 wxDocTemplate
*theTemplate
= FindTemplateForPath(path
);
1186 // In all other windowing systems, until we have more advanced
1187 // file selectors, we must select the document type (template) first, and
1188 // _then_ pop up the file selector.
1189 wxDocTemplate
*temp
= SelectDocumentType(templates
, noTemplates
);
1193 char *pathTmp
= wxFileSelector("Select a file", "", "",
1194 temp
->GetDefaultExtension(),
1195 temp
->GetFileFilter(),
1196 0, wxTheApp
->GetTopWindow());
1208 wxDocTemplate
*wxDocManager::SelectDocumentType(wxDocTemplate
**templates
,
1211 char **strings
= new char *[noTemplates
];
1212 char **data
= new char *[noTemplates
];
1215 for (i
= 0; i
< noTemplates
; i
++)
1217 if (templates
[i
]->IsVisible())
1219 strings
[n
] = WXSTRINGCAST templates
[i
]->m_description
;
1220 data
[n
] = (char *)templates
[i
];
1232 wxDocTemplate
*temp
= (wxDocTemplate
*)data
[0];
1238 wxDocTemplate
*theTemplate
= (wxDocTemplate
*)wxGetSingleChoiceData("Select a document template", "Templates", n
,
1245 wxDocTemplate
*wxDocManager::SelectViewType(wxDocTemplate
**templates
,
1248 char **strings
= new char *[noTemplates
];
1249 char **data
= new char *[noTemplates
];
1252 for (i
= 0; i
< noTemplates
; i
++)
1254 if (templates
[i
]->IsVisible() && templates
[i
]->GetViewName())
1256 strings
[n
] = WXSTRINGCAST templates
[i
]->m_viewTypeName
;
1257 data
[n
] = (char *)templates
[i
];
1261 wxDocTemplate
*theTemplate
= (wxDocTemplate
*)wxGetSingleChoiceData("Select a document view", "Views", n
,
1268 void wxDocManager::AssociateTemplate(wxDocTemplate
*temp
)
1270 if (!m_templates
.Member(temp
))
1271 m_templates
.Append(temp
);
1274 void wxDocManager::DisassociateTemplate(wxDocTemplate
*temp
)
1276 m_templates
.DeleteObject(temp
);
1279 // Add and remove a document from the manager's list
1280 void wxDocManager::AddDocument(wxDocument
*doc
)
1282 if (!m_docs
.Member(doc
))
1286 void wxDocManager::RemoveDocument(wxDocument
*doc
)
1288 m_docs
.DeleteObject(doc
);
1291 // Views or windows should inform the document manager
1292 // when a view is going in or out of focus
1293 void wxDocManager::ActivateView(wxView
*view
, bool activate
, bool WXUNUSED(deleting
))
1295 // If we're deactiving, and if we're not actually deleting the view, then
1296 // don't reset the current view because we may be going to
1297 // a window without a view.
1298 // WHAT DID I MEAN BY THAT EXACTLY?
1302 if (m_currentView == view)
1303 m_currentView = NULL;
1309 m_currentView
= view
;
1311 m_currentView
= NULL
;
1316 * Default document child frame
1319 BEGIN_EVENT_TABLE(wxDocChildFrame
, wxFrame
)
1320 EVT_ACTIVATE(wxDocChildFrame::OnActivate
)
1323 wxDocChildFrame::wxDocChildFrame(wxDocument
*doc
, wxView
*view
, wxFrame
*frame
, wxWindowID id
, const wxString
& title
,
1324 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
):
1325 wxFrame(frame
, id
, title
, pos
, size
, style
, name
)
1327 m_childDocument
= doc
;
1330 view
->SetFrame(this);
1333 wxDocChildFrame::~wxDocChildFrame(void)
1337 // Extend event processing to search the view's event table
1338 bool wxDocChildFrame::ProcessEvent(wxEvent
& event
)
1341 m_childView
->Activate(TRUE
);
1343 if ( !m_childView
|| ! m_childView
->ProcessEvent(event
) )
1345 // Only hand up to the parent if it's a menu command
1346 if (!event
.IsKindOf(CLASSINFO(wxCommandEvent
)) || !GetParent() || !GetParent()->ProcessEvent(event
))
1347 return wxEvtHandler::ProcessEvent(event
);
1355 void wxDocChildFrame::OnActivate(wxActivateEvent
& event
)
1357 wxFrame::OnActivate(event
);
1360 m_childView
->Activate(event
.GetActive());
1363 bool wxDocChildFrame::OnClose(void)
1365 // Close view but don't delete the frame while doing so!
1366 // ...since it will be deleted by wxWindows if we return TRUE.
1369 bool ans
= m_childView
->Close(FALSE
); // FALSE means don't delete associated window
1372 m_childView
->Activate(FALSE
);
1375 m_childDocument
= NULL
;
1384 * Default parent frame
1387 BEGIN_EVENT_TABLE(wxDocParentFrame
, wxFrame
)
1388 EVT_MENU(wxID_EXIT
, wxDocParentFrame::OnExit
)
1389 EVT_MENU_RANGE(wxID_FILE1
, wxID_FILE9
, wxDocParentFrame::OnMRUFile
)
1392 wxDocParentFrame::wxDocParentFrame(wxDocManager
*manager
, wxFrame
*frame
, wxWindowID id
, const wxString
& title
,
1393 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
):
1394 wxFrame(frame
, id
, title
, pos
, size
, style
, name
)
1396 m_docManager
= manager
;
1399 void wxDocParentFrame::OnExit(wxCommandEvent
& WXUNUSED(event
))
1404 void wxDocParentFrame::OnMRUFile(wxCommandEvent
& event
)
1406 wxString
f(m_docManager
->GetHistoryFile(event
.GetSelection() - wxID_FILE1
));
1408 (void)m_docManager
->CreateDocument(f
, wxDOC_SILENT
);
1411 // Extend event processing to search the view's event table
1412 bool wxDocParentFrame::ProcessEvent(wxEvent
& event
)
1414 // Try the document manager, then do default processing
1415 if (!m_docManager
|| !m_docManager
->ProcessEvent(event
))
1416 return wxEvtHandler::ProcessEvent(event
);
1421 // Define the behaviour for the frame closing
1422 // - must delete all frames except for the main one.
1423 bool wxDocParentFrame::OnClose(void)
1425 return m_docManager
->Clear(FALSE
);
1428 #if USE_PRINTING_ARCHITECTURE
1430 wxDocPrintout::wxDocPrintout(wxView
*view
, const wxString
& title
):
1431 wxPrintout(WXSTRINGCAST title
)
1433 m_printoutView
= view
;
1436 bool wxDocPrintout::OnPrintPage(int WXUNUSED(page
))
1440 // Get the logical pixels per inch of screen and printer
1441 int ppiScreenX
, ppiScreenY
;
1442 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
1443 int ppiPrinterX
, ppiPrinterY
;
1444 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
1446 // This scales the DC so that the printout roughly represents the
1447 // the screen scaling. The text point size _should_ be the right size
1448 // but in fact is too small for some reason. This is a detail that will
1449 // need to be addressed at some point but can be fudged for the
1451 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
1453 // Now we have to check in case our real page size is reduced
1454 // (e.g. because we're drawing to a print preview memory DC)
1455 int pageWidth
, pageHeight
;
1457 dc
->GetSize(&w
, &h
);
1458 GetPageSizePixels(&pageWidth
, &pageHeight
);
1460 // If printer pageWidth == current DC width, then this doesn't
1461 // change. But w might be the preview bitmap width, so scale down.
1462 float overallScale
= scale
* (float)(w
/(float)pageWidth
);
1463 dc
->SetUserScale(overallScale
, overallScale
);
1467 m_printoutView
->OnDraw(dc
);
1472 bool wxDocPrintout::HasPage(int pageNum
)
1474 return (pageNum
== 1);
1477 bool wxDocPrintout::OnBeginDocument(int startPage
, int endPage
)
1479 if (!wxPrintout::OnBeginDocument(startPage
, endPage
))
1485 void wxDocPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1496 * Command processing framework
1499 wxCommand::wxCommand(bool canUndoIt
, const wxString
& name
)
1501 m_canUndo
= canUndoIt
;
1502 m_commandName
= name
;
1505 wxCommand::~wxCommand(void)
1509 // Command processor
1510 wxCommandProcessor::wxCommandProcessor(int maxCommands
)
1512 m_maxNoCommands
= maxCommands
;
1513 m_currentCommand
= NULL
;
1514 m_commandEditMenu
= NULL
;
1517 wxCommandProcessor::~wxCommandProcessor(void)
1522 // Pass a command to the processor. The processor calls Do();
1523 // if successful, is appended to the command history unless
1524 // storeIt is FALSE.
1525 bool wxCommandProcessor::Submit(wxCommand
*command
, bool storeIt
)
1527 bool success
= command
->Do();
1528 if (success
&& storeIt
)
1530 if (m_commands
.Number() == m_maxNoCommands
)
1532 wxNode
*firstNode
= m_commands
.First();
1533 wxCommand
*firstCommand
= (wxCommand
*)firstNode
->Data();
1534 delete firstCommand
;
1538 // Correct a bug: we must chop off the current 'branch'
1539 // so that we're at the end of the command list.
1540 if (!m_currentCommand
)
1544 wxNode
*node
= m_currentCommand
->Next();
1547 wxNode
*next
= node
->Next();
1548 delete (wxCommand
*)node
->Data();
1554 m_commands
.Append(command
);
1555 m_currentCommand
= m_commands
.Last();
1561 bool wxCommandProcessor::Undo(void)
1563 if (m_currentCommand
)
1565 wxCommand
*command
= (wxCommand
*)m_currentCommand
->Data();
1566 if (command
->CanUndo())
1568 bool success
= command
->Undo();
1571 m_currentCommand
= m_currentCommand
->Previous();
1580 bool wxCommandProcessor::Redo(void)
1582 wxCommand
*redoCommand
= NULL
;
1583 wxNode
*redoNode
= NULL
;
1584 if (m_currentCommand
&& m_currentCommand
->Next())
1586 redoCommand
= (wxCommand
*)m_currentCommand
->Next()->Data();
1587 redoNode
= m_currentCommand
->Next();
1591 if (m_commands
.Number() > 0)
1593 redoCommand
= (wxCommand
*)m_commands
.First()->Data();
1594 redoNode
= m_commands
.First();
1600 bool success
= redoCommand
->Do();
1603 m_currentCommand
= redoNode
;
1611 bool wxCommandProcessor::CanUndo(void)
1613 if (m_currentCommand
)
1614 return ((wxCommand
*)m_currentCommand
->Data())->CanUndo();
1618 void wxCommandProcessor::Initialize(void)
1620 m_currentCommand
= m_commands
.Last();
1624 void wxCommandProcessor::SetMenuStrings(void)
1626 if (m_commandEditMenu
)
1629 if (m_currentCommand
)
1631 wxCommand
*command
= (wxCommand
*)m_currentCommand
->Data();
1632 wxString
commandName(command
->GetName());
1633 if (commandName
== "") commandName
= "Unnamed command";
1634 bool canUndo
= command
->CanUndo();
1636 buf
= wxString("&Undo ") + commandName
;
1638 buf
= wxString("Can't &Undo ") + commandName
;
1640 m_commandEditMenu
->SetLabel(wxID_UNDO
, buf
);
1641 m_commandEditMenu
->Enable(wxID_UNDO
, canUndo
);
1643 // We can redo, if we're not at the end of the history.
1644 if (m_currentCommand
->Next())
1646 wxCommand
*redoCommand
= (wxCommand
*)m_currentCommand
->Next()->Data();
1647 wxString
redoCommandName(redoCommand
->GetName());
1648 if (redoCommandName
== "") redoCommandName
= "Unnamed command";
1649 buf
= wxString("&Redo ") + redoCommandName
;
1650 m_commandEditMenu
->SetLabel(wxID_REDO
, buf
);
1651 m_commandEditMenu
->Enable(wxID_REDO
, TRUE
);
1655 m_commandEditMenu
->SetLabel(wxID_REDO
, "&Redo");
1656 m_commandEditMenu
->Enable(wxID_REDO
, FALSE
);
1661 m_commandEditMenu
->SetLabel(wxID_UNDO
, "&Undo");
1662 m_commandEditMenu
->Enable(wxID_UNDO
, FALSE
);
1664 if (m_commands
.Number() == 0)
1666 m_commandEditMenu
->SetLabel(wxID_REDO
, "&Redo");
1667 m_commandEditMenu
->Enable(wxID_REDO
, FALSE
);
1671 // currentCommand is NULL but there are commands: this means that
1672 // we've undone to the start of the list, but can redo the first.
1673 wxCommand
*redoCommand
= (wxCommand
*)m_commands
.First()->Data();
1674 wxString
redoCommandName(redoCommand
->GetName());
1675 if (!redoCommandName
) redoCommandName
= "Unnamed command";
1676 buf
= wxString("&Redo ") + redoCommandName
;
1677 m_commandEditMenu
->SetLabel(wxID_REDO
, buf
);
1678 m_commandEditMenu
->Enable(wxID_REDO
, TRUE
);
1684 void wxCommandProcessor::ClearCommands(void)
1686 wxNode
*node
= m_commands
.First();
1689 wxCommand
*command
= (wxCommand
*)node
->Data();
1692 node
= m_commands
.First();
1694 m_currentCommand
= NULL
;
1699 * File history processor
1702 wxFileHistory::wxFileHistory(int maxFiles
)
1704 m_fileMaxFiles
= maxFiles
;
1707 m_fileHistory
= new char *[m_fileMaxFiles
];
1710 wxFileHistory::~wxFileHistory(void)
1713 for (i
= 0; i
< m_fileHistoryN
; i
++)
1714 delete[] m_fileHistory
[i
];
1715 delete[] m_fileHistory
;
1718 // File history management
1719 void wxFileHistory::AddFileToHistory(const wxString
& file
)
1726 // Check we don't already have this file
1727 for (i
= 0; i
< m_fileHistoryN
; i
++)
1729 if (m_fileHistory
[i
] && wxString(m_fileHistory
[i
]) == file
)
1733 // Add to the project file history:
1734 // Move existing files (if any) down so we can insert file at beginning.
1736 // First delete filename that has popped off the end of the array (if any)
1737 if (m_fileHistoryN
== m_fileMaxFiles
)
1739 delete[] m_fileHistory
[m_fileMaxFiles
-1];
1740 m_fileHistory
[m_fileMaxFiles
-1] = NULL
;
1742 if (m_fileHistoryN
< m_fileMaxFiles
)
1744 if (m_fileHistoryN
== 0)
1745 m_fileMenu
->AppendSeparator();
1746 m_fileMenu
->Append(wxID_FILE1
+m_fileHistoryN
, "[EMPTY]");
1749 // Shuffle filenames down
1750 for (i
= (m_fileHistoryN
-1); i
> 0; i
--)
1752 m_fileHistory
[i
] = m_fileHistory
[i
-1];
1754 m_fileHistory
[0] = copystring(file
);
1756 for (i
= 0; i
< m_fileHistoryN
; i
++)
1757 if (m_fileHistory
[i
])
1760 sprintf(buf
, "&%d %s", i
+1, m_fileHistory
[i
]);
1761 m_fileMenu
->SetLabel(wxID_FILE1
+i
, buf
);
1765 wxString
wxFileHistory::GetHistoryFile(int i
) const
1767 if (i
< m_fileHistoryN
)
1768 return wxString(m_fileHistory
[i
]);
1770 return wxString("");
1773 void wxFileHistory::FileHistoryUseMenu(wxMenu
*menu
)
1778 void wxFileHistory::FileHistoryLoad(const wxString
& resourceFile
, const wxString
& section
)
1783 sprintf(buf
, "file%d", m_fileHistoryN
+1);
1784 char *historyFile
= NULL
;
1785 while ((m_fileHistoryN
<= m_fileMaxFiles
) && wxGetResource(section
, buf
, &historyFile
, resourceFile
) && historyFile
)
1787 // wxGetResource allocates memory so this is o.k.
1788 m_fileHistory
[m_fileHistoryN
] = historyFile
;
1790 sprintf(buf
, "file%d", m_fileHistoryN
+1);
1796 void wxFileHistory::FileHistorySave(const wxString
& resourceFile
, const wxString
& section
)
1801 for (i
= 0; i
< m_fileHistoryN
; i
++)
1803 sprintf(buf
, "file%d", i
+1);
1804 wxWriteResource(section
, buf
, m_fileHistory
[i
], resourceFile
);
1814 wxPrintInfo::wxPrintInfo(void)
1819 wxPrintInfo::~wxPrintInfo(void)
1825 * Permits compatibility with existing file formats and functions
1826 * that manipulate files directly
1829 bool wxTransferFileToStream(const wxString
& filename
, ostream
& stream
)
1834 if ((fd1
= fopen (WXSTRINGCAST filename
, "rb")) == NULL
)
1837 while ((ch
= getc (fd1
)) != EOF
)
1838 stream
<< (unsigned char)ch
;
1844 bool wxTransferStreamToFile(istream
& stream
, const wxString
& filename
)
1849 if ((fd1
= fopen (WXSTRINGCAST filename
, "wb")) == NULL
)
1854 while (!stream
.eof())
1865 // End USE_DOC_VIEW_ARCHITECTURE