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