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