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