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