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