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