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