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