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