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