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