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