X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/89d94e046d82725ac0b6d266c3d6263237ab2e47..b4c1fe36b9854cdb404906ba3a181a67f9247e0e:/src/common/docview.cpp?ds=sidebyside diff --git a/src/common/docview.cpp b/src/common/docview.cpp index 829ce9b852..6e1ef4c162 100644 --- a/src/common/docview.cpp +++ b/src/common/docview.cpp @@ -58,7 +58,9 @@ #include "wx/filename.h" #include "wx/stdpaths.h" #include "wx/vector.h" -#include "wx/ptr_scpd.h" +#include "wx/scopedarray.h" +#include "wx/scopedptr.h" +#include "wx/except.h" #if wxUSE_STD_IOSTREAM #include "wx/ioswrap.h" @@ -103,13 +105,6 @@ IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject) namespace { -wxWindow *wxFindSuitableParent() -{ - wxWindow * const win = wxGetTopLevelParent(wxWindow::FindFocus()); - - return win ? win : wxTheApp->GetTopWindow(); -} - wxString FindExtension(const wxString& path) { wxString ext; @@ -238,6 +233,18 @@ wxView *wxDocument::GetFirstView() const return static_cast(m_documentViews.GetFirst()->GetData()); } +void wxDocument::Modify(bool mod) +{ + if (mod != m_documentModified) + { + m_documentModified = mod; + + // Allow views to append asterix to the title + wxView* view = GetFirstView(); + if (view) view->OnChangeFilename(); + } +} + wxDocManager *wxDocument::GetDocumentManager() const { return m_documentTemplate ? m_documentTemplate->GetDocumentManager() : NULL; @@ -245,11 +252,13 @@ wxDocManager *wxDocument::GetDocumentManager() const bool wxDocument::OnNewDocument() { - if ( !OnSaveModified() ) - return false; + // notice that there is no need to neither reset nor even check the + // modified flag here as the document itself is a new object (this is only + // called from CreateDocument()) and so it shouldn't be saved anyhow even + // if it is modified -- this could happen if the user code creates + // documents pre-filled with some user-entered (and which hence must not be + // lost) information - DeleteContents(); - Modify(false); SetDocumentSaved(false); const wxString name = GetDocumentManager()->MakeNewDocumentName(); @@ -330,15 +339,6 @@ bool wxDocument::SaveAs() if (fileName.empty()) return false; // cancelled by user - wxString ext; - wxFileName::SplitPath(fileName, NULL, NULL, &ext); - - if (ext.empty()) - { - fileName += wxT("."); - fileName += docTemplate->GetDefaultExtension(); - } - // Files that were not saved correctly are not added to the FileHistory. if (!OnSaveDocument(fileName)) return false; @@ -346,16 +346,16 @@ bool wxDocument::SaveAs() SetTitle(wxFileNameFromPath(fileName)); SetFilename(fileName, true); // will call OnChangeFileName automatically - // A file that doesn't use the default extension of its document template - // cannot be opened via the FileHistory, so we do not add it. - if (docTemplate->FileMatchesTemplate(fileName)) - { - GetDocumentManager()->AddFileToHistory(fileName); - } - //else: the user will probably not be able to open the file again, so we - // could warn about the wrong file-extension here + // A file that doesn't use the default extension of its document template + // cannot be opened via the FileHistory, so we do not add it. + if (docTemplate->FileMatchesTemplate(fileName)) + { + GetDocumentManager()->AddFileToHistory(fileName); + } + //else: the user will probably not be able to open the file again, so we + // could warn about the wrong file-extension here - return true; + return true; } bool wxDocument::OnSaveDocument(const wxString& file) @@ -378,15 +378,20 @@ bool wxDocument::OnSaveDocument(const wxString& file) bool wxDocument::OnOpenDocument(const wxString& file) { - if ( !OnSaveModified() ) - return false; + // notice that there is no need to check the modified flag here for the + // reasons explained in OnNewDocument() if ( !DoOpenDocument(file) ) return false; SetFilename(file, true); - Modify(false); - m_savedYet = true; + + // stretching the logic a little this does make sense because the document + // had been saved into the file we just loaded it from, it just could have + // happened during a previous program execution, it's just that the name of + // this method is a bit unfortunate, it should probably have been called + // HasAssociatedFileName() + SetDocumentSaved(true); UpdateAllViews(); @@ -480,8 +485,7 @@ bool wxDocument::OnSaveModified() GetUserReadableName() ), wxTheApp->GetAppDisplayName(), - wxYES_NO | wxCANCEL | wxICON_QUESTION | wxCENTRE, - wxFindSuitableParent() + wxYES_NO | wxCANCEL | wxICON_QUESTION | wxCENTRE ) ) { case wxNO: @@ -641,15 +645,47 @@ wxView::wxView() m_viewDocument = NULL; m_viewFrame = NULL; + + m_docChildFrame = NULL; } wxView::~wxView() { - GetDocumentManager()->ActivateView(this, false); - m_viewDocument->RemoveView(this); + if (m_viewDocument && GetDocumentManager()) + GetDocumentManager()->ActivateView(this, false); + + // reset our frame view first, before removing it from the document as + // SetView(NULL) is a simple call while RemoveView() may result in user + // code being executed and this user code can, for example, show a message + // box which would result in an activation event for m_docChildFrame and so + // could reactivate the view being destroyed -- unless we reset it first + if ( m_docChildFrame && m_docChildFrame->GetView() == this ) + { + // prevent it from doing anything with us + m_docChildFrame->SetView(NULL); + + // it doesn't make sense to leave the frame alive if its associated + // view doesn't exist any more so unconditionally close it as well + // + // notice that we only get here if m_docChildFrame is non-NULL in the + // first place and it will be always NULL if we're deleted because our + // frame was closed, so this only catches the case of directly deleting + // the view, as it happens if its creation fails in wxDocTemplate:: + // CreateView() for example + m_docChildFrame->GetWindow()->Destroy(); + } + + if ( m_viewDocument ) + m_viewDocument->RemoveView(this); +} + +void wxView::SetDocChildFrame(wxDocChildFrameAnyBase *docChildFrame) +{ + SetFrame(docChildFrame ? docChildFrame->GetWindow() : NULL); + m_docChildFrame = docChildFrame; } -bool wxView::TryValidator(wxEvent& event) +bool wxView::TryBefore(wxEvent& event) { wxDocument * const doc = GetDocument(); return doc && doc->ProcessEventHere(event); @@ -681,7 +717,12 @@ void wxView::OnChangeFilename() wxDocument *doc = GetDocument(); if (!doc) return; - win->SetLabel(doc->GetUserReadableName()); + wxString label = doc->GetUserReadableName(); + if (doc->IsModified()) + { + label += "*"; + } + win->SetLabel(label); } void wxView::SetDocument(wxDocument *doc) @@ -754,11 +795,15 @@ wxDocTemplate::~wxDocTemplate() // Tries to dynamically construct an object of the right class. wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags) { + // InitDocument() is supposed to delete the document object if its + // initialization fails so don't use wxScopedPtr<> here: this is fragile + // but unavoidable because the default implementation uses CreateView() + // which may -- or not -- create a wxView and if it does create it and its + // initialization fails then the view destructor will delete the document + // (via RemoveView()) and as we can't distinguish between the two cases we + // just have to assume that it always deletes it in case of failure wxDocument * const doc = DoCreateDocument(); - // VZ: this code doesn't delete doc if InitDocument() (i.e. doc->OnCreate()) - // fails, is this intentional? - return doc && InitDocument(doc, path, flags) ? doc : NULL; } @@ -863,8 +908,6 @@ wxDocManager* wxDocManager::sm_docManager = NULL; wxDocManager::wxDocManager(long WXUNUSED(flags), bool initialize) { - wxASSERT_MSG( !sm_docManager, "multiple wxDocManagers not allowed" ); - sm_docManager = this; m_defaultDocumentNameCounter = 1; @@ -944,12 +987,35 @@ bool wxDocManager::Initialize() wxString wxDocManager::GetLastDirectory() const { - // use the system-dependent default location for the document files if - // we're being opened for the first time + // if we haven't determined the last used directory yet, do it now if ( m_lastDirectory.empty() ) { + // we're going to modify m_lastDirectory in this const method, so do it + // via non-const self pointer instead of const this one wxDocManager * const self = const_cast(this); - self->m_lastDirectory = wxStandardPaths::Get().GetAppDocumentsDir(); + + // first try to reuse the directory of the most recently opened file: + // this ensures that if the user opens a file, closes the program and + // runs it again the "Open file" dialog will open in the directory of + // the last file he used + if ( m_fileHistory && m_fileHistory->GetCount() ) + { + const wxString lastOpened = m_fileHistory->GetHistoryFile(0); + const wxFileName fn(lastOpened); + if ( fn.DirExists() ) + { + self->m_lastDirectory = fn.GetPath(); + } + //else: should we try the next one? + } + //else: no history yet + + // if we don't have any files in the history (yet?), use the + // system-dependent default location for the document files + if ( m_lastDirectory.empty() ) + { + self->m_lastDirectory = wxStandardPaths::Get().GetAppDocumentsDir(); + } } return m_lastDirectory; @@ -1018,7 +1084,7 @@ void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event)) void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event)) { #if wxUSE_PRINTING_ARCHITECTURE - wxView *view = GetCurrentView(); + wxView *view = GetActiveView(); if (!view) return; @@ -1036,7 +1102,8 @@ void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event)) void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event)) { #if wxUSE_PRINTING_ARCHITECTURE - wxView *view = GetCurrentView(); + wxBusyCursor busy; + wxView *view = GetActiveView(); if (!view) return; @@ -1140,21 +1207,33 @@ void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event) cmdproc->SetMenuStrings(); } -wxView *wxDocManager::GetCurrentView() const +wxView *wxDocManager::GetActiveView() const { - if (m_currentView) - return m_currentView; - if (m_docs.GetCount() == 1) + wxView *view = GetCurrentView(); + + if ( !view && !m_docs.empty() ) { - wxDocument* doc = (wxDocument*) m_docs.GetFirst()->GetData(); - return doc->GetFirstView(); + // if we have exactly one document, consider its view to be the current + // one + // + // VZ: I'm not exactly sure why is this needed but this is how this + // code used to behave before the bug #9518 was fixed and it seems + // safer to preserve the old logic + wxList::compatibility_iterator node = m_docs.GetFirst(); + if ( !node->GetNext() ) + { + wxDocument *doc = static_cast(node->GetData()); + view = doc->GetFirstView(); + } + //else: we have more than one document } - return NULL; + + return view; } -bool wxDocManager::TryValidator(wxEvent& event) +bool wxDocManager::TryBefore(wxEvent& event) { - wxView * const view = GetCurrentView(); + wxView * const view = GetActiveView(); return view && view->ProcessEventHere(event); } @@ -1275,15 +1354,18 @@ wxDocument *wxDocManager::CreateDocument(const wxString& pathOrig, long flags) docNew->SetDocumentName(temp->GetDocumentName()); docNew->SetDocumentTemplate(temp); - // call the appropriate function depending on whether we're creating a new - // file or opening an existing one - if ( !(flags & wxDOC_NEW ? docNew->OnNewDocument() - : docNew->OnOpenDocument(path)) ) + wxTRY { - // Document is implicitly deleted by DeleteAllViews - docNew->DeleteAllViews(); - return NULL; + // call the appropriate function depending on whether we're creating a + // new file or opening an existing one + if ( !(flags & wxDOC_NEW ? docNew->OnNewDocument() + : docNew->OnOpenDocument(path)) ) + { + docNew->DeleteAllViews(); + return NULL; + } } + wxCATCH_ALL( docNew->DeleteAllViews(); throw; ) // add the successfully opened file to MRU, but only if we're going to be // able to reopen it successfully later which requires the template for @@ -1329,7 +1411,7 @@ bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc)) wxDocument *wxDocManager::GetCurrentDocument() const { - wxView * const view = GetCurrentView(); + wxView * const view = GetActiveView(); return view ? view->GetDocument() : NULL; } @@ -1507,15 +1589,11 @@ wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, int FilterIndex = -1; - wxWindow* parent = wxFindSuitableParent(); - wxString pathTmp = wxFileSelectorEx(_("Open File"), GetLastDirectory(), wxEmptyString, &FilterIndex, - descrBuf, - 0, - parent); + descrBuf); wxDocTemplate *theTemplate = NULL; if (!pathTmp.empty()) @@ -1530,8 +1608,7 @@ wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, wxMessageBox(_("Sorry, could not open this file."), msgTitle, - wxOK | wxICON_EXCLAMATION | wxCENTRE, - parent); + wxOK | wxICON_EXCLAMATION | wxCENTRE); path = wxEmptyString; return NULL; @@ -1554,8 +1631,7 @@ wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, // allowed templates in runtime. wxMessageBox(_("Sorry, the format for this file is unknown."), _("Open File"), - wxOK | wxICON_EXCLAMATION | wxCENTRE, - parent); + wxOK | wxICON_EXCLAMATION | wxCENTRE); } } else @@ -1637,8 +1713,7 @@ wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates, _("Select a document template"), _("Templates"), strings, - (void **)data.get(), - wxFindSuitableParent() + (void **)data.get() ); } @@ -1712,8 +1787,7 @@ wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates, _("Select a document view"), _("Views"), strings, - (void **)data.get(), - wxFindSuitableParent() + (void **)data.get() ); } @@ -1763,68 +1837,34 @@ void wxDocManager::ActivateView(wxView *view, bool activate) } // ---------------------------------------------------------------------------- -// Default document child frame +// wxDocChildFrameAnyBase // ---------------------------------------------------------------------------- -BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame) - EVT_ACTIVATE(wxDocChildFrame::OnActivate) - EVT_CLOSE(wxDocChildFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxDocChildFrame::wxDocChildFrame(wxDocument *doc, - wxView *view, - wxFrame *frame, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) - : wxFrame(frame, id, title, pos, size, style, name) +bool wxDocChildFrameAnyBase::CloseView(wxCloseEvent& event) { - m_childDocument = doc; - m_childView = view; - if (view) - view->SetFrame(this); -} - -bool wxDocChildFrame::TryValidator(wxEvent& event) -{ - if ( !m_childView ) - return false; - - // FIXME: why is this needed here? - m_childView->Activate(true); - - return m_childView->ProcessEventHere(event); -} - -void wxDocChildFrame::OnActivate(wxActivateEvent& event) -{ - wxFrame::OnActivate(event); - - if (m_childView) - m_childView->Activate(event.GetActive()); -} + if ( m_childView ) + { + if ( event.CanVeto() && !m_childView->Close(false) ) + { + event.Veto(); + return false; + } -void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event) -{ - if ( !m_childView ) - return; + m_childView->Activate(false); - // passing false to Close() means to not delete associated window - if ( event.CanVeto() && !m_childView->Close(false) ) - { - event.Veto(); - return; + // it is important to reset m_childView frame pointer to NULL before + // deleting it because while normally it is the frame which deletes the + // view when it's closed, the view also closes the frame if it is + // deleted directly not by us as indicated by its doc child frame + // pointer still being set + m_childView->SetDocChildFrame(NULL); + delete m_childView; + m_childView = NULL; } - m_childView->Activate(false); - delete m_childView; - m_childView = NULL; m_childDocument = NULL; - Destroy(); + return true; } // ---------------------------------------------------------------------------- @@ -1907,9 +1947,12 @@ void wxDocParentFrame::OnMRUFile(wxCommandEvent& event) } // Extend event processing to search the view's event table -bool wxDocParentFrame::TryValidator(wxEvent& event) +bool wxDocParentFrame::TryBefore(wxEvent& event) { - return m_docManager && m_docManager->ProcessEventHere(event); + if ( m_docManager && m_docManager->ProcessEventHere(event) ) + return true; + + return wxFrame::TryBefore(event); } // Define the behaviour for the frame closing @@ -2201,7 +2244,11 @@ void wxFileHistory::AddFilesToMenu(wxMenu* menu) bool wxTransferFileToStream(const wxString& filename, wxSTD ostream& stream) { - wxFFile file(filename, _T("rb")); +#if wxUSE_FFILE + wxFFile file(filename, wxT("rb")); +#elif wxUSE_FILE + wxFile file(filename, wxFile::read); +#endif if ( !file.IsOpened() ) return false; @@ -2225,7 +2272,11 @@ bool wxTransferFileToStream(const wxString& filename, wxSTD ostream& stream) bool wxTransferStreamToFile(wxSTD istream& stream, const wxString& filename) { - wxFFile file(filename, _T("wb")); +#if wxUSE_FFILE + wxFFile file(filename, wxT("wb")); +#elif wxUSE_FILE + wxFile file(filename, wxFile::write); +#endif if ( !file.IsOpened() ) return false; @@ -2248,7 +2299,11 @@ bool wxTransferStreamToFile(wxSTD istream& stream, const wxString& filename) bool wxTransferFileToStream(const wxString& filename, wxOutputStream& stream) { - wxFFile file(filename, _T("rb")); +#if wxUSE_FFILE + wxFFile file(filename, wxT("rb")); +#elif wxUSE_FILE + wxFile file(filename, wxFile::read); +#endif if ( !file.IsOpened() ) return false; @@ -2272,7 +2327,11 @@ bool wxTransferFileToStream(const wxString& filename, wxOutputStream& stream) bool wxTransferStreamToFile(wxInputStream& stream, const wxString& filename) { - wxFFile file(filename, _T("wb")); +#if wxUSE_FFILE + wxFFile file(filename, wxT("wb")); +#elif wxUSE_FILE + wxFile file(filename, wxFile::write); +#endif if ( !file.IsOpened() ) return false;