]> git.saurik.com Git - wxWidgets.git/blob - src/common/docview.cpp
the initial draft of wxLongLong class
[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 int noTemplates,
1158 wxString& path,
1159 long WXUNUSED(flags),
1160 bool WXUNUSED(save))
1161 {
1162 // We can only have multiple filters in Windows
1163 #ifdef __WXMSW__
1164 wxString descrBuf;
1165
1166 int i;
1167 for (i = 0; i < noTemplates; i++)
1168 {
1169 if (templates[i]->IsVisible())
1170 {
1171 // add a '|' to separate this filter from the previous one
1172 if ( !descrBuf.IsEmpty() )
1173 descrBuf << _T('|');
1174
1175 descrBuf << templates[i]->GetDescription()
1176 << _T(" (") << templates[i]->GetFileFilter() << _T(") |")
1177 << templates[i]->GetFileFilter();
1178 }
1179 }
1180 #else
1181 wxString descrBuf = _T("*.*");
1182 #endif
1183
1184 int FilterIndex = 0;
1185 wxString pathTmp = wxFileSelectorEx(_("Select a file"),
1186 _T(""),
1187 _T(""),
1188 &FilterIndex,
1189 descrBuf,
1190 0,
1191 wxTheApp->GetTopWindow());
1192
1193 if (!pathTmp.IsEmpty())
1194 {
1195 path = pathTmp;
1196 wxString theExt = FindExtension(path);
1197 if (!theExt)
1198 return (wxDocTemplate *) NULL;
1199
1200 // This is dodgy in that we're selecting the template on the
1201 // basis of the file extension, which may not be a standard
1202 // one. We really want to know exactly which template was
1203 // chosen by using a more advanced file selector.
1204 wxDocTemplate *theTemplate = FindTemplateForPath(path);
1205 if ( !theTemplate )
1206 theTemplate = templates[FilterIndex];
1207
1208 return theTemplate;
1209 }
1210 else
1211 {
1212 path = _T("");
1213 return (wxDocTemplate *) NULL;
1214 }
1215 #if 0
1216 // In all other windowing systems, until we have more advanced
1217 // file selectors, we must select the document type (template) first, and
1218 // _then_ pop up the file selector.
1219 wxDocTemplate *temp = SelectDocumentType(templates, noTemplates);
1220 if (!temp)
1221 return (wxDocTemplate *) NULL;
1222
1223 wxChar *pathTmp = wxFileSelector(_("Select a file"), _T(""), _T(""),
1224 temp->GetDefaultExtension(),
1225 temp->GetFileFilter(),
1226 0, wxTheApp->GetTopWindow());
1227
1228 if (pathTmp)
1229 {
1230 path = pathTmp;
1231 return temp;
1232 }
1233 else
1234 return (wxDocTemplate *) NULL;
1235 #endif // 0
1236 }
1237
1238 wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates,
1239 int noTemplates)
1240 {
1241 wxChar **strings = new wxChar *[noTemplates];
1242 wxChar **data = new wxChar *[noTemplates];
1243 int i;
1244 int n = 0;
1245 for (i = 0; i < noTemplates; i++)
1246 {
1247 if (templates[i]->IsVisible())
1248 {
1249 strings[n] = WXSTRINGCAST templates[i]->m_description;
1250 data[n] = (wxChar *)templates[i];
1251 n ++;
1252 }
1253 }
1254 if (n == 0)
1255 {
1256 delete[] strings;
1257 delete[] data;
1258 return (wxDocTemplate *) NULL;
1259 }
1260 else if (n == 1)
1261 {
1262 wxDocTemplate *temp = (wxDocTemplate *)data[0];
1263 delete[] strings;
1264 delete[] data;
1265 return temp;
1266 }
1267
1268 wxDocTemplate *theTemplate = (wxDocTemplate *)wxGetSingleChoiceData(_("Select a document template"), _("Templates"), n,
1269 strings, data);
1270 delete[] strings;
1271 delete[] data;
1272 return theTemplate;
1273 }
1274
1275 wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates,
1276 int noTemplates)
1277 {
1278 wxChar **strings = new wxChar *[noTemplates];
1279 wxChar **data = new wxChar *[noTemplates];
1280 int i;
1281 int n = 0;
1282 for (i = 0; i < noTemplates; i++)
1283 {
1284 if (templates[i]->IsVisible() && (templates[i]->GetViewName() != _T("")))
1285 {
1286 strings[n] = WXSTRINGCAST templates[i]->m_viewTypeName;
1287 data[n] = (wxChar *)templates[i];
1288 n ++;
1289 }
1290 }
1291 wxDocTemplate *theTemplate = (wxDocTemplate *)wxGetSingleChoiceData(_("Select a document view"), _("Views"), n,
1292 strings, data);
1293 delete[] strings;
1294 delete[] data;
1295 return theTemplate;
1296 }
1297
1298 void wxDocManager::AssociateTemplate(wxDocTemplate *temp)
1299 {
1300 if (!m_templates.Member(temp))
1301 m_templates.Append(temp);
1302 }
1303
1304 void wxDocManager::DisassociateTemplate(wxDocTemplate *temp)
1305 {
1306 m_templates.DeleteObject(temp);
1307 }
1308
1309 // Add and remove a document from the manager's list
1310 void wxDocManager::AddDocument(wxDocument *doc)
1311 {
1312 if (!m_docs.Member(doc))
1313 m_docs.Append(doc);
1314 }
1315
1316 void wxDocManager::RemoveDocument(wxDocument *doc)
1317 {
1318 m_docs.DeleteObject(doc);
1319 }
1320
1321 // Views or windows should inform the document manager
1322 // when a view is going in or out of focus
1323 void wxDocManager::ActivateView(wxView *view, bool activate, bool WXUNUSED(deleting))
1324 {
1325 // If we're deactiving, and if we're not actually deleting the view, then
1326 // don't reset the current view because we may be going to
1327 // a window without a view.
1328 // WHAT DID I MEAN BY THAT EXACTLY?
1329 /*
1330 if (deleting)
1331 {
1332 if (m_currentView == view)
1333 m_currentView = NULL;
1334 }
1335 else
1336 */
1337 {
1338 if (activate)
1339 m_currentView = view;
1340 else
1341 m_currentView = (wxView *) NULL;
1342 }
1343 }
1344
1345 // ----------------------------------------------------------------------------
1346 // Default document child frame
1347 // ----------------------------------------------------------------------------
1348
1349 BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame)
1350 EVT_ACTIVATE(wxDocChildFrame::OnActivate)
1351 EVT_CLOSE(wxDocChildFrame::OnCloseWindow)
1352 END_EVENT_TABLE()
1353
1354 wxDocChildFrame::wxDocChildFrame(wxDocument *doc,
1355 wxView *view,
1356 wxFrame *frame,
1357 wxWindowID id,
1358 const wxString& title,
1359 const wxPoint& pos,
1360 const wxSize& size,
1361 long style,
1362 const wxString& name)
1363 : wxFrame(frame, id, title, pos, size, style, name)
1364 {
1365 m_childDocument = doc;
1366 m_childView = view;
1367 if (view)
1368 view->SetFrame(this);
1369 }
1370
1371 wxDocChildFrame::~wxDocChildFrame()
1372 {
1373 }
1374
1375 // Extend event processing to search the view's event table
1376 bool wxDocChildFrame::ProcessEvent(wxEvent& event)
1377 {
1378 if (m_childView)
1379 m_childView->Activate(TRUE);
1380
1381 if ( !m_childView || ! m_childView->ProcessEvent(event) )
1382 {
1383 // Only hand up to the parent if it's a menu command
1384 if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event))
1385 return wxEvtHandler::ProcessEvent(event);
1386 else
1387 return TRUE;
1388 }
1389 else
1390 return TRUE;
1391 }
1392
1393 void wxDocChildFrame::OnActivate(wxActivateEvent& event)
1394 {
1395 wxFrame::OnActivate(event);
1396
1397 if (m_childView)
1398 m_childView->Activate(event.GetActive());
1399 }
1400
1401 void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event)
1402 {
1403 if (m_childView)
1404 {
1405 bool ans = FALSE;
1406 if (!event.CanVeto())
1407 ans = TRUE; // Must delete.
1408 else
1409 ans = m_childView->Close(FALSE); // FALSE means don't delete associated window
1410
1411 if (ans)
1412 {
1413 m_childView->Activate(FALSE);
1414 delete m_childView;
1415 m_childView = (wxView *) NULL;
1416 m_childDocument = (wxDocument *) NULL;
1417
1418 this->Destroy();
1419 }
1420 else
1421 event.Veto();
1422 }
1423 else
1424 event.Veto();
1425 }
1426
1427 // ----------------------------------------------------------------------------
1428 // Default parent frame
1429 // ----------------------------------------------------------------------------
1430
1431 BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame)
1432 EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit)
1433 EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile)
1434 EVT_CLOSE(wxDocParentFrame::OnCloseWindow)
1435 END_EVENT_TABLE()
1436
1437 wxDocParentFrame::wxDocParentFrame(wxDocManager *manager,
1438 wxFrame *frame,
1439 wxWindowID id,
1440 const wxString& title,
1441 const wxPoint& pos,
1442 const wxSize& size,
1443 long style,
1444 const wxString& name)
1445 : wxFrame(frame, id, title, pos, size, style, name)
1446 {
1447 m_docManager = manager;
1448 }
1449
1450 void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event))
1451 {
1452 Close();
1453 }
1454
1455 void wxDocParentFrame::OnMRUFile(wxCommandEvent& event)
1456 {
1457 wxString f(m_docManager->GetHistoryFile(event.GetSelection() - wxID_FILE1));
1458 if (f != _T(""))
1459 (void)m_docManager->CreateDocument(f, wxDOC_SILENT);
1460 }
1461
1462 // Extend event processing to search the view's event table
1463 bool wxDocParentFrame::ProcessEvent(wxEvent& event)
1464 {
1465 // Try the document manager, then do default processing
1466 if (!m_docManager || !m_docManager->ProcessEvent(event))
1467 return wxEvtHandler::ProcessEvent(event);
1468 else
1469 return TRUE;
1470 }
1471
1472 // Define the behaviour for the frame closing
1473 // - must delete all frames except for the main one.
1474 void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event)
1475 {
1476 if (m_docManager->Clear(!event.CanVeto()))
1477 {
1478 this->Destroy();
1479 }
1480 else
1481 event.Veto();
1482 }
1483
1484 #if wxUSE_PRINTING_ARCHITECTURE
1485
1486 wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title)
1487 : wxPrintout(WXSTRINGCAST title)
1488 {
1489 m_printoutView = view;
1490 }
1491
1492 bool wxDocPrintout::OnPrintPage(int WXUNUSED(page))
1493 {
1494 wxDC *dc = GetDC();
1495
1496 // Get the logical pixels per inch of screen and printer
1497 int ppiScreenX, ppiScreenY;
1498 GetPPIScreen(&ppiScreenX, &ppiScreenY);
1499 int ppiPrinterX, ppiPrinterY;
1500 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
1501
1502 // This scales the DC so that the printout roughly represents the
1503 // the screen scaling. The text point size _should_ be the right size
1504 // but in fact is too small for some reason. This is a detail that will
1505 // need to be addressed at some point but can be fudged for the
1506 // moment.
1507 float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
1508
1509 // Now we have to check in case our real page size is reduced
1510 // (e.g. because we're drawing to a print preview memory DC)
1511 int pageWidth, pageHeight;
1512 int w, h;
1513 dc->GetSize(&w, &h);
1514 GetPageSizePixels(&pageWidth, &pageHeight);
1515
1516 // If printer pageWidth == current DC width, then this doesn't
1517 // change. But w might be the preview bitmap width, so scale down.
1518 float overallScale = scale * (float)(w/(float)pageWidth);
1519 dc->SetUserScale(overallScale, overallScale);
1520
1521 if (m_printoutView)
1522 {
1523 m_printoutView->OnDraw(dc);
1524 }
1525 return TRUE;
1526 }
1527
1528 bool wxDocPrintout::HasPage(int pageNum)
1529 {
1530 return (pageNum == 1);
1531 }
1532
1533 bool wxDocPrintout::OnBeginDocument(int startPage, int endPage)
1534 {
1535 if (!wxPrintout::OnBeginDocument(startPage, endPage))
1536 return FALSE;
1537
1538 return TRUE;
1539 }
1540
1541 void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
1542 {
1543 *minPage = 1;
1544 *maxPage = 1;
1545 *selPageFrom = 1;
1546 *selPageTo = 1;
1547 }
1548
1549 #endif // wxUSE_PRINTING_ARCHITECTURE
1550
1551 // ----------------------------------------------------------------------------
1552 // Command processing framework
1553 // ----------------------------------------------------------------------------
1554
1555 wxCommand::wxCommand(bool canUndoIt, const wxString& name)
1556 {
1557 m_canUndo = canUndoIt;
1558 m_commandName = name;
1559 }
1560
1561 wxCommand::~wxCommand()
1562 {
1563 }
1564
1565 // Command processor
1566 wxCommandProcessor::wxCommandProcessor(int maxCommands)
1567 {
1568 m_maxNoCommands = maxCommands;
1569 m_currentCommand = (wxNode *) NULL;
1570 m_commandEditMenu = (wxMenu *) NULL;
1571 }
1572
1573 wxCommandProcessor::~wxCommandProcessor()
1574 {
1575 ClearCommands();
1576 }
1577
1578 // Pass a command to the processor. The processor calls Do();
1579 // if successful, is appended to the command history unless
1580 // storeIt is FALSE.
1581 bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt)
1582 {
1583 bool success = command->Do();
1584 if (success && storeIt)
1585 {
1586 if (m_commands.Number() == m_maxNoCommands)
1587 {
1588 wxNode *firstNode = m_commands.First();
1589 wxCommand *firstCommand = (wxCommand *)firstNode->Data();
1590 delete firstCommand;
1591 delete firstNode;
1592 }
1593
1594 // Correct a bug: we must chop off the current 'branch'
1595 // so that we're at the end of the command list.
1596 if (!m_currentCommand)
1597 ClearCommands();
1598 else
1599 {
1600 wxNode *node = m_currentCommand->Next();
1601 while (node)
1602 {
1603 wxNode *next = node->Next();
1604 delete (wxCommand *)node->Data();
1605 delete node;
1606 node = next;
1607 }
1608 }
1609
1610 m_commands.Append(command);
1611 m_currentCommand = m_commands.Last();
1612 SetMenuStrings();
1613 }
1614 return success;
1615 }
1616
1617 bool wxCommandProcessor::Undo()
1618 {
1619 if (m_currentCommand)
1620 {
1621 wxCommand *command = (wxCommand *)m_currentCommand->Data();
1622 if (command->CanUndo())
1623 {
1624 bool success = command->Undo();
1625 if (success)
1626 {
1627 m_currentCommand = m_currentCommand->Previous();
1628 SetMenuStrings();
1629 return TRUE;
1630 }
1631 }
1632 }
1633 return FALSE;
1634 }
1635
1636 bool wxCommandProcessor::Redo()
1637 {
1638 wxCommand *redoCommand = (wxCommand *) NULL;
1639 wxNode *redoNode = (wxNode *) NULL;
1640 if (m_currentCommand && m_currentCommand->Next())
1641 {
1642 redoCommand = (wxCommand *)m_currentCommand->Next()->Data();
1643 redoNode = m_currentCommand->Next();
1644 }
1645 else
1646 {
1647 if (m_commands.Number() > 0)
1648 {
1649 redoCommand = (wxCommand *)m_commands.First()->Data();
1650 redoNode = m_commands.First();
1651 }
1652 }
1653
1654 if (redoCommand)
1655 {
1656 bool success = redoCommand->Do();
1657 if (success)
1658 {
1659 m_currentCommand = redoNode;
1660 SetMenuStrings();
1661 return TRUE;
1662 }
1663 }
1664 return FALSE;
1665 }
1666
1667 bool wxCommandProcessor::CanUndo() const
1668 {
1669 if (m_currentCommand)
1670 return ((wxCommand *)m_currentCommand->Data())->CanUndo();
1671 return FALSE;
1672 }
1673
1674 bool wxCommandProcessor::CanRedo() const
1675 {
1676 if ((m_currentCommand != (wxNode*) NULL) && (m_currentCommand->Next() == (wxNode*) NULL))
1677 return FALSE;
1678
1679 if ((m_currentCommand != (wxNode*) NULL) && (m_currentCommand->Next() != (wxNode*) NULL))
1680 return TRUE;
1681
1682 if ((m_currentCommand == (wxNode*) NULL) && (m_commands.Number() > 0))
1683 return TRUE;
1684
1685 return FALSE;
1686 }
1687
1688 void wxCommandProcessor::Initialize()
1689 {
1690 m_currentCommand = m_commands.Last();
1691 SetMenuStrings();
1692 }
1693
1694 void wxCommandProcessor::SetMenuStrings()
1695 {
1696 if (m_commandEditMenu)
1697 {
1698 wxString buf;
1699 if (m_currentCommand)
1700 {
1701 wxCommand *command = (wxCommand *)m_currentCommand->Data();
1702 wxString commandName(command->GetName());
1703 if (commandName == _T("")) commandName = _("Unnamed command");
1704 bool canUndo = command->CanUndo();
1705 if (canUndo)
1706 buf = wxString(_("&Undo ")) + commandName;
1707 else
1708 buf = wxString(_("Can't &Undo ")) + commandName;
1709
1710 m_commandEditMenu->SetLabel(wxID_UNDO, buf);
1711 m_commandEditMenu->Enable(wxID_UNDO, canUndo);
1712
1713 // We can redo, if we're not at the end of the history.
1714 if (m_currentCommand->Next())
1715 {
1716 wxCommand *redoCommand = (wxCommand *)m_currentCommand->Next()->Data();
1717 wxString redoCommandName(redoCommand->GetName());
1718 if (redoCommandName == _T("")) redoCommandName = _("Unnamed command");
1719 buf = wxString(_("&Redo ")) + redoCommandName;
1720 m_commandEditMenu->SetLabel(wxID_REDO, buf);
1721 m_commandEditMenu->Enable(wxID_REDO, TRUE);
1722 }
1723 else
1724 {
1725 m_commandEditMenu->SetLabel(wxID_REDO, _("&Redo"));
1726 m_commandEditMenu->Enable(wxID_REDO, FALSE);
1727 }
1728 }
1729 else
1730 {
1731 m_commandEditMenu->SetLabel(wxID_UNDO, _("&Undo"));
1732 m_commandEditMenu->Enable(wxID_UNDO, FALSE);
1733
1734 if (m_commands.Number() == 0)
1735 {
1736 m_commandEditMenu->SetLabel(wxID_REDO, _("&Redo"));
1737 m_commandEditMenu->Enable(wxID_REDO, FALSE);
1738 }
1739 else
1740 {
1741 // currentCommand is NULL but there are commands: this means that
1742 // we've undone to the start of the list, but can redo the first.
1743 wxCommand *redoCommand = (wxCommand *)m_commands.First()->Data();
1744 wxString redoCommandName(redoCommand->GetName());
1745 if (redoCommandName == _T("")) redoCommandName = _("Unnamed command");
1746 buf = wxString(_("&Redo ")) + redoCommandName;
1747 m_commandEditMenu->SetLabel(wxID_REDO, buf);
1748 m_commandEditMenu->Enable(wxID_REDO, TRUE);
1749 }
1750 }
1751 }
1752 }
1753
1754 void wxCommandProcessor::ClearCommands()
1755 {
1756 wxNode *node = m_commands.First();
1757 while (node)
1758 {
1759 wxCommand *command = (wxCommand *)node->Data();
1760 delete command;
1761 delete node;
1762 node = m_commands.First();
1763 }
1764 m_currentCommand = (wxNode *) NULL;
1765 }
1766
1767 // ----------------------------------------------------------------------------
1768 // File history processor
1769 // ----------------------------------------------------------------------------
1770
1771 wxFileHistory::wxFileHistory(int maxFiles)
1772 {
1773 m_fileMaxFiles = maxFiles;
1774 m_fileHistoryN = 0;
1775 m_fileHistory = new wxChar *[m_fileMaxFiles];
1776 }
1777
1778 wxFileHistory::~wxFileHistory()
1779 {
1780 int i;
1781 for (i = 0; i < m_fileHistoryN; i++)
1782 delete[] m_fileHistory[i];
1783 delete[] m_fileHistory;
1784 }
1785
1786 // File history management
1787 void wxFileHistory::AddFileToHistory(const wxString& file)
1788 {
1789 int i;
1790 // Check we don't already have this file
1791 for (i = 0; i < m_fileHistoryN; i++)
1792 {
1793 if (m_fileHistory[i] && wxString(m_fileHistory[i]) == file)
1794 return;
1795 }
1796
1797 // Add to the project file history:
1798 // Move existing files (if any) down so we can insert file at beginning.
1799
1800 // First delete filename that has popped off the end of the array (if any)
1801 if (m_fileHistoryN == m_fileMaxFiles)
1802 {
1803 delete[] m_fileHistory[m_fileMaxFiles-1];
1804 m_fileHistory[m_fileMaxFiles-1] = (wxChar *) NULL;
1805 }
1806 if (m_fileHistoryN < m_fileMaxFiles)
1807 {
1808 wxNode* node = m_fileMenus.First();
1809 while (node)
1810 {
1811 wxMenu* menu = (wxMenu*) node->Data();
1812 if (m_fileHistoryN == 0)
1813 menu->AppendSeparator();
1814 menu->Append(wxID_FILE1+m_fileHistoryN, _("[EMPTY]"));
1815 node = node->Next();
1816 }
1817 m_fileHistoryN ++;
1818 }
1819 // Shuffle filenames down
1820 for (i = (m_fileHistoryN-1); i > 0; i--)
1821 {
1822 m_fileHistory[i] = m_fileHistory[i-1];
1823 }
1824 m_fileHistory[0] = copystring(file);
1825
1826 for (i = 0; i < m_fileHistoryN; i++)
1827 if (m_fileHistory[i])
1828 {
1829 wxString buf;
1830 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
1831 wxNode* node = m_fileMenus.First();
1832 while (node)
1833 {
1834 wxMenu* menu = (wxMenu*) node->Data();
1835 menu->SetLabel(wxID_FILE1+i, buf);
1836 node = node->Next();
1837 }
1838 }
1839 }
1840
1841 wxString wxFileHistory::GetHistoryFile(int i) const
1842 {
1843 if (i < m_fileHistoryN)
1844 return wxString(m_fileHistory[i]);
1845 else
1846 return wxString("");
1847 }
1848
1849 void wxFileHistory::UseMenu(wxMenu *menu)
1850 {
1851 if (!m_fileMenus.Member(menu))
1852 m_fileMenus.Append(menu);
1853 }
1854
1855 void wxFileHistory::RemoveMenu(wxMenu *menu)
1856 {
1857 m_fileMenus.DeleteObject(menu);
1858 }
1859
1860 #if wxUSE_CONFIG
1861 void wxFileHistory::Load(wxConfigBase& config)
1862 {
1863 m_fileHistoryN = 0;
1864 wxString buf;
1865 buf.Printf(_T("file%d"), m_fileHistoryN+1);
1866 wxString historyFile;
1867 while ((m_fileHistoryN <= m_fileMaxFiles) && config.Read(buf, &historyFile) && (historyFile != _T("")))
1868 {
1869 m_fileHistory[m_fileHistoryN] = copystring((const wxChar*) historyFile);
1870 m_fileHistoryN ++;
1871 buf.Printf(_T("file%d"), m_fileHistoryN+1);
1872 historyFile = "";
1873 }
1874 AddFilesToMenu();
1875 }
1876
1877 void wxFileHistory::Save(wxConfigBase& config)
1878 {
1879 int i;
1880 for (i = 0; i < m_fileHistoryN; i++)
1881 {
1882 wxString buf;
1883 buf.Printf(_T("file%d"), i+1);
1884 config.Write(buf, wxString(m_fileHistory[i]));
1885 }
1886 }
1887 #endif // wxUSE_CONFIG
1888
1889 void wxFileHistory::AddFilesToMenu()
1890 {
1891 if (m_fileHistoryN > 0)
1892 {
1893 wxNode* node = m_fileMenus.First();
1894 while (node)
1895 {
1896 wxMenu* menu = (wxMenu*) node->Data();
1897 menu->AppendSeparator();
1898 int i;
1899 for (i = 0; i < m_fileHistoryN; i++)
1900 {
1901 if (m_fileHistory[i])
1902 {
1903 wxString buf;
1904 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
1905 menu->Append(wxID_FILE1+i, buf);
1906 }
1907 }
1908 node = node->Next();
1909 }
1910 }
1911 }
1912
1913 void wxFileHistory::AddFilesToMenu(wxMenu* menu)
1914 {
1915 if (m_fileHistoryN > 0)
1916 {
1917 menu->AppendSeparator();
1918 int i;
1919 for (i = 0; i < m_fileHistoryN; i++)
1920 {
1921 if (m_fileHistory[i])
1922 {
1923 wxString buf;
1924 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
1925 menu->Append(wxID_FILE1+i, buf);
1926 }
1927 }
1928 }
1929 }
1930
1931 // ----------------------------------------------------------------------------
1932 // Permits compatibility with existing file formats and functions that
1933 // manipulate files directly
1934 // ----------------------------------------------------------------------------
1935
1936 bool wxTransferFileToStream(const wxString& filename, ostream& stream)
1937 {
1938 FILE *fd1;
1939 int ch;
1940
1941 if ((fd1 = fopen (filename.fn_str(), "rb")) == NULL)
1942 return FALSE;
1943
1944 while ((ch = getc (fd1)) != EOF)
1945 stream << (unsigned char)ch;
1946
1947 fclose (fd1);
1948 return TRUE;
1949 }
1950
1951 bool wxTransferStreamToFile(istream& stream, const wxString& filename)
1952 {
1953 FILE *fd1;
1954 int ch;
1955
1956 if ((fd1 = fopen (filename.fn_str(), "wb")) == NULL)
1957 {
1958 return FALSE;
1959 }
1960
1961 while (!stream.eof())
1962 {
1963 ch = stream.get();
1964 if (!stream.eof())
1965 putc (ch, fd1);
1966 }
1967 fclose (fd1);
1968 return TRUE;
1969 }
1970
1971 #endif // wxUSE_DOC_VIEW_ARCHITECTURE
1972