Various bug fixes to OGL; wxStripExtension prototype added to filefn.h
[wxWidgets.git] / src / common / docview.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: docview.cpp
3 // Purpose: Document/view classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "docview.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/defs.h"
25 #endif
26
27 #if USE_DOC_VIEW_ARCHITECTURE
28
29 #ifndef WX_PRECOMP
30 #include "wx/utils.h"
31 #include "wx/app.h"
32 #include "wx/dc.h"
33 #include "wx/dialog.h"
34 #include "wx/menu.h"
35 #include "wx/list.h"
36 #include "wx/filedlg.h"
37 #endif
38
39 #ifdef __WXGTK__
40 #include "wx/mdi.h"
41 #endif
42
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"
49
50 #include <stdio.h>
51 #include <string.h>
52
53 #if USE_IOSTREAMH
54 #include <iostream.h>
55 #else
56 #include <iostream>
57 #endif
58
59 #include "fstream.h"
60
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)
70 #endif
71 IMPLEMENT_CLASS(wxCommand, wxObject)
72 IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject)
73 IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
74 // IMPLEMENT_DYNAMIC_CLASS(wxPrintInfo, wxObject)
75 #endif
76
77 /*
78 * Definition of wxDocument
79 */
80
81 wxDocument::wxDocument(wxDocument *parent)
82 {
83 m_documentModified=FALSE;
84 m_documentFile="";
85 m_documentTitle="";
86 m_documentParent=parent;
87 m_documentTemplate = NULL;
88 m_documentTypeName = "";
89 m_savedYet = FALSE;
90 }
91
92 bool wxDocument::DeleteContents(void)
93 {
94 return TRUE;
95 }
96
97 wxDocument::~wxDocument(void)
98 {
99 DeleteContents();
100
101 if (m_commandProcessor)
102 delete m_commandProcessor;
103
104 GetDocumentManager()->RemoveDocument(this);
105
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.
110 // DeleteAllViews();
111 }
112
113 bool wxDocument::Close(void)
114 {
115 if (OnSaveModified())
116 return OnCloseDocument();
117 else
118 return FALSE;
119 }
120
121 bool wxDocument::OnCloseDocument(void)
122 {
123 DeleteContents();
124 Modify(FALSE);
125 return TRUE;
126 }
127
128 // Note that this implicitly deletes the document when
129 // the last view is deleted.
130 bool wxDocument::DeleteAllViews(void)
131 {
132 wxNode *node = m_documentViews.First();
133 while (node)
134 {
135 wxView *view = (wxView *)node->Data();
136 if (!view->Close())
137 return FALSE;
138
139 wxNode *next = node->Next();
140
141 delete view; // Deletes node implicitly
142 node = next;
143 }
144 return TRUE;
145 }
146
147 wxView *wxDocument::GetFirstView(void) const
148 {
149 if (m_documentViews.Number() == 0)
150 return NULL;
151 return (wxView *)m_documentViews.First()->Data();
152 }
153
154 wxDocManager *wxDocument::GetDocumentManager(void) const
155 {
156 return m_documentTemplate->GetDocumentManager();
157 }
158
159 bool wxDocument::OnNewDocument(void)
160 {
161 if (!OnSaveModified())
162 return FALSE;
163
164 if (OnCloseDocument()==FALSE) return FALSE;
165 DeleteContents();
166 Modify(FALSE);
167 SetDocumentSaved(FALSE);
168
169 wxString name;
170 GetDocumentManager()->MakeDefaultName(name);
171 SetTitle(name);
172 SetFilename(name, TRUE);
173
174 return TRUE;
175 }
176
177 bool wxDocument::Save(void)
178 {
179 bool ret = FALSE;
180
181 if (!IsModified()) return TRUE;
182 if (m_documentFile == "" || !m_savedYet)
183 ret = SaveAs();
184 else
185 ret = OnSaveDocument(m_documentFile);
186 if ( ret )
187 SetDocumentSaved(TRUE);
188 return ret;
189 }
190
191 bool wxDocument::SaveAs(void)
192 {
193 wxDocTemplate *docTemplate = GetDocumentTemplate();
194 if (!docTemplate)
195 return FALSE;
196
197 char *tmp = wxFileSelector("Save as", docTemplate->GetDirectory(), GetFilename(),
198 docTemplate->GetDefaultExtension(), docTemplate->GetFileFilter(),
199 wxSAVE|wxOVERWRITE_PROMPT, GetDocumentWindow());
200
201 if (!tmp)
202 return FALSE;
203 else
204 {
205 wxString fileName(tmp);
206 wxString path("");
207 wxString name("");
208 wxString ext("");
209 wxSplitPath(fileName, & path, & name, & ext);
210
211 if (ext.IsEmpty() || ext == "")
212 {
213 fileName += ".";
214 fileName += docTemplate->GetDefaultExtension();
215 }
216
217 SetFilename(fileName);
218 SetTitle(wxFileNameFromPath(fileName));
219
220 GetDocumentManager()->AddFileToHistory(fileName);
221
222 // Notify the views that the filename has changed
223 wxNode *node = m_documentViews.First();
224 while (node)
225 {
226 wxView *view = (wxView *)node->Data();
227 view->OnChangeFilename();
228 node = node->Next();
229 }
230 }
231 return OnSaveDocument(m_documentFile);
232 }
233
234 bool wxDocument::OnSaveDocument(const wxString& file)
235 {
236 if (file == "")
237 return FALSE;
238
239 wxString msgTitle;
240 if (wxTheApp->GetAppName() != "")
241 msgTitle = wxTheApp->GetAppName();
242 else
243 msgTitle = wxString("File error");
244
245 ofstream store(file);
246 if (store.fail() || store.bad())
247 {
248 (void)wxMessageBox("Sorry, could not open this file for saving.", msgTitle, wxOK | wxICON_EXCLAMATION,
249 GetDocumentWindow());
250 // Saving error
251 return FALSE;
252 }
253 if (SaveObject(store)==FALSE)
254 {
255 (void)wxMessageBox("Sorry, could not save this file.", msgTitle, wxOK | wxICON_EXCLAMATION,
256 GetDocumentWindow());
257 // Saving error
258 return FALSE;
259 }
260 Modify(FALSE);
261 SetFilename(file);
262 return TRUE;
263 }
264
265 bool wxDocument::OnOpenDocument(const wxString& file)
266 {
267 if (!OnSaveModified())
268 return FALSE;
269
270 wxString msgTitle;
271 if (wxTheApp->GetAppName() != "")
272 msgTitle = wxTheApp->GetAppName();
273 else
274 msgTitle = wxString("File error");
275
276 ifstream store(file);
277 if (store.fail() || store.bad())
278 {
279 (void)wxMessageBox("Sorry, could not open this file.", msgTitle, wxOK|wxICON_EXCLAMATION,
280 GetDocumentWindow());
281 return FALSE;
282 }
283 if (LoadObject(store)==FALSE)
284 {
285 (void)wxMessageBox("Sorry, could not open this file.", msgTitle, wxOK|wxICON_EXCLAMATION,
286 GetDocumentWindow());
287 return FALSE;
288 }
289 SetFilename(file, TRUE);
290 Modify(FALSE);
291
292 UpdateAllViews();
293
294 return TRUE;
295 }
296
297 istream& wxDocument::LoadObject(istream& stream)
298 {
299 // wxObject::LoadObject(stream);
300
301 return stream;
302 }
303
304 ostream& wxDocument::SaveObject(ostream& stream)
305 {
306 // wxObject::SaveObject(stream);
307
308 return stream;
309 }
310
311 bool wxDocument::Revert(void)
312 {
313 return FALSE;
314 }
315
316
317 // Get title, or filename if no title, else unnamed
318 bool wxDocument::GetPrintableName(wxString& buf) const
319 {
320 if (m_documentTitle != "")
321 {
322 buf = m_documentTitle;
323 return TRUE;
324 }
325 else if (m_documentFile != "")
326 {
327 buf = wxFileNameFromPath(m_documentFile);
328 return TRUE;
329 }
330 else
331 {
332 buf = "unnamed";
333 return TRUE;
334 }
335 }
336
337 wxWindow *wxDocument::GetDocumentWindow(void) const
338 {
339 wxView *view = GetFirstView();
340 if (view)
341 return view->GetFrame();
342 else
343 return wxTheApp->GetTopWindow();
344 }
345
346 wxCommandProcessor *wxDocument::OnCreateCommandProcessor(void)
347 {
348 return new wxCommandProcessor;
349 }
350
351 // TRUE if safe to close
352 bool wxDocument::OnSaveModified(void)
353 {
354 if (IsModified())
355 {
356 char buf[400];
357 wxString title;
358 GetPrintableName(title);
359
360 wxString msgTitle;
361 if (wxTheApp->GetAppName() != "")
362 msgTitle = wxTheApp->GetAppName();
363 else
364 msgTitle = wxString("Warning");
365
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());
369 if (res == wxNO)
370 {
371 Modify(FALSE);
372 return TRUE;
373 }
374 else if (res == wxYES)
375 return Save();
376 else if (res == wxCANCEL)
377 return FALSE;
378 }
379 return TRUE;
380 }
381
382 bool wxDocument::Draw(wxDC& WXUNUSED(context))
383 {
384 return TRUE;
385 }
386
387 bool wxDocument::AddView(wxView *view)
388 {
389 if (!m_documentViews.Member(view))
390 {
391 m_documentViews.Append(view);
392 OnChangedViewList();
393 }
394 return TRUE;
395 }
396
397 bool wxDocument::RemoveView(wxView *view)
398 {
399 (void)m_documentViews.DeleteObject(view);
400 OnChangedViewList();
401 return TRUE;
402 }
403
404 bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags)
405 {
406 if (GetDocumentTemplate()->CreateView(this, flags))
407 return TRUE;
408 else
409 return FALSE;
410 }
411
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)
416 {
417 if (m_documentViews.Number() == 0)
418 {
419 if (OnSaveModified())
420 {
421 delete this;
422 }
423 }
424 }
425
426 void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint)
427 {
428 wxNode *node = m_documentViews.First();
429 while (node)
430 {
431 wxView *view = (wxView *)node->Data();
432 view->OnUpdate(sender, hint);
433 node = node->Next();
434 }
435 }
436
437 void wxDocument::SetFilename(const wxString& filename, bool notifyViews)
438 {
439 m_documentFile = filename;
440 if ( notifyViews )
441 {
442 // Notify the views that the filename has changed
443 wxNode *node = m_documentViews.First();
444 while (node)
445 {
446 wxView *view = (wxView *)node->Data();
447 view->OnChangeFilename();
448 node = node->Next();
449 }
450 }
451 }
452
453
454 /*
455 * Document view
456 */
457
458 wxView::wxView(wxDocument *doc)
459 {
460 SetDocument(doc);
461
462 m_viewTypeName = "";
463 m_viewFrame = NULL;
464 }
465
466 wxView::~wxView(void)
467 {
468 GetDocumentManager()->ActivateView(this, FALSE, TRUE);
469 m_viewDocument->RemoveView(this);
470 }
471
472 // Extend event processing to search the document's event table
473 bool wxView::ProcessEvent(wxEvent& event)
474 {
475 if ( !GetDocument() || !GetDocument()->ProcessEvent(event) )
476 return wxEvtHandler::ProcessEvent(event);
477 else
478 return TRUE;
479 }
480
481 void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView))
482 {
483 }
484
485 void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info))
486 {
487 OnDraw(dc);
488 }
489
490 void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
491 {
492 }
493
494 void wxView::OnChangeFilename(void)
495 {
496 if (GetFrame() && GetDocument())
497 {
498 wxString name;
499 GetDocument()->GetPrintableName(name);
500
501 GetFrame()->SetTitle(name);
502 }
503 }
504
505 void wxView::SetDocument(wxDocument *doc)
506 {
507 m_viewDocument = doc;
508 if (doc)
509 doc->AddView(this);
510 }
511
512 bool wxView::Close(bool deleteWindow)
513 {
514 if (OnClose(deleteWindow))
515 return TRUE;
516 else
517 return FALSE;
518 }
519
520 void wxView::Activate(bool activate)
521 {
522 if (GetDocumentManager())
523 {
524 OnActivateView(activate, this, GetDocumentManager()->GetCurrentView());
525 GetDocumentManager()->ActivateView(this, activate);
526 }
527 }
528
529 bool wxView::OnClose(bool WXUNUSED(deleteWindow))
530 {
531 return GetDocument() ? GetDocument()->Close() : TRUE;
532 }
533
534 #if USE_PRINTING_ARCHITECTURE
535 wxPrintout *wxView::OnCreatePrintout(void)
536 {
537 return new wxDocPrintout(this);
538 }
539 #endif
540
541
542 /*
543 * wxDocTemplate
544 */
545
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)
550 {
551 m_documentManager = manager;
552 m_flags = flags;
553 m_description = descr;
554 m_directory = dir;
555 m_defaultExt = ext;
556 m_fileFilter = filter;
557 m_flags = flags;
558 m_docTypeName = docTypeName;
559 m_viewTypeName = viewTypeName;
560 m_documentManager->AssociateTemplate(this);
561
562 m_docClassInfo = docClassInfo;
563 m_viewClassInfo = viewClassInfo;
564 }
565
566 wxDocTemplate::~wxDocTemplate(void)
567 {
568 m_documentManager->DisassociateTemplate(this);
569 }
570
571 // Tries to dynamically construct an object of the right
572 // class.
573 wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags)
574 {
575 if (!m_docClassInfo)
576 return NULL;
577 wxDocument *doc = (wxDocument *)m_docClassInfo->CreateObject();
578 doc->SetFilename(path);
579 doc->SetDocumentTemplate(this);
580 GetDocumentManager()->AddDocument(doc);
581 doc->SetCommandProcessor(doc->OnCreateCommandProcessor());
582
583 if (doc->OnCreate(path, flags))
584 return doc;
585 else
586 {
587 delete doc;
588 return NULL;
589 }
590 }
591
592 wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags)
593 {
594 if (!m_viewClassInfo)
595 return NULL;
596 wxView *view = (wxView *)m_viewClassInfo->CreateObject();
597 view->SetDocument(doc);
598 if (view->OnCreate(doc, flags))
599 {
600 return view;
601 }
602 else
603 {
604 delete view;
605 return NULL;
606 }
607 }
608
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)
621 END_EVENT_TABLE()
622
623 wxDocManager::wxDocManager(long flags, bool initialize)
624 {
625 m_defaultDocumentNameCounter = 1;
626 m_flags = flags;
627 m_currentView = NULL;
628 m_maxDocsOpen = 10000;
629 m_fileHistory = NULL;
630 if (initialize)
631 Initialize();
632 }
633
634 wxDocManager::~wxDocManager(void)
635 {
636 Clear();
637 if (m_fileHistory)
638 delete m_fileHistory;
639 }
640
641 bool wxDocManager::Clear(bool force)
642 {
643 wxNode *node = m_docs.First();
644 while (node)
645 {
646 wxDocument *doc = (wxDocument *)node->Data();
647 wxNode *next = node->Next();
648
649 if (!doc->Close() && !force)
650 return FALSE;
651
652 // Implicitly deletes the document when the last
653 // view is removed (deleted)
654 doc->DeleteAllViews();
655
656 // Check document is deleted
657 if (m_docs.Member(doc))
658 delete doc;
659
660 // This assumes that documents are not connected in
661 // any way, i.e. deleting one document does NOT
662 // delete another.
663 node = next;
664 }
665 node = m_templates.First();
666 while (node)
667 {
668 wxDocTemplate *templ = (wxDocTemplate*) node->Data();
669 wxNode* next = node->Next();
670 delete templ;
671 node = next;
672 }
673 return TRUE;
674 }
675
676 bool wxDocManager::Initialize(void)
677 {
678 m_fileHistory = OnCreateFileHistory();
679 return TRUE;
680 }
681
682 wxFileHistory *wxDocManager::OnCreateFileHistory(void)
683 {
684 return new wxFileHistory;
685 }
686
687 void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event))
688 {
689 wxDocument *doc = GetCurrentDocument();
690 if (!doc)
691 return;
692 if (doc->Close())
693 {
694 doc->DeleteAllViews();
695 if (m_docs.Member(doc))
696 delete doc;
697 }
698 }
699
700 void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event))
701 {
702 CreateDocument(wxString(""), wxDOC_NEW);
703 }
704
705 void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event))
706 {
707 CreateDocument(wxString(""), 0);
708 }
709
710 void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event))
711 {
712 wxDocument *doc = GetCurrentDocument();
713 if (!doc)
714 return;
715 doc->Revert();
716 }
717
718 void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event))
719 {
720 wxDocument *doc = GetCurrentDocument();
721 if (!doc)
722 return;
723 doc->Save();
724 }
725
726 void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event))
727 {
728 wxDocument *doc = GetCurrentDocument();
729 if (!doc)
730 return;
731 doc->SaveAs();
732 }
733
734 void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event))
735 {
736 wxView *view = GetCurrentView();
737 if (!view)
738 return;
739
740 wxPrintout *printout = view->OnCreatePrintout();
741 if (printout)
742 {
743 // TODO: trouble about this is that it pulls in the postscript
744 // code unecessarily
745 #ifdef __WXMSW__
746 if ( wxTheApp->GetPrintMode() == wxPRINT_WINDOWS )
747 {
748 wxWindowsPrinter printer;
749 printer.Print(view->GetFrame(), printout, TRUE);
750 }
751 else
752 #endif
753 {
754 wxPostScriptPrinter printer;
755 printer.Print(view->GetFrame(), printout, TRUE);
756 }
757
758 delete printout;
759 }
760 }
761
762 void wxDocManager::OnPrintSetup(wxCommandEvent& WXUNUSED(event))
763 {
764 wxWindow *parentWin = wxTheApp->GetTopWindow();
765 wxView *view = GetCurrentView();
766 if (view)
767 parentWin = view->GetFrame();
768
769 wxPrintData data;
770
771 #ifdef __WXMSW__
772 if ( wxTheApp->GetPrintMode() == wxPRINT_WINDOWS )
773 {
774 wxPrintDialog printerDialog(parentWin, & data);
775 printerDialog.GetPrintData().SetSetupDialog(TRUE);
776 printerDialog.ShowModal();
777 }
778 else
779 #endif
780 {
781 wxGenericPrintDialog printerDialog(parentWin, & data);
782 printerDialog.GetPrintData().SetSetupDialog(TRUE);
783 printerDialog.ShowModal();
784 }
785 }
786
787 void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event))
788 {
789 wxView *view = GetCurrentView();
790 if (!view)
791 return;
792
793 wxPrintout *printout = view->OnCreatePrintout();
794 if (printout)
795 {
796 // Pass two printout objects: for preview, and possible printing.
797 wxPrintPreviewBase *preview = NULL;
798 #ifdef __WXMSW__
799 if ( wxTheApp->GetPrintMode() == wxPRINT_WINDOWS )
800 preview = new wxWindowsPrintPreview(printout, view->OnCreatePrintout());
801 else
802 #endif
803 preview = new wxPostScriptPrintPreview(printout, view->OnCreatePrintout());
804
805 wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), "Print Preview",
806 wxPoint(100, 100), wxSize(600, 650));
807 frame->Centre(wxBOTH);
808 frame->Initialize();
809 frame->Show(TRUE);
810 }
811 }
812
813 void wxDocManager::OnUndo(wxCommandEvent& WXUNUSED(event))
814 {
815 wxDocument *doc = GetCurrentDocument();
816 if (!doc)
817 return;
818 if (doc->GetCommandProcessor())
819 doc->GetCommandProcessor()->Undo();
820 }
821
822 void wxDocManager::OnRedo(wxCommandEvent& WXUNUSED(event))
823 {
824 wxDocument *doc = GetCurrentDocument();
825 if (!doc)
826 return;
827 if (doc->GetCommandProcessor())
828 doc->GetCommandProcessor()->Redo();
829 }
830
831 wxView *wxDocManager::GetCurrentView(void) const
832 {
833 if (m_currentView)
834 return m_currentView;
835 if (m_docs.Number() == 1)
836 {
837 wxDocument* doc = (wxDocument*) m_docs.First()->Data();
838 return doc->GetFirstView();
839 }
840 return NULL;
841 }
842
843 // Extend event processing to search the view's event table
844 bool wxDocManager::ProcessEvent(wxEvent& event)
845 {
846 wxView* view = GetCurrentView();
847 if (view)
848 {
849 if (view->ProcessEvent(event))
850 return TRUE;
851 }
852 return wxEvtHandler::ProcessEvent(event);
853 }
854
855 wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags)
856 {
857 wxDocTemplate **templates = new wxDocTemplate *[m_templates.Number()];
858 int i;
859 int n = 0;
860 for (i = 0; i < m_templates.Number(); i++)
861 {
862 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Nth(i)->Data());
863 if (temp->IsVisible())
864 {
865 templates[n] = temp;
866 n ++;
867 }
868 }
869 if (n == 0)
870 {
871 delete[] templates;
872 return NULL;
873 }
874
875 // If we've reached the max number of docs, close the
876 // first one.
877 if (GetDocuments().Number() >= m_maxDocsOpen)
878 {
879 wxDocument *doc = (wxDocument *)GetDocuments().First()->Data();
880 if (doc->Close())
881 {
882 // Implicitly deletes the document when
883 // the last view is deleted
884 doc->DeleteAllViews();
885
886 // Check we're really deleted
887 if (m_docs.Member(doc))
888 delete doc;
889 }
890 else
891 return NULL;
892 }
893
894 // New document: user chooses a template, unless there's only one.
895 if (flags & wxDOC_NEW)
896 {
897 if (n == 1)
898 {
899 wxDocTemplate *temp = templates[0];
900 delete[] templates;
901 wxDocument *newDoc = temp->CreateDocument(path, flags);
902 if (newDoc)
903 {
904 newDoc->SetDocumentName(temp->GetDocumentName());
905 newDoc->SetDocumentTemplate(temp);
906 newDoc->OnNewDocument();
907 }
908 return newDoc;
909 }
910
911 wxDocTemplate *temp = SelectDocumentType(templates, n);
912 delete[] templates;
913 if (temp)
914 {
915 wxDocument *newDoc = temp->CreateDocument(path, flags);
916 if (newDoc)
917 {
918 newDoc->SetDocumentName(temp->GetDocumentName());
919 newDoc->SetDocumentTemplate(temp);
920 newDoc->OnNewDocument();
921 }
922 return newDoc;
923 }
924 else
925 return NULL;
926 }
927
928 // Existing document
929 wxDocTemplate *temp = NULL;
930
931 wxString path2("");
932 if (path != "")
933 path2 = path;
934
935 if (flags & wxDOC_SILENT)
936 temp = FindTemplateForPath(path2);
937 else
938 temp = SelectDocumentPath(templates, n, path2, flags);
939
940 delete[] templates;
941
942 if (temp)
943 {
944 wxDocument *newDoc = temp->CreateDocument(path2, flags);
945 if (newDoc)
946 {
947 newDoc->SetDocumentName(temp->GetDocumentName());
948 newDoc->SetDocumentTemplate(temp);
949 if (!newDoc->OnOpenDocument(path2))
950 {
951 delete newDoc;
952 return NULL;
953 }
954 AddFileToHistory(path2);
955 }
956 return newDoc;
957 }
958 else
959 return NULL;
960 }
961
962 wxView *wxDocManager::CreateView(wxDocument *doc, long flags)
963 {
964 wxDocTemplate **templates = new wxDocTemplate *[m_templates.Number()];
965 int n =0;
966 int i;
967 for (i = 0; i < m_templates.Number(); i++)
968 {
969 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Nth(i)->Data());
970 if (temp->IsVisible())
971 {
972 if (temp->GetDocumentName() == doc->GetDocumentName())
973 {
974 templates[n] = temp;
975 n ++;
976 }
977 }
978 }
979 if (n == 0)
980 {
981 delete[] templates;
982 return NULL;
983 }
984 if (n == 1)
985 {
986 wxDocTemplate *temp = templates[0];
987 delete[] templates;
988 wxView *view = temp->CreateView(doc, flags);
989 if (view)
990 view->SetViewName(temp->GetViewName());
991 return view;
992 }
993
994 wxDocTemplate *temp = SelectViewType(templates, n);
995 delete[] templates;
996 if (temp)
997 {
998 wxView *view = temp->CreateView(doc, flags);
999 if (view)
1000 view->SetViewName(temp->GetViewName());
1001 return view;
1002 }
1003 else
1004 return NULL;
1005 }
1006
1007 // Not yet implemented
1008 void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags))
1009 {
1010 }
1011
1012 // Not yet implemented
1013 bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc))
1014 {
1015 return FALSE;
1016 }
1017
1018 wxDocument *wxDocManager::GetCurrentDocument(void) const
1019 {
1020 if (m_currentView)
1021 return m_currentView->GetDocument();
1022 else
1023 return NULL;
1024 }
1025
1026 // Make a default document name
1027 bool wxDocManager::MakeDefaultName(wxString& name)
1028 {
1029 char buf[256];
1030 sprintf(buf, "unnamed%d", m_defaultDocumentNameCounter);
1031 m_defaultDocumentNameCounter ++;
1032 name = buf;
1033 return TRUE;
1034 }
1035
1036 // Not yet implemented
1037 wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path))
1038 {
1039 return NULL;
1040 }
1041
1042 // File history management
1043 void wxDocManager::AddFileToHistory(const wxString& file)
1044 {
1045 if (m_fileHistory)
1046 m_fileHistory->AddFileToHistory(file);
1047 }
1048
1049 wxString wxDocManager::GetHistoryFile(int i) const
1050 {
1051 if (m_fileHistory)
1052 return wxString(m_fileHistory->GetHistoryFile(i));
1053 else
1054 return wxString("");
1055 }
1056
1057 void wxDocManager::FileHistoryUseMenu(wxMenu *menu)
1058 {
1059 if (m_fileHistory)
1060 m_fileHistory->FileHistoryUseMenu(menu);
1061 }
1062
1063 void wxDocManager::FileHistoryLoad(const wxString& resourceFile, const wxString& section)
1064 {
1065 if (m_fileHistory)
1066 m_fileHistory->FileHistoryLoad(resourceFile, section);
1067 }
1068
1069 void wxDocManager::FileHistorySave(const wxString& resourceFile, const wxString& section)
1070 {
1071 if (m_fileHistory)
1072 m_fileHistory->FileHistorySave(resourceFile, section);
1073 }
1074
1075 int wxDocManager::GetNoHistoryFiles(void) const
1076 {
1077 if (m_fileHistory)
1078 return m_fileHistory->GetNoHistoryFiles();
1079 else
1080 return 0;
1081 }
1082
1083 static char *FindExtension(char *path)
1084 {
1085 static char ext[10];
1086 int len = strlen(path);
1087 if (path)
1088 {
1089 int i = 0;
1090 for (i = (len-1); i > 0; i --)
1091 if (path[i] == '.')
1092 break;
1093 if (path[i] == '.')
1094 {
1095 int j;
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
1098 ext[j-(i+1)] = 0;
1099 return ext;
1100 }
1101 else
1102 return NULL;
1103 }
1104 else return NULL;
1105 }
1106
1107
1108 // Given a path, try to find a matching template. Won't
1109 // always work, of course.
1110 wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path)
1111 {
1112 char *theExt = FindExtension((char *)(const char *)path);
1113 if (!theExt)
1114 return NULL;
1115 wxDocTemplate *theTemplate = NULL;
1116
1117 if (m_templates.Number() == 1)
1118 return (wxDocTemplate *)m_templates.First()->Data();
1119
1120 // Find the template which this extension corresponds to
1121 int i;
1122 for (i = 0; i < m_templates.Number(); i++)
1123 {
1124 wxDocTemplate *temp = (wxDocTemplate *)m_templates.Nth(i)->Data();
1125 if (strcmp(temp->GetDefaultExtension(), theExt) == 0)
1126 {
1127 theTemplate = temp;
1128 break;
1129 }
1130 }
1131 return theTemplate;
1132 }
1133
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))
1140 {
1141 // We can only have multiple filters in Windows
1142 #ifdef __WXMSW__
1143 char *descrBuf = new char[1000];
1144 descrBuf[0] = 0;
1145 int i;
1146 for (i = 0; i < noTemplates; i++)
1147 {
1148 if (templates[i]->IsVisible())
1149 {
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, "|");
1157 }
1158 }
1159 int len = strlen(descrBuf);
1160 if (len > 0)
1161 // Omit final "|"
1162 descrBuf[len-1] = 0;
1163
1164 char *pathTmp = wxFileSelector("Select a file", "", "", "", descrBuf, 0, wxTheApp->GetTopWindow());
1165 delete[] descrBuf;
1166 if (pathTmp)
1167 {
1168 path = pathTmp;
1169 char *theExt = FindExtension((char *)(const char *)path);
1170 if (!theExt)
1171 return NULL;
1172
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);
1178 return theTemplate;
1179 }
1180 else
1181 {
1182 path = "";
1183 return NULL;
1184 }
1185 #else
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);
1190 if (!temp)
1191 return NULL;
1192
1193 char *pathTmp = wxFileSelector("Select a file", "", "",
1194 temp->GetDefaultExtension(),
1195 temp->GetFileFilter(),
1196 0, wxTheApp->GetTopWindow());
1197
1198 if (pathTmp)
1199 {
1200 path = pathTmp;
1201 return temp;
1202 }
1203 else
1204 return NULL;
1205 #endif
1206 }
1207
1208 wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates,
1209 int noTemplates)
1210 {
1211 char **strings = new char *[noTemplates];
1212 char **data = new char *[noTemplates];
1213 int i;
1214 int n = 0;
1215 for (i = 0; i < noTemplates; i++)
1216 {
1217 if (templates[i]->IsVisible())
1218 {
1219 strings[n] = WXSTRINGCAST templates[i]->m_description;
1220 data[n] = (char *)templates[i];
1221 n ++;
1222 }
1223 }
1224 if (n == 0)
1225 {
1226 delete[] strings;
1227 delete[] data;
1228 return NULL;
1229 }
1230 else if (n == 1)
1231 {
1232 wxDocTemplate *temp = (wxDocTemplate *)data[0];
1233 delete[] strings;
1234 delete[] data;
1235 return temp;
1236 }
1237
1238 wxDocTemplate *theTemplate = (wxDocTemplate *)wxGetSingleChoiceData("Select a document template", "Templates", n,
1239 strings, data);
1240 delete[] strings;
1241 delete[] data;
1242 return theTemplate;
1243 }
1244
1245 wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates,
1246 int noTemplates)
1247 {
1248 char **strings = new char *[noTemplates];
1249 char **data = new char *[noTemplates];
1250 int i;
1251 int n = 0;
1252 for (i = 0; i < noTemplates; i++)
1253 {
1254 if (templates[i]->IsVisible() && templates[i]->GetViewName())
1255 {
1256 strings[n] = WXSTRINGCAST templates[i]->m_viewTypeName;
1257 data[n] = (char *)templates[i];
1258 n ++;
1259 }
1260 }
1261 wxDocTemplate *theTemplate = (wxDocTemplate *)wxGetSingleChoiceData("Select a document view", "Views", n,
1262 strings, data);
1263 delete[] strings;
1264 delete[] data;
1265 return theTemplate;
1266 }
1267
1268 void wxDocManager::AssociateTemplate(wxDocTemplate *temp)
1269 {
1270 if (!m_templates.Member(temp))
1271 m_templates.Append(temp);
1272 }
1273
1274 void wxDocManager::DisassociateTemplate(wxDocTemplate *temp)
1275 {
1276 m_templates.DeleteObject(temp);
1277 }
1278
1279 // Add and remove a document from the manager's list
1280 void wxDocManager::AddDocument(wxDocument *doc)
1281 {
1282 if (!m_docs.Member(doc))
1283 m_docs.Append(doc);
1284 }
1285
1286 void wxDocManager::RemoveDocument(wxDocument *doc)
1287 {
1288 m_docs.DeleteObject(doc);
1289 }
1290
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))
1294 {
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?
1299 /*
1300 if (deleting)
1301 {
1302 if (m_currentView == view)
1303 m_currentView = NULL;
1304 }
1305 else
1306 */
1307 {
1308 if (activate)
1309 m_currentView = view;
1310 else
1311 m_currentView = NULL;
1312 }
1313 }
1314
1315 /*
1316 * Default document child frame
1317 */
1318
1319 BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame)
1320 EVT_ACTIVATE(wxDocChildFrame::OnActivate)
1321 END_EVENT_TABLE()
1322
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)
1326 {
1327 m_childDocument = doc;
1328 m_childView = view;
1329 if (view)
1330 view->SetFrame(this);
1331 }
1332
1333 wxDocChildFrame::~wxDocChildFrame(void)
1334 {
1335 }
1336
1337 // Extend event processing to search the view's event table
1338 bool wxDocChildFrame::ProcessEvent(wxEvent& event)
1339 {
1340 if (m_childView)
1341 m_childView->Activate(TRUE);
1342
1343 if ( !m_childView || ! m_childView->ProcessEvent(event) )
1344 {
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);
1348 else
1349 return TRUE;
1350 }
1351 else
1352 return TRUE;
1353 }
1354
1355 void wxDocChildFrame::OnActivate(wxActivateEvent& event)
1356 {
1357 wxFrame::OnActivate(event);
1358
1359 if (m_childView)
1360 m_childView->Activate(event.GetActive());
1361 }
1362
1363 bool wxDocChildFrame::OnClose(void)
1364 {
1365 // Close view but don't delete the frame while doing so!
1366 // ...since it will be deleted by wxWindows if we return TRUE.
1367 if (m_childView)
1368 {
1369 bool ans = m_childView->Close(FALSE); // FALSE means don't delete associated window
1370 if (ans)
1371 {
1372 m_childView->Activate(FALSE);
1373 delete m_childView;
1374 m_childView = NULL;
1375 m_childDocument = NULL;
1376 }
1377
1378 return ans;
1379 }
1380 else return TRUE;
1381 }
1382
1383 /*
1384 * Default parent frame
1385 */
1386
1387 BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame)
1388 EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit)
1389 EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile)
1390 END_EVENT_TABLE()
1391
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)
1395 {
1396 m_docManager = manager;
1397 }
1398
1399 void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event))
1400 {
1401 Close();
1402 }
1403
1404 void wxDocParentFrame::OnMRUFile(wxCommandEvent& event)
1405 {
1406 wxString f(m_docManager->GetHistoryFile(event.GetSelection() - wxID_FILE1));
1407 if (f != "")
1408 (void)m_docManager->CreateDocument(f, wxDOC_SILENT);
1409 }
1410
1411 // Extend event processing to search the view's event table
1412 bool wxDocParentFrame::ProcessEvent(wxEvent& event)
1413 {
1414 // Try the document manager, then do default processing
1415 if (!m_docManager || !m_docManager->ProcessEvent(event))
1416 return wxEvtHandler::ProcessEvent(event);
1417 else
1418 return TRUE;
1419 }
1420
1421 // Define the behaviour for the frame closing
1422 // - must delete all frames except for the main one.
1423 bool wxDocParentFrame::OnClose(void)
1424 {
1425 return m_docManager->Clear(FALSE);
1426 }
1427
1428 #if USE_PRINTING_ARCHITECTURE
1429
1430 wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title):
1431 wxPrintout(WXSTRINGCAST title)
1432 {
1433 m_printoutView = view;
1434 }
1435
1436 bool wxDocPrintout::OnPrintPage(int WXUNUSED(page))
1437 {
1438 wxDC *dc = GetDC();
1439
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);
1445
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
1450 // moment.
1451 float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
1452
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;
1456 int w, h;
1457 dc->GetSize(&w, &h);
1458 GetPageSizePixels(&pageWidth, &pageHeight);
1459
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);
1464
1465 if (m_printoutView)
1466 {
1467 m_printoutView->OnDraw(dc);
1468 }
1469 return TRUE;
1470 }
1471
1472 bool wxDocPrintout::HasPage(int pageNum)
1473 {
1474 return (pageNum == 1);
1475 }
1476
1477 bool wxDocPrintout::OnBeginDocument(int startPage, int endPage)
1478 {
1479 if (!wxPrintout::OnBeginDocument(startPage, endPage))
1480 return FALSE;
1481
1482 return TRUE;
1483 }
1484
1485 void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
1486 {
1487 *minPage = 1;
1488 *maxPage = 1;
1489 *selPageFrom = 1;
1490 *selPageTo = 1;
1491 }
1492
1493 #endif
1494
1495 /*
1496 * Command processing framework
1497 */
1498
1499 wxCommand::wxCommand(bool canUndoIt, const wxString& name)
1500 {
1501 m_canUndo = canUndoIt;
1502 m_commandName = name;
1503 }
1504
1505 wxCommand::~wxCommand(void)
1506 {
1507 }
1508
1509 // Command processor
1510 wxCommandProcessor::wxCommandProcessor(int maxCommands)
1511 {
1512 m_maxNoCommands = maxCommands;
1513 m_currentCommand = NULL;
1514 m_commandEditMenu = NULL;
1515 }
1516
1517 wxCommandProcessor::~wxCommandProcessor(void)
1518 {
1519 ClearCommands();
1520 }
1521
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)
1526 {
1527 bool success = command->Do();
1528 if (success && storeIt)
1529 {
1530 if (m_commands.Number() == m_maxNoCommands)
1531 {
1532 wxNode *firstNode = m_commands.First();
1533 wxCommand *firstCommand = (wxCommand *)firstNode->Data();
1534 delete firstCommand;
1535 delete firstNode;
1536 }
1537
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)
1541 ClearCommands();
1542 else
1543 {
1544 wxNode *node = m_currentCommand->Next();
1545 while (node)
1546 {
1547 wxNode *next = node->Next();
1548 delete (wxCommand *)node->Data();
1549 delete node;
1550 node = next;
1551 }
1552 }
1553
1554 m_commands.Append(command);
1555 m_currentCommand = m_commands.Last();
1556 SetMenuStrings();
1557 }
1558 return success;
1559 }
1560
1561 bool wxCommandProcessor::Undo(void)
1562 {
1563 if (m_currentCommand)
1564 {
1565 wxCommand *command = (wxCommand *)m_currentCommand->Data();
1566 if (command->CanUndo())
1567 {
1568 bool success = command->Undo();
1569 if (success)
1570 {
1571 m_currentCommand = m_currentCommand->Previous();
1572 SetMenuStrings();
1573 return TRUE;
1574 }
1575 }
1576 }
1577 return FALSE;
1578 }
1579
1580 bool wxCommandProcessor::Redo(void)
1581 {
1582 wxCommand *redoCommand = NULL;
1583 wxNode *redoNode = NULL;
1584 if (m_currentCommand && m_currentCommand->Next())
1585 {
1586 redoCommand = (wxCommand *)m_currentCommand->Next()->Data();
1587 redoNode = m_currentCommand->Next();
1588 }
1589 else
1590 {
1591 if (m_commands.Number() > 0)
1592 {
1593 redoCommand = (wxCommand *)m_commands.First()->Data();
1594 redoNode = m_commands.First();
1595 }
1596 }
1597
1598 if (redoCommand)
1599 {
1600 bool success = redoCommand->Do();
1601 if (success)
1602 {
1603 m_currentCommand = redoNode;
1604 SetMenuStrings();
1605 return TRUE;
1606 }
1607 }
1608 return FALSE;
1609 }
1610
1611 bool wxCommandProcessor::CanUndo(void)
1612 {
1613 if (m_currentCommand)
1614 return ((wxCommand *)m_currentCommand->Data())->CanUndo();
1615 return FALSE;
1616 }
1617
1618 void wxCommandProcessor::Initialize(void)
1619 {
1620 m_currentCommand = m_commands.Last();
1621 SetMenuStrings();
1622 }
1623
1624 void wxCommandProcessor::SetMenuStrings(void)
1625 {
1626 if (m_commandEditMenu)
1627 {
1628 wxString buf;
1629 if (m_currentCommand)
1630 {
1631 wxCommand *command = (wxCommand *)m_currentCommand->Data();
1632 wxString commandName(command->GetName());
1633 if (commandName == "") commandName = "Unnamed command";
1634 bool canUndo = command->CanUndo();
1635 if (canUndo)
1636 buf = wxString("&Undo ") + commandName;
1637 else
1638 buf = wxString("Can't &Undo ") + commandName;
1639
1640 m_commandEditMenu->SetLabel(wxID_UNDO, buf);
1641 m_commandEditMenu->Enable(wxID_UNDO, canUndo);
1642
1643 // We can redo, if we're not at the end of the history.
1644 if (m_currentCommand->Next())
1645 {
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);
1652 }
1653 else
1654 {
1655 m_commandEditMenu->SetLabel(wxID_REDO, "&Redo");
1656 m_commandEditMenu->Enable(wxID_REDO, FALSE);
1657 }
1658 }
1659 else
1660 {
1661 m_commandEditMenu->SetLabel(wxID_UNDO, "&Undo");
1662 m_commandEditMenu->Enable(wxID_UNDO, FALSE);
1663
1664 if (m_commands.Number() == 0)
1665 {
1666 m_commandEditMenu->SetLabel(wxID_REDO, "&Redo");
1667 m_commandEditMenu->Enable(wxID_REDO, FALSE);
1668 }
1669 else
1670 {
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);
1679 }
1680 }
1681 }
1682 }
1683
1684 void wxCommandProcessor::ClearCommands(void)
1685 {
1686 wxNode *node = m_commands.First();
1687 while (node)
1688 {
1689 wxCommand *command = (wxCommand *)node->Data();
1690 delete command;
1691 delete node;
1692 node = m_commands.First();
1693 }
1694 m_currentCommand = NULL;
1695 }
1696
1697
1698 /*
1699 * File history processor
1700 */
1701
1702 wxFileHistory::wxFileHistory(int maxFiles)
1703 {
1704 m_fileMaxFiles = maxFiles;
1705 m_fileMenu = NULL;
1706 m_fileHistoryN = 0;
1707 m_fileHistory = new char *[m_fileMaxFiles];
1708 }
1709
1710 wxFileHistory::~wxFileHistory(void)
1711 {
1712 int i;
1713 for (i = 0; i < m_fileHistoryN; i++)
1714 delete[] m_fileHistory[i];
1715 delete[] m_fileHistory;
1716 }
1717
1718 // File history management
1719 void wxFileHistory::AddFileToHistory(const wxString& file)
1720 {
1721 if (!m_fileMenu)
1722 return;
1723
1724 int i;
1725
1726 // Check we don't already have this file
1727 for (i = 0; i < m_fileHistoryN; i++)
1728 {
1729 if (m_fileHistory[i] && wxString(m_fileHistory[i]) == file)
1730 return;
1731 }
1732
1733 // Add to the project file history:
1734 // Move existing files (if any) down so we can insert file at beginning.
1735
1736 // First delete filename that has popped off the end of the array (if any)
1737 if (m_fileHistoryN == m_fileMaxFiles)
1738 {
1739 delete[] m_fileHistory[m_fileMaxFiles-1];
1740 m_fileHistory[m_fileMaxFiles-1] = NULL;
1741 }
1742 if (m_fileHistoryN < m_fileMaxFiles)
1743 {
1744 if (m_fileHistoryN == 0)
1745 m_fileMenu->AppendSeparator();
1746 m_fileMenu->Append(wxID_FILE1+m_fileHistoryN, "[EMPTY]");
1747 m_fileHistoryN ++;
1748 }
1749 // Shuffle filenames down
1750 for (i = (m_fileHistoryN-1); i > 0; i--)
1751 {
1752 m_fileHistory[i] = m_fileHistory[i-1];
1753 }
1754 m_fileHistory[0] = copystring(file);
1755
1756 for (i = 0; i < m_fileHistoryN; i++)
1757 if (m_fileHistory[i])
1758 {
1759 char buf[400];
1760 sprintf(buf, "&%d %s", i+1, m_fileHistory[i]);
1761 m_fileMenu->SetLabel(wxID_FILE1+i, buf);
1762 }
1763 }
1764
1765 wxString wxFileHistory::GetHistoryFile(int i) const
1766 {
1767 if (i < m_fileHistoryN)
1768 return wxString(m_fileHistory[i]);
1769 else
1770 return wxString("");
1771 }
1772
1773 void wxFileHistory::FileHistoryUseMenu(wxMenu *menu)
1774 {
1775 m_fileMenu = menu;
1776 }
1777
1778 void wxFileHistory::FileHistoryLoad(const wxString& resourceFile, const wxString& section)
1779 {
1780 #if USE_RESOURCES
1781 m_fileHistoryN = 0;
1782 char buf[400];
1783 sprintf(buf, "file%d", m_fileHistoryN+1);
1784 char *historyFile = NULL;
1785 while ((m_fileHistoryN <= m_fileMaxFiles) && wxGetResource(section, buf, &historyFile, resourceFile) && historyFile)
1786 {
1787 // wxGetResource allocates memory so this is o.k.
1788 m_fileHistory[m_fileHistoryN] = historyFile;
1789 m_fileHistoryN ++;
1790 sprintf(buf, "file%d", m_fileHistoryN+1);
1791 historyFile = NULL;
1792 }
1793 #endif
1794 }
1795
1796 void wxFileHistory::FileHistorySave(const wxString& resourceFile, const wxString& section)
1797 {
1798 #if USE_RESOURCES
1799 char buf[400];
1800 int i;
1801 for (i = 0; i < m_fileHistoryN; i++)
1802 {
1803 sprintf(buf, "file%d", i+1);
1804 wxWriteResource(section, buf, m_fileHistory[i], resourceFile);
1805 }
1806 #endif
1807 }
1808
1809 #if 0
1810 /*
1811 * wxPrintInfo
1812 */
1813
1814 wxPrintInfo::wxPrintInfo(void)
1815 {
1816 pageNumber = 1;
1817 }
1818
1819 wxPrintInfo::~wxPrintInfo(void)
1820 {
1821 }
1822 #endif
1823
1824 /*
1825 * Permits compatibility with existing file formats and functions
1826 * that manipulate files directly
1827 */
1828
1829 bool wxTransferFileToStream(const wxString& filename, ostream& stream)
1830 {
1831 FILE *fd1;
1832 int ch;
1833
1834 if ((fd1 = fopen (WXSTRINGCAST filename, "rb")) == NULL)
1835 return FALSE;
1836
1837 while ((ch = getc (fd1)) != EOF)
1838 stream << (unsigned char)ch;
1839
1840 fclose (fd1);
1841 return TRUE;
1842 }
1843
1844 bool wxTransferStreamToFile(istream& stream, const wxString& filename)
1845 {
1846 FILE *fd1;
1847 int ch;
1848
1849 if ((fd1 = fopen (WXSTRINGCAST filename, "wb")) == NULL)
1850 {
1851 return FALSE;
1852 }
1853
1854 while (!stream.eof())
1855 {
1856 ch = stream.get();
1857 if (!stream.eof())
1858 putc (ch, fd1);
1859 }
1860 fclose (fd1);
1861 return TRUE;
1862 }
1863
1864 #endif
1865 // End USE_DOC_VIEW_ARCHITECTURE