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