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