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