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