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