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