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