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