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