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