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