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