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