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