1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/docview.cpp
3 // Purpose: Document/view classes
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #if wxUSE_DOC_VIEW_ARCHITECTURE
29 #include "wx/docview.h"
33 #include "wx/string.h"
37 #include "wx/dialog.h"
39 #include "wx/filedlg.h"
42 #include "wx/msgdlg.h"
44 #include "wx/choicdlg.h"
47 #if wxUSE_PRINTING_ARCHITECTURE
48 #include "wx/prntbase.h"
49 #include "wx/printdlg.h"
52 #include "wx/confbase.h"
53 #include "wx/filename.h"
56 #include "wx/cmdproc.h"
57 #include "wx/tokenzr.h"
58 #include "wx/filename.h"
59 #include "wx/stdpaths.h"
60 #include "wx/vector.h"
61 #include "wx/scopedarray.h"
62 #include "wx/scopedptr.h"
63 #include "wx/except.h"
65 #if wxUSE_STD_IOSTREAM
66 #include "wx/ioswrap.h"
67 #include "wx/beforestd.h"
73 #include "wx/afterstd.h"
75 #include "wx/wfstream.h"
78 typedef wxVector
<wxDocTemplate
*> wxDocTemplates
;
80 // ----------------------------------------------------------------------------
82 // ----------------------------------------------------------------------------
84 IMPLEMENT_ABSTRACT_CLASS(wxDocument
, wxEvtHandler
)
85 IMPLEMENT_ABSTRACT_CLASS(wxView
, wxEvtHandler
)
86 IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate
, wxObject
)
87 IMPLEMENT_DYNAMIC_CLASS(wxDocManager
, wxEvtHandler
)
88 IMPLEMENT_CLASS(wxDocChildFrame
, wxFrame
)
89 IMPLEMENT_CLASS(wxDocParentFrame
, wxFrame
)
91 #if wxUSE_PRINTING_ARCHITECTURE
92 IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout
, wxPrintout
)
95 IMPLEMENT_DYNAMIC_CLASS(wxFileHistory
, wxObject
)
97 // ============================================================================
99 // ============================================================================
101 // ----------------------------------------------------------------------------
103 // ----------------------------------------------------------------------------
108 wxWindow
*wxFindSuitableParent()
110 wxWindow
* const win
= wxGetTopLevelParent(wxWindow::FindFocus());
112 return win
? win
: wxTheApp
->GetTopWindow();
115 wxString
FindExtension(const wxString
& path
)
118 wxFileName::SplitPath(path
, NULL
, NULL
, &ext
);
120 // VZ: extensions are considered not case sensitive - is this really a good
122 return ext
.MakeLower();
125 // return the string used for the MRU list items in the menu
127 // NB: the index n is 0-based, as usual, but the strings start from 1
128 wxString
GetMRUEntryLabel(int n
, const wxString
& path
)
130 // we need to quote '&' characters which are used for mnemonics
131 wxString
pathInMenu(path
);
132 pathInMenu
.Replace("&", "&&");
134 return wxString::Format("&%d %s", n
+ 1, pathInMenu
);
137 } // anonymous namespace
139 // ----------------------------------------------------------------------------
140 // Definition of wxDocument
141 // ----------------------------------------------------------------------------
143 wxDocument::wxDocument(wxDocument
*parent
)
145 m_documentModified
= false;
146 m_documentParent
= parent
;
147 m_documentTemplate
= NULL
;
148 m_commandProcessor
= NULL
;
152 bool wxDocument::DeleteContents()
157 wxDocument::~wxDocument()
161 delete m_commandProcessor
;
163 if (GetDocumentManager())
164 GetDocumentManager()->RemoveDocument(this);
166 // Not safe to do here, since it'll invoke virtual view functions
167 // expecting to see valid derived objects: and by the time we get here,
168 // we've called destructors higher up.
172 bool wxDocument::Close()
174 if ( !OnSaveModified() )
177 return OnCloseDocument();
180 bool wxDocument::OnCloseDocument()
182 // Tell all views that we're about to close
189 // Note that this implicitly deletes the document when the last view is
191 bool wxDocument::DeleteAllViews()
193 wxDocManager
* manager
= GetDocumentManager();
195 // first check if all views agree to be closed
196 const wxList::iterator end
= m_documentViews
.end();
197 for ( wxList::iterator i
= m_documentViews
.begin(); i
!= end
; ++i
)
199 wxView
*view
= (wxView
*)*i
;
200 if ( !view
->Close() )
204 // all views agreed to close, now do close them
205 if ( m_documentViews
.empty() )
207 // normally the document would be implicitly deleted when the last view
208 // is, but if don't have any views, do it here instead
209 if ( manager
&& manager
->GetDocuments().Member(this) )
214 // as we delete elements we iterate over, don't use the usual "from
215 // begin to end" loop
218 wxView
*view
= (wxView
*)*m_documentViews
.begin();
220 bool isLastOne
= m_documentViews
.size() == 1;
222 // this always deletes the node implicitly and if this is the last
223 // view also deletes this object itself (also implicitly, great),
224 // so we can't test for m_documentViews.empty() after calling this!
235 wxView
*wxDocument::GetFirstView() const
237 if ( m_documentViews
.empty() )
240 return static_cast<wxView
*>(m_documentViews
.GetFirst()->GetData());
243 wxDocManager
*wxDocument::GetDocumentManager() const
245 return m_documentTemplate
? m_documentTemplate
->GetDocumentManager() : NULL
;
248 bool wxDocument::OnNewDocument()
250 // notice that there is no need to neither reset nor even check the
251 // modified flag here as the document itself is a new object (this is only
252 // called from CreateDocument()) and so it shouldn't be saved anyhow even
253 // if it is modified -- this could happen if the user code creates
254 // documents pre-filled with some user-entered (and which hence must not be
257 SetDocumentSaved(false);
259 const wxString name
= GetDocumentManager()->MakeNewDocumentName();
261 SetFilename(name
, true);
266 bool wxDocument::Save()
268 if ( AlreadySaved() )
271 if ( m_documentFile
.empty() || !m_savedYet
)
274 return OnSaveDocument(m_documentFile
);
277 bool wxDocument::SaveAs()
279 wxDocTemplate
*docTemplate
= GetDocumentTemplate();
283 #ifdef wxHAS_MULTIPLE_FILEDLG_FILTERS
284 wxString filter
= docTemplate
->GetDescription() + wxT(" (") +
285 docTemplate
->GetFileFilter() + wxT(")|") +
286 docTemplate
->GetFileFilter();
288 // Now see if there are some other template with identical view and document
289 // classes, whose filters may also be used.
290 if (docTemplate
->GetViewClassInfo() && docTemplate
->GetDocClassInfo())
292 wxList::compatibility_iterator
293 node
= docTemplate
->GetDocumentManager()->GetTemplates().GetFirst();
296 wxDocTemplate
*t
= (wxDocTemplate
*) node
->GetData();
298 if (t
->IsVisible() && t
!= docTemplate
&&
299 t
->GetViewClassInfo() == docTemplate
->GetViewClassInfo() &&
300 t
->GetDocClassInfo() == docTemplate
->GetDocClassInfo())
302 // add a '|' to separate this filter from the previous one
303 if ( !filter
.empty() )
306 filter
<< t
->GetDescription()
307 << wxT(" (") << t
->GetFileFilter() << wxT(") |")
308 << t
->GetFileFilter();
311 node
= node
->GetNext();
315 wxString filter
= docTemplate
->GetFileFilter() ;
318 wxString defaultDir
= docTemplate
->GetDirectory();
319 if ( defaultDir
.empty() )
321 defaultDir
= wxPathOnly(GetFilename());
322 if ( defaultDir
.empty() )
323 defaultDir
= GetDocumentManager()->GetLastDirectory();
326 wxString fileName
= wxFileSelector(_("Save As"),
328 wxFileNameFromPath(GetFilename()),
329 docTemplate
->GetDefaultExtension(),
331 wxFD_SAVE
| wxFD_OVERWRITE_PROMPT
,
332 GetDocumentWindow());
334 if (fileName
.empty())
335 return false; // cancelled by user
338 wxFileName::SplitPath(fileName
, NULL
, NULL
, &ext
);
342 fileName
+= wxT(".");
343 fileName
+= docTemplate
->GetDefaultExtension();
346 // Files that were not saved correctly are not added to the FileHistory.
347 if (!OnSaveDocument(fileName
))
350 SetTitle(wxFileNameFromPath(fileName
));
351 SetFilename(fileName
, true); // will call OnChangeFileName automatically
353 // A file that doesn't use the default extension of its document template
354 // cannot be opened via the FileHistory, so we do not add it.
355 if (docTemplate
->FileMatchesTemplate(fileName
))
357 GetDocumentManager()->AddFileToHistory(fileName
);
359 //else: the user will probably not be able to open the file again, so we
360 // could warn about the wrong file-extension here
365 bool wxDocument::OnSaveDocument(const wxString
& file
)
370 if ( !DoSaveDocument(file
) )
375 SetDocumentSaved(true);
376 #if defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON
377 wxFileName
fn(file
) ;
378 fn
.MacSetDefaultTypeAndCreator() ;
383 bool wxDocument::OnOpenDocument(const wxString
& file
)
385 // notice that there is no need to check the modified flag here for the
386 // reasons explained in OnNewDocument()
388 if ( !DoOpenDocument(file
) )
391 SetFilename(file
, true);
393 // stretching the logic a little this does make sense because the document
394 // had been saved into the file we just loaded it from, it just could have
395 // happened during a previous program execution, it's just that the name of
396 // this method is a bit unfortunate, it should probably have been called
397 // HasAssociatedFileName()
398 SetDocumentSaved(true);
405 #if wxUSE_STD_IOSTREAM
406 wxSTD istream
& wxDocument::LoadObject(wxSTD istream
& stream
)
408 wxInputStream
& wxDocument::LoadObject(wxInputStream
& stream
)
414 #if wxUSE_STD_IOSTREAM
415 wxSTD ostream
& wxDocument::SaveObject(wxSTD ostream
& stream
)
417 wxOutputStream
& wxDocument::SaveObject(wxOutputStream
& stream
)
423 bool wxDocument::Revert()
429 // Get title, or filename if no title, else unnamed
430 #if WXWIN_COMPATIBILITY_2_8
431 bool wxDocument::GetPrintableName(wxString
& buf
) const
433 // this function can not only be overridden by the user code but also
434 // called by it so we need to ensure that we return the same thing as
435 // GetUserReadableName() but we can't call it because this would result in
436 // an infinite recursion, hence we use the helper DoGetUserReadableName()
437 buf
= DoGetUserReadableName();
441 #endif // WXWIN_COMPATIBILITY_2_8
443 wxString
wxDocument::GetUserReadableName() const
445 #if WXWIN_COMPATIBILITY_2_8
446 // we need to call the old virtual function to ensure that the overridden
447 // version of it is still called
449 if ( GetPrintableName(name
) )
451 #endif // WXWIN_COMPATIBILITY_2_8
453 return DoGetUserReadableName();
456 wxString
wxDocument::DoGetUserReadableName() const
458 if ( !m_documentTitle
.empty() )
459 return m_documentTitle
;
461 if ( !m_documentFile
.empty() )
462 return wxFileNameFromPath(m_documentFile
);
467 wxWindow
*wxDocument::GetDocumentWindow() const
469 wxView
* const view
= GetFirstView();
471 return view
? view
->GetFrame() : wxTheApp
->GetTopWindow();
474 wxCommandProcessor
*wxDocument::OnCreateCommandProcessor()
476 return new wxCommandProcessor
;
479 // true if safe to close
480 bool wxDocument::OnSaveModified()
484 switch ( wxMessageBox
488 _("Do you want to save changes to %s?"),
489 GetUserReadableName()
491 wxTheApp
->GetAppDisplayName(),
492 wxYES_NO
| wxCANCEL
| wxICON_QUESTION
| wxCENTRE
,
493 wxFindSuitableParent()
511 bool wxDocument::Draw(wxDC
& WXUNUSED(context
))
516 bool wxDocument::AddView(wxView
*view
)
518 if ( !m_documentViews
.Member(view
) )
520 m_documentViews
.Append(view
);
526 bool wxDocument::RemoveView(wxView
*view
)
528 (void)m_documentViews
.DeleteObject(view
);
533 bool wxDocument::OnCreate(const wxString
& WXUNUSED(path
), long flags
)
535 return GetDocumentTemplate()->CreateView(this, flags
) != NULL
;
538 // Called after a view is added or removed.
539 // The default implementation deletes the document if
540 // there are no more views.
541 void wxDocument::OnChangedViewList()
543 if ( m_documentViews
.empty() && OnSaveModified() )
547 void wxDocument::UpdateAllViews(wxView
*sender
, wxObject
*hint
)
549 wxList::compatibility_iterator node
= m_documentViews
.GetFirst();
552 wxView
*view
= (wxView
*)node
->GetData();
554 view
->OnUpdate(sender
, hint
);
555 node
= node
->GetNext();
559 void wxDocument::NotifyClosing()
561 wxList::compatibility_iterator node
= m_documentViews
.GetFirst();
564 wxView
*view
= (wxView
*)node
->GetData();
565 view
->OnClosingDocument();
566 node
= node
->GetNext();
570 void wxDocument::SetFilename(const wxString
& filename
, bool notifyViews
)
572 m_documentFile
= filename
;
573 OnChangeFilename(notifyViews
);
576 void wxDocument::OnChangeFilename(bool notifyViews
)
580 // Notify the views that the filename has changed
581 wxList::compatibility_iterator node
= m_documentViews
.GetFirst();
584 wxView
*view
= (wxView
*)node
->GetData();
585 view
->OnChangeFilename();
586 node
= node
->GetNext();
591 bool wxDocument::DoSaveDocument(const wxString
& file
)
593 #if wxUSE_STD_IOSTREAM
594 wxSTD ofstream
store(file
.mb_str(), wxSTD
ios::binary
);
597 wxFileOutputStream
store(file
);
598 if ( store
.GetLastError() != wxSTREAM_NO_ERROR
)
601 wxLogError(_("File \"%s\" could not be opened for writing."), file
);
605 if (!SaveObject(store
))
607 wxLogError(_("Failed to save document to the file \"%s\"."), file
);
614 bool wxDocument::DoOpenDocument(const wxString
& file
)
616 #if wxUSE_STD_IOSTREAM
617 wxSTD ifstream
store(file
.mb_str(), wxSTD
ios::binary
);
620 wxFileInputStream
store(file
);
621 if (store
.GetLastError() != wxSTREAM_NO_ERROR
|| !store
.IsOk())
624 wxLogError(_("File \"%s\" could not be opened for reading."), file
);
628 #if wxUSE_STD_IOSTREAM
632 int res
= LoadObject(store
).GetLastError();
633 if ( res
!= wxSTREAM_NO_ERROR
&& res
!= wxSTREAM_EOF
)
636 wxLogError(_("Failed to read document from the file \"%s\"."), file
);
644 // ----------------------------------------------------------------------------
646 // ----------------------------------------------------------------------------
650 m_viewDocument
= NULL
;
654 m_docChildFrame
= NULL
;
659 GetDocumentManager()->ActivateView(this, false);
661 // reset our frame view first, before removing it from the document as
662 // SetView(NULL) is a simple call while RemoveView() may result in user
663 // code being executed and this user code can, for example, show a message
664 // box which would result in an activation event for m_docChildFrame and so
665 // could reactivate the view being destroyed -- unless we reset it first
666 if ( m_docChildFrame
&& m_docChildFrame
->GetView() == this )
667 m_docChildFrame
->SetView(NULL
);
669 if ( m_viewDocument
)
670 m_viewDocument
->RemoveView(this);
673 bool wxView::TryBefore(wxEvent
& event
)
675 wxDocument
* const doc
= GetDocument();
676 return doc
&& doc
->ProcessEventHere(event
);
679 void wxView::OnActivateView(bool WXUNUSED(activate
),
680 wxView
*WXUNUSED(activeView
),
681 wxView
*WXUNUSED(deactiveView
))
685 void wxView::OnPrint(wxDC
*dc
, wxObject
*WXUNUSED(info
))
690 void wxView::OnUpdate(wxView
*WXUNUSED(sender
), wxObject
*WXUNUSED(hint
))
694 void wxView::OnChangeFilename()
696 // GetFrame can return wxWindow rather than wxTopLevelWindow due to
697 // generic MDI implementation so use SetLabel rather than SetTitle.
698 // It should cause SetTitle() for top level windows.
699 wxWindow
*win
= GetFrame();
702 wxDocument
*doc
= GetDocument();
705 win
->SetLabel(doc
->GetUserReadableName());
708 void wxView::SetDocument(wxDocument
*doc
)
710 m_viewDocument
= doc
;
715 bool wxView::Close(bool deleteWindow
)
717 return OnClose(deleteWindow
);
720 void wxView::Activate(bool activate
)
722 if (GetDocument() && GetDocumentManager())
724 OnActivateView(activate
, this, GetDocumentManager()->GetCurrentView());
725 GetDocumentManager()->ActivateView(this, activate
);
729 bool wxView::OnClose(bool WXUNUSED(deleteWindow
))
731 return GetDocument() ? GetDocument()->Close() : true;
734 #if wxUSE_PRINTING_ARCHITECTURE
735 wxPrintout
*wxView::OnCreatePrintout()
737 return new wxDocPrintout(this);
739 #endif // wxUSE_PRINTING_ARCHITECTURE
741 // ----------------------------------------------------------------------------
743 // ----------------------------------------------------------------------------
745 wxDocTemplate::wxDocTemplate(wxDocManager
*manager
,
746 const wxString
& descr
,
747 const wxString
& filter
,
750 const wxString
& docTypeName
,
751 const wxString
& viewTypeName
,
752 wxClassInfo
*docClassInfo
,
753 wxClassInfo
*viewClassInfo
,
756 m_documentManager
= manager
;
757 m_description
= descr
;
760 m_fileFilter
= filter
;
762 m_docTypeName
= docTypeName
;
763 m_viewTypeName
= viewTypeName
;
764 m_documentManager
->AssociateTemplate(this);
766 m_docClassInfo
= docClassInfo
;
767 m_viewClassInfo
= viewClassInfo
;
770 wxDocTemplate::~wxDocTemplate()
772 m_documentManager
->DisassociateTemplate(this);
775 // Tries to dynamically construct an object of the right class.
776 wxDocument
*wxDocTemplate::CreateDocument(const wxString
& path
, long flags
)
778 // InitDocument() is supposed to delete the document object if its
779 // initialization fails so don't use wxScopedPtr<> here: this is fragile
780 // but unavoidable because the default implementation uses CreateView()
781 // which may -- or not -- create a wxView and if it does create it and its
782 // initialization fails then the view destructor will delete the document
783 // (via RemoveView()) and as we can't distinguish between the two cases we
784 // just have to assume that it always deletes it in case of failure
785 wxDocument
* const doc
= DoCreateDocument();
787 return doc
&& InitDocument(doc
, path
, flags
) ? doc
: NULL
;
791 wxDocTemplate::InitDocument(wxDocument
* doc
, const wxString
& path
, long flags
)
793 doc
->SetFilename(path
);
794 doc
->SetDocumentTemplate(this);
795 GetDocumentManager()->AddDocument(doc
);
796 doc
->SetCommandProcessor(doc
->OnCreateCommandProcessor());
798 if (doc
->OnCreate(path
, flags
))
801 if (GetDocumentManager()->GetDocuments().Member(doc
))
802 doc
->DeleteAllViews();
806 wxView
*wxDocTemplate::CreateView(wxDocument
*doc
, long flags
)
808 wxScopedPtr
<wxView
> view(DoCreateView());
812 view
->SetDocument(doc
);
813 if ( !view
->OnCreate(doc
, flags
) )
816 return view
.release();
819 // The default (very primitive) format detection: check is the extension is
820 // that of the template
821 bool wxDocTemplate::FileMatchesTemplate(const wxString
& path
)
823 wxStringTokenizer
parser (GetFileFilter(), wxT(";"));
824 wxString anything
= wxT ("*");
825 while (parser
.HasMoreTokens())
827 wxString filter
= parser
.GetNextToken();
828 wxString filterExt
= FindExtension (filter
);
829 if ( filter
.IsSameAs (anything
) ||
830 filterExt
.IsSameAs (anything
) ||
831 filterExt
.IsSameAs (FindExtension (path
)) )
834 return GetDefaultExtension().IsSameAs(FindExtension(path
));
837 wxDocument
*wxDocTemplate::DoCreateDocument()
842 return static_cast<wxDocument
*>(m_docClassInfo
->CreateObject());
845 wxView
*wxDocTemplate::DoCreateView()
847 if (!m_viewClassInfo
)
850 return static_cast<wxView
*>(m_viewClassInfo
->CreateObject());
853 // ----------------------------------------------------------------------------
855 // ----------------------------------------------------------------------------
857 BEGIN_EVENT_TABLE(wxDocManager
, wxEvtHandler
)
858 EVT_MENU(wxID_OPEN
, wxDocManager::OnFileOpen
)
859 EVT_MENU(wxID_CLOSE
, wxDocManager::OnFileClose
)
860 EVT_MENU(wxID_CLOSE_ALL
, wxDocManager::OnFileCloseAll
)
861 EVT_MENU(wxID_REVERT
, wxDocManager::OnFileRevert
)
862 EVT_MENU(wxID_NEW
, wxDocManager::OnFileNew
)
863 EVT_MENU(wxID_SAVE
, wxDocManager::OnFileSave
)
864 EVT_MENU(wxID_SAVEAS
, wxDocManager::OnFileSaveAs
)
865 EVT_MENU(wxID_UNDO
, wxDocManager::OnUndo
)
866 EVT_MENU(wxID_REDO
, wxDocManager::OnRedo
)
868 EVT_UPDATE_UI(wxID_OPEN
, wxDocManager::OnUpdateFileOpen
)
869 EVT_UPDATE_UI(wxID_CLOSE
, wxDocManager::OnUpdateDisableIfNoDoc
)
870 EVT_UPDATE_UI(wxID_CLOSE_ALL
, wxDocManager::OnUpdateDisableIfNoDoc
)
871 EVT_UPDATE_UI(wxID_REVERT
, wxDocManager::OnUpdateDisableIfNoDoc
)
872 EVT_UPDATE_UI(wxID_NEW
, wxDocManager::OnUpdateFileNew
)
873 EVT_UPDATE_UI(wxID_SAVE
, wxDocManager::OnUpdateFileSave
)
874 EVT_UPDATE_UI(wxID_SAVEAS
, wxDocManager::OnUpdateDisableIfNoDoc
)
875 EVT_UPDATE_UI(wxID_UNDO
, wxDocManager::OnUpdateUndo
)
876 EVT_UPDATE_UI(wxID_REDO
, wxDocManager::OnUpdateRedo
)
878 #if wxUSE_PRINTING_ARCHITECTURE
879 EVT_MENU(wxID_PRINT
, wxDocManager::OnPrint
)
880 EVT_MENU(wxID_PREVIEW
, wxDocManager::OnPreview
)
882 EVT_UPDATE_UI(wxID_PRINT
, wxDocManager::OnUpdateDisableIfNoDoc
)
883 EVT_UPDATE_UI(wxID_PREVIEW
, wxDocManager::OnUpdateDisableIfNoDoc
)
887 wxDocManager
* wxDocManager::sm_docManager
= NULL
;
889 wxDocManager::wxDocManager(long WXUNUSED(flags
), bool initialize
)
891 wxASSERT_MSG( !sm_docManager
, "multiple wxDocManagers not allowed" );
893 sm_docManager
= this;
895 m_defaultDocumentNameCounter
= 1;
896 m_currentView
= NULL
;
897 m_maxDocsOpen
= INT_MAX
;
898 m_fileHistory
= NULL
;
903 wxDocManager::~wxDocManager()
906 delete m_fileHistory
;
907 sm_docManager
= NULL
;
910 // closes the specified document
911 bool wxDocManager::CloseDocument(wxDocument
* doc
, bool force
)
913 if ( !doc
->Close() && !force
)
916 // Implicitly deletes the document when
917 // the last view is deleted
918 doc
->DeleteAllViews();
920 // Check we're really deleted
921 if (m_docs
.Member(doc
))
927 bool wxDocManager::CloseDocuments(bool force
)
929 wxList::compatibility_iterator node
= m_docs
.GetFirst();
932 wxDocument
*doc
= (wxDocument
*)node
->GetData();
933 wxList::compatibility_iterator next
= node
->GetNext();
935 if (!CloseDocument(doc
, force
))
938 // This assumes that documents are not connected in
939 // any way, i.e. deleting one document does NOT
946 bool wxDocManager::Clear(bool force
)
948 if (!CloseDocuments(force
))
951 m_currentView
= NULL
;
953 wxList::compatibility_iterator node
= m_templates
.GetFirst();
956 wxDocTemplate
*templ
= (wxDocTemplate
*) node
->GetData();
957 wxList::compatibility_iterator next
= node
->GetNext();
964 bool wxDocManager::Initialize()
966 m_fileHistory
= OnCreateFileHistory();
970 wxString
wxDocManager::GetLastDirectory() const
972 // use the system-dependent default location for the document files if
973 // we're being opened for the first time
974 if ( m_lastDirectory
.empty() )
976 wxDocManager
* const self
= const_cast<wxDocManager
*>(this);
977 self
->m_lastDirectory
= wxStandardPaths::Get().GetAppDocumentsDir();
980 return m_lastDirectory
;
983 wxFileHistory
*wxDocManager::OnCreateFileHistory()
985 return new wxFileHistory
;
988 void wxDocManager::OnFileClose(wxCommandEvent
& WXUNUSED(event
))
990 wxDocument
*doc
= GetCurrentDocument();
995 doc
->DeleteAllViews();
996 if (m_docs
.Member(doc
))
1001 void wxDocManager::OnFileCloseAll(wxCommandEvent
& WXUNUSED(event
))
1003 CloseDocuments(false);
1006 void wxDocManager::OnFileNew(wxCommandEvent
& WXUNUSED(event
))
1008 CreateNewDocument();
1011 void wxDocManager::OnFileOpen(wxCommandEvent
& WXUNUSED(event
))
1013 if ( !CreateDocument("") )
1015 OnOpenFileFailure();
1019 void wxDocManager::OnFileRevert(wxCommandEvent
& WXUNUSED(event
))
1021 wxDocument
*doc
= GetCurrentDocument();
1027 void wxDocManager::OnFileSave(wxCommandEvent
& WXUNUSED(event
))
1029 wxDocument
*doc
= GetCurrentDocument();
1035 void wxDocManager::OnFileSaveAs(wxCommandEvent
& WXUNUSED(event
))
1037 wxDocument
*doc
= GetCurrentDocument();
1043 void wxDocManager::OnPrint(wxCommandEvent
& WXUNUSED(event
))
1045 #if wxUSE_PRINTING_ARCHITECTURE
1046 wxView
*view
= GetActiveView();
1050 wxPrintout
*printout
= view
->OnCreatePrintout();
1054 printer
.Print(view
->GetFrame(), printout
, true);
1058 #endif // wxUSE_PRINTING_ARCHITECTURE
1061 void wxDocManager::OnPreview(wxCommandEvent
& WXUNUSED(event
))
1063 #if wxUSE_PRINTING_ARCHITECTURE
1064 wxView
*view
= GetActiveView();
1068 wxPrintout
*printout
= view
->OnCreatePrintout();
1071 // Pass two printout objects: for preview, and possible printing.
1072 wxPrintPreviewBase
*
1073 preview
= new wxPrintPreview(printout
, view
->OnCreatePrintout());
1074 if ( !preview
->Ok() )
1077 wxLogError(_("Print preview creation failed."));
1082 frame
= new wxPreviewFrame(preview
, wxTheApp
->GetTopWindow(),
1083 _("Print Preview"));
1084 frame
->Centre(wxBOTH
);
1085 frame
->Initialize();
1088 #endif // wxUSE_PRINTING_ARCHITECTURE
1091 void wxDocManager::OnUndo(wxCommandEvent
& event
)
1093 wxCommandProcessor
* const cmdproc
= GetCurrentCommandProcessor();
1103 void wxDocManager::OnRedo(wxCommandEvent
& event
)
1105 wxCommandProcessor
* const cmdproc
= GetCurrentCommandProcessor();
1115 // Handlers for UI update commands
1117 void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent
& event
)
1119 // CreateDocument() (which is called from OnFileOpen) may succeed
1120 // only when there is at least a template:
1121 event
.Enable( GetTemplates().GetCount()>0 );
1124 void wxDocManager::OnUpdateDisableIfNoDoc(wxUpdateUIEvent
& event
)
1126 event
.Enable( GetCurrentDocument() != NULL
);
1129 void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent
& event
)
1131 // CreateDocument() (which is called from OnFileNew) may succeed
1132 // only when there is at least a template:
1133 event
.Enable( GetTemplates().GetCount()>0 );
1136 void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent
& event
)
1138 wxDocument
* const doc
= GetCurrentDocument();
1139 event
.Enable( doc
&& !doc
->AlreadySaved() );
1142 void wxDocManager::OnUpdateUndo(wxUpdateUIEvent
& event
)
1144 wxCommandProcessor
* const cmdproc
= GetCurrentCommandProcessor();
1147 event
.Enable(false);
1151 event
.Enable(cmdproc
->CanUndo());
1152 cmdproc
->SetMenuStrings();
1155 void wxDocManager::OnUpdateRedo(wxUpdateUIEvent
& event
)
1157 wxCommandProcessor
* const cmdproc
= GetCurrentCommandProcessor();
1160 event
.Enable(false);
1164 event
.Enable(cmdproc
->CanRedo());
1165 cmdproc
->SetMenuStrings();
1168 wxView
*wxDocManager::GetActiveView() const
1170 wxView
*view
= GetCurrentView();
1172 if ( !view
&& !m_docs
.empty() )
1174 // if we have exactly one document, consider its view to be the current
1177 // VZ: I'm not exactly sure why is this needed but this is how this
1178 // code used to behave before the bug #9518 was fixed and it seems
1179 // safer to preserve the old logic
1180 wxList::compatibility_iterator node
= m_docs
.GetFirst();
1181 if ( !node
->GetNext() )
1183 wxDocument
*doc
= static_cast<wxDocument
*>(node
->GetData());
1184 view
= doc
->GetFirstView();
1186 //else: we have more than one document
1192 bool wxDocManager::TryBefore(wxEvent
& event
)
1194 wxView
* const view
= GetActiveView();
1195 return view
&& view
->ProcessEventHere(event
);
1201 // helper function: return only the visible templates
1202 wxDocTemplates
GetVisibleTemplates(const wxList
& allTemplates
)
1204 // select only the visible templates
1205 const size_t totalNumTemplates
= allTemplates
.GetCount();
1206 wxDocTemplates templates
;
1207 if ( totalNumTemplates
)
1209 templates
.reserve(totalNumTemplates
);
1211 for ( wxList::const_iterator i
= allTemplates
.begin(),
1212 end
= allTemplates
.end();
1216 wxDocTemplate
* const temp
= (wxDocTemplate
*)*i
;
1217 if ( temp
->IsVisible() )
1218 templates
.push_back(temp
);
1225 } // anonymous namespace
1227 wxDocument
*wxDocManager::CreateDocument(const wxString
& pathOrig
, long flags
)
1229 // this ought to be const but SelectDocumentType/Path() are not
1230 // const-correct and can't be changed as, being virtual, this risks
1231 // breaking user code overriding them
1232 wxDocTemplates
templates(GetVisibleTemplates(m_templates
));
1233 const size_t numTemplates
= templates
.size();
1234 if ( !numTemplates
)
1236 // no templates can be used, can't create document
1241 // normally user should select the template to use but wxDOC_SILENT flag we
1242 // choose one ourselves
1243 wxString path
= pathOrig
; // may be modified below
1244 wxDocTemplate
*temp
;
1245 if ( flags
& wxDOC_SILENT
)
1247 wxASSERT_MSG( !path
.empty(),
1248 "using empty path with wxDOC_SILENT doesn't make sense" );
1250 temp
= FindTemplateForPath(path
);
1253 wxLogWarning(_("The format of file '%s' couldn't be determined."),
1257 else // not silent, ask the user
1259 // for the new file we need just the template, for an existing one we
1260 // need the template and the path, unless it's already specified
1261 if ( (flags
& wxDOC_NEW
) || !path
.empty() )
1262 temp
= SelectDocumentType(&templates
[0], numTemplates
);
1264 temp
= SelectDocumentPath(&templates
[0], numTemplates
, path
, flags
);
1270 // check whether the document with this path is already opened
1271 if ( !path
.empty() )
1273 const wxFileName
fn(path
);
1274 for ( wxList::const_iterator i
= m_docs
.begin(); i
!= m_docs
.end(); ++i
)
1276 wxDocument
* const doc
= (wxDocument
*)*i
;
1278 if ( fn
== doc
->GetFilename() )
1280 // file already open, just activate it and return
1281 if ( doc
->GetFirstView() )
1283 ActivateView(doc
->GetFirstView());
1284 if ( doc
->GetDocumentWindow() )
1285 doc
->GetDocumentWindow()->SetFocus();
1293 // no, we need to create a new document
1296 // if we've reached the max number of docs, close the first one.
1297 if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen
)
1299 if ( !CloseDocument((wxDocument
*)GetDocuments().GetFirst()->GetData()) )
1301 // can't open the new document if closing the old one failed
1307 // do create and initialize the new document finally
1308 wxDocument
* const docNew
= temp
->CreateDocument(path
, flags
);
1312 docNew
->SetDocumentName(temp
->GetDocumentName());
1313 docNew
->SetDocumentTemplate(temp
);
1317 // call the appropriate function depending on whether we're creating a
1318 // new file or opening an existing one
1319 if ( !(flags
& wxDOC_NEW
? docNew
->OnNewDocument()
1320 : docNew
->OnOpenDocument(path
)) )
1322 docNew
->DeleteAllViews();
1326 wxCATCH_ALL( docNew
->DeleteAllViews(); throw; )
1328 // add the successfully opened file to MRU, but only if we're going to be
1329 // able to reopen it successfully later which requires the template for
1330 // this document to be retrievable from the file extension
1331 if ( !(flags
& wxDOC_NEW
) && temp
->FileMatchesTemplate(path
) )
1332 AddFileToHistory(path
);
1337 wxView
*wxDocManager::CreateView(wxDocument
*doc
, long flags
)
1339 wxDocTemplates
templates(GetVisibleTemplates(m_templates
));
1340 const size_t numTemplates
= templates
.size();
1342 if ( numTemplates
== 0 )
1345 wxDocTemplate
* const
1346 temp
= numTemplates
== 1 ? templates
[0]
1347 : SelectViewType(&templates
[0], numTemplates
);
1352 wxView
*view
= temp
->CreateView(doc
, flags
);
1354 view
->SetViewName(temp
->GetViewName());
1358 // Not yet implemented
1360 wxDocManager::DeleteTemplate(wxDocTemplate
*WXUNUSED(temp
), long WXUNUSED(flags
))
1364 // Not yet implemented
1365 bool wxDocManager::FlushDoc(wxDocument
*WXUNUSED(doc
))
1370 wxDocument
*wxDocManager::GetCurrentDocument() const
1372 wxView
* const view
= GetActiveView();
1373 return view
? view
->GetDocument() : NULL
;
1376 wxCommandProcessor
*wxDocManager::GetCurrentCommandProcessor() const
1378 wxDocument
* const doc
= GetCurrentDocument();
1379 return doc
? doc
->GetCommandProcessor() : NULL
;
1382 // Make a default name for a new document
1383 #if WXWIN_COMPATIBILITY_2_8
1384 bool wxDocManager::MakeDefaultName(wxString
& WXUNUSED(name
))
1386 // we consider that this function can only be overridden by the user code,
1387 // not called by it as it only makes sense to call it internally, so we
1388 // don't bother to return anything from here
1391 #endif // WXWIN_COMPATIBILITY_2_8
1393 wxString
wxDocManager::MakeNewDocumentName()
1397 #if WXWIN_COMPATIBILITY_2_8
1398 if ( !MakeDefaultName(name
) )
1399 #endif // WXWIN_COMPATIBILITY_2_8
1401 name
.Printf(_("unnamed%d"), m_defaultDocumentNameCounter
);
1402 m_defaultDocumentNameCounter
++;
1408 // Make a frame title (override this to do something different)
1409 // If docName is empty, a document is not currently active.
1410 wxString
wxDocManager::MakeFrameTitle(wxDocument
* doc
)
1412 wxString appName
= wxTheApp
->GetAppDisplayName();
1418 wxString docName
= doc
->GetUserReadableName();
1419 title
= docName
+ wxString(_(" - ")) + appName
;
1425 // Not yet implemented
1426 wxDocTemplate
*wxDocManager::MatchTemplate(const wxString
& WXUNUSED(path
))
1431 // File history management
1432 void wxDocManager::AddFileToHistory(const wxString
& file
)
1435 m_fileHistory
->AddFileToHistory(file
);
1438 void wxDocManager::RemoveFileFromHistory(size_t i
)
1441 m_fileHistory
->RemoveFileFromHistory(i
);
1444 wxString
wxDocManager::GetHistoryFile(size_t i
) const
1449 histFile
= m_fileHistory
->GetHistoryFile(i
);
1454 void wxDocManager::FileHistoryUseMenu(wxMenu
*menu
)
1457 m_fileHistory
->UseMenu(menu
);
1460 void wxDocManager::FileHistoryRemoveMenu(wxMenu
*menu
)
1463 m_fileHistory
->RemoveMenu(menu
);
1467 void wxDocManager::FileHistoryLoad(const wxConfigBase
& config
)
1470 m_fileHistory
->Load(config
);
1473 void wxDocManager::FileHistorySave(wxConfigBase
& config
)
1476 m_fileHistory
->Save(config
);
1480 void wxDocManager::FileHistoryAddFilesToMenu(wxMenu
* menu
)
1483 m_fileHistory
->AddFilesToMenu(menu
);
1486 void wxDocManager::FileHistoryAddFilesToMenu()
1489 m_fileHistory
->AddFilesToMenu();
1492 size_t wxDocManager::GetHistoryFilesCount() const
1494 return m_fileHistory
? m_fileHistory
->GetCount() : 0;
1498 // Find out the document template via matching in the document file format
1499 // against that of the template
1500 wxDocTemplate
*wxDocManager::FindTemplateForPath(const wxString
& path
)
1502 wxDocTemplate
*theTemplate
= NULL
;
1504 // Find the template which this extension corresponds to
1505 for (size_t i
= 0; i
< m_templates
.GetCount(); i
++)
1507 wxDocTemplate
*temp
= (wxDocTemplate
*)m_templates
.Item(i
)->GetData();
1508 if ( temp
->FileMatchesTemplate(path
) )
1517 // Prompts user to open a file, using file specs in templates.
1518 // Must extend the file selector dialog or implement own; OR
1519 // match the extension to the template extension.
1521 wxDocTemplate
*wxDocManager::SelectDocumentPath(wxDocTemplate
**templates
,
1524 long WXUNUSED(flags
),
1525 bool WXUNUSED(save
))
1527 #ifdef wxHAS_MULTIPLE_FILEDLG_FILTERS
1530 for (int i
= 0; i
< noTemplates
; i
++)
1532 if (templates
[i
]->IsVisible())
1534 // add a '|' to separate this filter from the previous one
1535 if ( !descrBuf
.empty() )
1536 descrBuf
<< wxT('|');
1538 descrBuf
<< templates
[i
]->GetDescription()
1539 << wxT(" (") << templates
[i
]->GetFileFilter() << wxT(") |")
1540 << templates
[i
]->GetFileFilter();
1544 wxString descrBuf
= wxT("*.*");
1545 wxUnusedVar(noTemplates
);
1548 int FilterIndex
= -1;
1550 wxWindow
* parent
= wxFindSuitableParent();
1552 wxString pathTmp
= wxFileSelectorEx(_("Open File"),
1560 wxDocTemplate
*theTemplate
= NULL
;
1561 if (!pathTmp
.empty())
1563 if (!wxFileExists(pathTmp
))
1566 if (!wxTheApp
->GetAppDisplayName().empty())
1567 msgTitle
= wxTheApp
->GetAppDisplayName();
1569 msgTitle
= wxString(_("File error"));
1571 wxMessageBox(_("Sorry, could not open this file."),
1573 wxOK
| wxICON_EXCLAMATION
| wxCENTRE
,
1576 path
= wxEmptyString
;
1580 SetLastDirectory(wxPathOnly(pathTmp
));
1584 // first choose the template using the extension, if this fails (i.e.
1585 // wxFileSelectorEx() didn't fill it), then use the path
1586 if ( FilterIndex
!= -1 )
1587 theTemplate
= templates
[FilterIndex
];
1589 theTemplate
= FindTemplateForPath(path
);
1592 // Since we do not add files with non-default extensions to the
1593 // file history this can only happen if the application changes the
1594 // allowed templates in runtime.
1595 wxMessageBox(_("Sorry, the format for this file is unknown."),
1597 wxOK
| wxICON_EXCLAMATION
| wxCENTRE
,
1609 wxDocTemplate
*wxDocManager::SelectDocumentType(wxDocTemplate
**templates
,
1610 int noTemplates
, bool sort
)
1612 wxArrayString strings
;
1613 wxScopedArray
<wxDocTemplate
*> data(new wxDocTemplate
*[noTemplates
]);
1617 for (i
= 0; i
< noTemplates
; i
++)
1619 if (templates
[i
]->IsVisible())
1623 for (j
= 0; j
< n
; j
++)
1625 //filter out NOT unique documents + view combinations
1626 if ( templates
[i
]->m_docTypeName
== data
[j
]->m_docTypeName
&&
1627 templates
[i
]->m_viewTypeName
== data
[j
]->m_viewTypeName
1634 strings
.Add(templates
[i
]->m_description
);
1636 data
[n
] = templates
[i
];
1644 strings
.Sort(); // ascending sort
1645 // Yes, this will be slow, but template lists
1646 // are typically short.
1648 n
= strings
.Count();
1649 for (i
= 0; i
< n
; i
++)
1651 for (j
= 0; j
< noTemplates
; j
++)
1653 if (strings
[i
] == templates
[j
]->m_description
)
1654 data
[i
] = templates
[j
];
1659 wxDocTemplate
*theTemplate
;
1664 // no visible templates, hence nothing to choose from
1669 // don't propose the user to choose if he has no choice
1670 theTemplate
= data
[0];
1674 // propose the user to choose one of several
1675 theTemplate
= (wxDocTemplate
*)wxGetSingleChoiceData
1677 _("Select a document template"),
1680 (void **)data
.get(),
1681 wxFindSuitableParent()
1688 wxDocTemplate
*wxDocManager::SelectViewType(wxDocTemplate
**templates
,
1689 int noTemplates
, bool sort
)
1691 wxArrayString strings
;
1692 wxScopedArray
<wxDocTemplate
*> data(new wxDocTemplate
*[noTemplates
]);
1696 for (i
= 0; i
< noTemplates
; i
++)
1698 wxDocTemplate
*templ
= templates
[i
];
1699 if ( templ
->IsVisible() && !templ
->GetViewName().empty() )
1703 for (j
= 0; j
< n
; j
++)
1705 //filter out NOT unique views
1706 if ( templates
[i
]->m_viewTypeName
== data
[j
]->m_viewTypeName
)
1712 strings
.Add(templ
->m_viewTypeName
);
1721 strings
.Sort(); // ascending sort
1722 // Yes, this will be slow, but template lists
1723 // are typically short.
1725 n
= strings
.Count();
1726 for (i
= 0; i
< n
; i
++)
1728 for (j
= 0; j
< noTemplates
; j
++)
1730 if (strings
[i
] == templates
[j
]->m_viewTypeName
)
1731 data
[i
] = templates
[j
];
1736 wxDocTemplate
*theTemplate
;
1738 // the same logic as above
1746 theTemplate
= data
[0];
1750 theTemplate
= (wxDocTemplate
*)wxGetSingleChoiceData
1752 _("Select a document view"),
1755 (void **)data
.get(),
1756 wxFindSuitableParent()
1764 void wxDocManager::AssociateTemplate(wxDocTemplate
*temp
)
1766 if (!m_templates
.Member(temp
))
1767 m_templates
.Append(temp
);
1770 void wxDocManager::DisassociateTemplate(wxDocTemplate
*temp
)
1772 m_templates
.DeleteObject(temp
);
1775 // Add and remove a document from the manager's list
1776 void wxDocManager::AddDocument(wxDocument
*doc
)
1778 if (!m_docs
.Member(doc
))
1782 void wxDocManager::RemoveDocument(wxDocument
*doc
)
1784 m_docs
.DeleteObject(doc
);
1787 // Views or windows should inform the document manager
1788 // when a view is going in or out of focus
1789 void wxDocManager::ActivateView(wxView
*view
, bool activate
)
1793 m_currentView
= view
;
1797 if ( m_currentView
== view
)
1799 // don't keep stale pointer
1800 m_currentView
= NULL
;
1805 // ----------------------------------------------------------------------------
1806 // wxDocChildFrameAnyBase
1807 // ----------------------------------------------------------------------------
1809 bool wxDocChildFrameAnyBase::CloseView(wxCloseEvent
& event
)
1813 if ( event
.CanVeto() && !m_childView
->Close(false) )
1819 m_childView
->Activate(false);
1824 m_childDocument
= NULL
;
1829 // ----------------------------------------------------------------------------
1830 // Default parent frame
1831 // ----------------------------------------------------------------------------
1833 BEGIN_EVENT_TABLE(wxDocParentFrame
, wxFrame
)
1834 EVT_MENU(wxID_EXIT
, wxDocParentFrame::OnExit
)
1835 EVT_MENU_RANGE(wxID_FILE1
, wxID_FILE9
, wxDocParentFrame::OnMRUFile
)
1836 EVT_CLOSE(wxDocParentFrame::OnCloseWindow
)
1839 wxDocParentFrame::wxDocParentFrame()
1841 m_docManager
= NULL
;
1844 wxDocParentFrame::wxDocParentFrame(wxDocManager
*manager
,
1847 const wxString
& title
,
1851 const wxString
& name
)
1852 : wxFrame(frame
, id
, title
, pos
, size
, style
, name
)
1854 m_docManager
= manager
;
1857 bool wxDocParentFrame::Create(wxDocManager
*manager
,
1860 const wxString
& title
,
1864 const wxString
& name
)
1866 m_docManager
= manager
;
1867 return base_type::Create(frame
, id
, title
, pos
, size
, style
, name
);
1870 void wxDocParentFrame::OnExit(wxCommandEvent
& WXUNUSED(event
))
1875 void wxDocParentFrame::OnMRUFile(wxCommandEvent
& event
)
1877 int n
= event
.GetId() - wxID_FILE1
; // the index in MRU list
1878 wxString
filename(m_docManager
->GetHistoryFile(n
));
1879 if ( filename
.empty() )
1882 wxString errMsg
; // must contain exactly one "%s" if non-empty
1883 if ( wxFile::Exists(filename
) )
1886 if ( m_docManager
->CreateDocument(filename
, wxDOC_SILENT
) )
1889 errMsg
= _("The file '%s' couldn't be opened.");
1891 else // file doesn't exist
1893 errMsg
= _("The file '%s' doesn't exist and couldn't be opened.");
1897 wxASSERT_MSG( !errMsg
.empty(), "should have an error message" );
1899 // remove the file which we can't open from the MRU list
1900 m_docManager
->RemoveFileFromHistory(n
);
1902 // and tell the user about it
1903 wxLogError(errMsg
+ '\n' +
1904 _("It has been removed from the most recently used files list."),
1908 // Extend event processing to search the view's event table
1909 bool wxDocParentFrame::TryBefore(wxEvent
& event
)
1911 if ( m_docManager
&& m_docManager
->ProcessEventHere(event
) )
1914 return wxFrame::TryBefore(event
);
1917 // Define the behaviour for the frame closing
1918 // - must delete all frames except for the main one.
1919 void wxDocParentFrame::OnCloseWindow(wxCloseEvent
& event
)
1921 if (m_docManager
->Clear(!event
.CanVeto()))
1929 #if wxUSE_PRINTING_ARCHITECTURE
1931 wxDocPrintout::wxDocPrintout(wxView
*view
, const wxString
& title
)
1934 m_printoutView
= view
;
1937 bool wxDocPrintout::OnPrintPage(int WXUNUSED(page
))
1941 // Get the logical pixels per inch of screen and printer
1942 int ppiScreenX
, ppiScreenY
;
1943 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
1944 wxUnusedVar(ppiScreenY
);
1945 int ppiPrinterX
, ppiPrinterY
;
1946 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
1947 wxUnusedVar(ppiPrinterY
);
1949 // This scales the DC so that the printout roughly represents the
1950 // the screen scaling. The text point size _should_ be the right size
1951 // but in fact is too small for some reason. This is a detail that will
1952 // need to be addressed at some point but can be fudged for the
1954 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
1956 // Now we have to check in case our real page size is reduced
1957 // (e.g. because we're drawing to a print preview memory DC)
1958 int pageWidth
, pageHeight
;
1960 dc
->GetSize(&w
, &h
);
1961 GetPageSizePixels(&pageWidth
, &pageHeight
);
1962 wxUnusedVar(pageHeight
);
1964 // If printer pageWidth == current DC width, then this doesn't
1965 // change. But w might be the preview bitmap width, so scale down.
1966 float overallScale
= scale
* (float)(w
/(float)pageWidth
);
1967 dc
->SetUserScale(overallScale
, overallScale
);
1971 m_printoutView
->OnDraw(dc
);
1976 bool wxDocPrintout::HasPage(int pageNum
)
1978 return (pageNum
== 1);
1981 bool wxDocPrintout::OnBeginDocument(int startPage
, int endPage
)
1983 if (!wxPrintout::OnBeginDocument(startPage
, endPage
))
1989 void wxDocPrintout::GetPageInfo(int *minPage
, int *maxPage
,
1990 int *selPageFrom
, int *selPageTo
)
1998 #endif // wxUSE_PRINTING_ARCHITECTURE
2000 // ----------------------------------------------------------------------------
2001 // File history (a.k.a. MRU, most recently used, files list)
2002 // ----------------------------------------------------------------------------
2004 wxFileHistory::wxFileHistory(size_t maxFiles
, wxWindowID idBase
)
2006 m_fileMaxFiles
= maxFiles
;
2010 void wxFileHistory::AddFileToHistory(const wxString
& file
)
2012 // check if we don't already have this file
2013 const wxFileName
fnNew(file
);
2015 numFiles
= m_fileHistory
.size();
2016 for ( i
= 0; i
< numFiles
; i
++ )
2018 if ( fnNew
== m_fileHistory
[i
] )
2020 // we do have it, move it to the top of the history
2021 RemoveFileFromHistory(i
);
2027 // if we already have a full history, delete the one at the end
2028 if ( numFiles
== m_fileMaxFiles
)
2030 RemoveFileFromHistory(--numFiles
);
2033 // add a new menu item to all file menus (they will be updated below)
2034 for ( wxList::compatibility_iterator node
= m_fileMenus
.GetFirst();
2036 node
= node
->GetNext() )
2038 wxMenu
* const menu
= (wxMenu
*)node
->GetData();
2040 if ( !numFiles
&& menu
->GetMenuItemCount() )
2041 menu
->AppendSeparator();
2043 // label doesn't matter, it will be set below anyhow, but it can't
2044 // be empty (this is supposed to indicate a stock item)
2045 menu
->Append(m_idBase
+ numFiles
, " ");
2048 // insert the new file in the beginning of the file history
2049 m_fileHistory
.insert(m_fileHistory
.begin(), file
);
2052 // update the labels in all menus
2053 for ( i
= 0; i
< numFiles
; i
++ )
2055 // if in same directory just show the filename; otherwise the full path
2056 const wxFileName
fnOld(m_fileHistory
[i
]);
2058 wxString pathInMenu
;
2059 if ( fnOld
.GetPath() == fnNew
.GetPath() )
2061 pathInMenu
= fnOld
.GetFullName();
2063 else // file in different directory
2065 // absolute path; could also set relative path
2066 pathInMenu
= m_fileHistory
[i
];
2069 for ( wxList::compatibility_iterator node
= m_fileMenus
.GetFirst();
2071 node
= node
->GetNext() )
2073 wxMenu
* const menu
= (wxMenu
*)node
->GetData();
2075 menu
->SetLabel(m_idBase
+ i
, GetMRUEntryLabel(i
, pathInMenu
));
2080 void wxFileHistory::RemoveFileFromHistory(size_t i
)
2082 size_t numFiles
= m_fileHistory
.size();
2083 wxCHECK_RET( i
< numFiles
,
2084 wxT("invalid index in wxFileHistory::RemoveFileFromHistory") );
2086 // delete the element from the array
2087 m_fileHistory
.RemoveAt(i
);
2090 for ( wxList::compatibility_iterator node
= m_fileMenus
.GetFirst();
2092 node
= node
->GetNext() )
2094 wxMenu
* const menu
= (wxMenu
*) node
->GetData();
2096 // shift filenames up
2097 for ( size_t j
= i
; j
< numFiles
; j
++ )
2099 menu
->SetLabel(m_idBase
+ j
, GetMRUEntryLabel(j
, m_fileHistory
[j
]));
2102 // delete the last menu item which is unused now
2103 const wxWindowID lastItemId
= m_idBase
+ numFiles
;
2104 if ( menu
->FindItem(lastItemId
) )
2105 menu
->Delete(lastItemId
);
2107 // delete the last separator too if no more files are left
2108 if ( m_fileHistory
.empty() )
2110 const wxMenuItemList::compatibility_iterator
2111 nodeLast
= menu
->GetMenuItems().GetLast();
2114 wxMenuItem
* const lastMenuItem
= nodeLast
->GetData();
2115 if ( lastMenuItem
->IsSeparator() )
2116 menu
->Delete(lastMenuItem
);
2118 //else: menu is empty somehow
2123 void wxFileHistory::UseMenu(wxMenu
*menu
)
2125 if ( !m_fileMenus
.Member(menu
) )
2126 m_fileMenus
.Append(menu
);
2129 void wxFileHistory::RemoveMenu(wxMenu
*menu
)
2131 m_fileMenus
.DeleteObject(menu
);
2135 void wxFileHistory::Load(const wxConfigBase
& config
)
2137 m_fileHistory
.Clear();
2140 buf
.Printf(wxT("file%d"), 1);
2142 wxString historyFile
;
2143 while ((m_fileHistory
.GetCount() < m_fileMaxFiles
) &&
2144 config
.Read(buf
, &historyFile
) && !historyFile
.empty())
2146 m_fileHistory
.Add(historyFile
);
2148 buf
.Printf(wxT("file%d"), (int)m_fileHistory
.GetCount()+1);
2149 historyFile
= wxEmptyString
;
2155 void wxFileHistory::Save(wxConfigBase
& config
)
2158 for (i
= 0; i
< m_fileMaxFiles
; i
++)
2161 buf
.Printf(wxT("file%d"), (int)i
+1);
2162 if (i
< m_fileHistory
.GetCount())
2163 config
.Write(buf
, wxString(m_fileHistory
[i
]));
2165 config
.Write(buf
, wxEmptyString
);
2168 #endif // wxUSE_CONFIG
2170 void wxFileHistory::AddFilesToMenu()
2172 if ( m_fileHistory
.empty() )
2175 for ( wxList::compatibility_iterator node
= m_fileMenus
.GetFirst();
2177 node
= node
->GetNext() )
2179 AddFilesToMenu((wxMenu
*) node
->GetData());
2183 void wxFileHistory::AddFilesToMenu(wxMenu
* menu
)
2185 if ( m_fileHistory
.empty() )
2188 if ( menu
->GetMenuItemCount() )
2189 menu
->AppendSeparator();
2191 for ( size_t i
= 0; i
< m_fileHistory
.GetCount(); i
++ )
2193 menu
->Append(m_idBase
+ i
, GetMRUEntryLabel(i
, m_fileHistory
[i
]));
2197 // ----------------------------------------------------------------------------
2198 // Permits compatibility with existing file formats and functions that
2199 // manipulate files directly
2200 // ----------------------------------------------------------------------------
2202 #if wxUSE_STD_IOSTREAM
2204 bool wxTransferFileToStream(const wxString
& filename
, wxSTD ostream
& stream
)
2206 wxFFile
file(filename
, _T("rb"));
2207 if ( !file
.IsOpened() )
2215 nRead
= file
.Read(buf
, WXSIZEOF(buf
));
2219 stream
.write(buf
, nRead
);
2223 while ( !file
.Eof() );
2228 bool wxTransferStreamToFile(wxSTD istream
& stream
, const wxString
& filename
)
2230 wxFFile
file(filename
, _T("wb"));
2231 if ( !file
.IsOpened() )
2237 stream
.read(buf
, WXSIZEOF(buf
));
2238 if ( !stream
.bad() ) // fail may be set on EOF, don't use operator!()
2240 if ( !file
.Write(buf
, stream
.gcount()) )
2244 while ( !stream
.eof() );
2249 #else // !wxUSE_STD_IOSTREAM
2251 bool wxTransferFileToStream(const wxString
& filename
, wxOutputStream
& stream
)
2253 wxFFile
file(filename
, _T("rb"));
2254 if ( !file
.IsOpened() )
2262 nRead
= file
.Read(buf
, WXSIZEOF(buf
));
2266 stream
.Write(buf
, nRead
);
2270 while ( !file
.Eof() );
2275 bool wxTransferStreamToFile(wxInputStream
& stream
, const wxString
& filename
)
2277 wxFFile
file(filename
, _T("wb"));
2278 if ( !file
.IsOpened() )
2284 stream
.Read(buf
, WXSIZEOF(buf
));
2286 const size_t nRead
= stream
.LastRead();
2295 if ( !file
.Write(buf
, nRead
) )
2302 #endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM
2304 #endif // wxUSE_DOC_VIEW_ARCHITECTURE