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