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