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