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