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