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