#include "wx/vector.h"
#include "wx/scopedarray.h"
#include "wx/scopedptr.h"
+#include "wx/scopeguard.h"
#include "wx/except.h"
#if wxUSE_STD_IOSTREAM
#include "wx/wfstream.h"
#endif
-typedef wxVector<wxDocTemplate *> wxDocTemplates;
-
// ----------------------------------------------------------------------------
// wxWidgets macros
// ----------------------------------------------------------------------------
wxDocument::wxDocument(wxDocument *parent)
{
m_documentModified = false;
- m_documentParent = parent;
m_documentTemplate = NULL;
+
+ m_documentParent = parent;
+ if ( parent )
+ parent->m_childDocuments.push_back(this);
+
m_commandProcessor = NULL;
m_savedYet = false;
}
if (GetDocumentManager())
GetDocumentManager()->RemoveDocument(this);
+ if ( m_documentParent )
+ m_documentParent->m_childDocuments.remove(this);
+
// Not safe to do here, since it'll invoke virtual view functions
// expecting to see valid derived objects: and by the time we get here,
// we've called destructors higher up.
if ( !OnSaveModified() )
return false;
+ // When the parent document closes, its children must be closed as well as
+ // they can't exist without the parent.
+
+ // As usual, first check if all children can be closed.
+ DocsList::const_iterator it = m_childDocuments.begin();
+ for ( DocsList::const_iterator end = m_childDocuments.end(); it != end; ++it )
+ {
+ if ( !(*it)->OnSaveModified() )
+ {
+ // Leave the parent document opened if a child can't close.
+ return false;
+ }
+ }
+
+ // Now that they all did, do close them: as m_childDocuments is modified as
+ // we iterate over it, don't use the usual for-style iteration here.
+ while ( !m_childDocuments.empty() )
+ {
+ wxDocument * const childDoc = m_childDocuments.front();
+
+ // This will call OnSaveModified() once again but it shouldn't do
+ // anything as the document was just saved or marked as not needing to
+ // be saved by the call to OnSaveModified() that returned true above.
+ if ( !childDoc->Close() )
+ {
+ wxFAIL_MSG( "Closing the child document unexpectedly failed "
+ "after its OnSaveModified() returned true" );
+ }
+
+ // Delete the child document by deleting all its views.
+ childDoc->DeleteAllViews();
+ }
+
+
return OnCloseDocument();
}
wxDocManager *wxDocument::GetDocumentManager() const
{
+ // For child documents we use the same document manager as the parent, even
+ // though we don't have our own template (as children are not opened/saved
+ // directly).
+ if ( m_documentParent )
+ return m_documentParent->GetDocumentManager();
+
return m_documentTemplate ? m_documentTemplate->GetDocumentManager() : NULL;
}
if ( !DoSaveDocument(file) )
return false;
+ if ( m_commandProcessor )
+ m_commandProcessor->MarkAsSaved();
+
Modify(false);
SetFilename(file);
SetDocumentSaved(true);
#if WXWIN_COMPATIBILITY_2_8
bool wxDocument::GetPrintableName(wxString& buf) const
{
- // this function can not only be overridden by the user code but also
+ // this function cannot only be overridden by the user code but also
// called by it so we need to ensure that we return the same thing as
// GetUserReadableName() but we can't call it because this would result in
// an infinite recursion, hence we use the helper DoGetUserReadableName()
bool
wxDocTemplate::InitDocument(wxDocument* doc, const wxString& path, long flags)
{
+ wxScopeGuard g = wxMakeObjGuard(*doc, &wxDocument::DeleteAllViews);
+
doc->SetFilename(path);
doc->SetDocumentTemplate(this);
GetDocumentManager()->AddDocument(doc);
doc->SetCommandProcessor(doc->OnCreateCommandProcessor());
- if (doc->OnCreate(path, flags))
- return true;
+ if ( !doc->OnCreate(path, flags) )
+ return false;
- if (GetDocumentManager()->GetDocuments().Member(doc))
- doc->DeleteAllViews();
- return false;
+ g.Dismiss(); // no need to call DeleteAllViews() anymore
+
+ return true;
}
wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags)
EVT_UPDATE_UI(wxID_REVERT, wxDocManager::OnUpdateFileRevert)
EVT_UPDATE_UI(wxID_NEW, wxDocManager::OnUpdateFileNew)
EVT_UPDATE_UI(wxID_SAVE, wxDocManager::OnUpdateFileSave)
- EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateDisableIfNoDoc)
+ EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateFileSaveAs)
EVT_UPDATE_UI(wxID_UNDO, wxDocManager::OnUpdateUndo)
EVT_UPDATE_UI(wxID_REDO, wxDocManager::OnUpdateRedo)
void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event))
{
wxDocument *doc = GetCurrentDocument();
- if (!doc)
- return;
- if (doc->Close())
- {
- doc->DeleteAllViews();
- if (m_docs.Member(doc))
- delete doc;
- }
+ if (doc)
+ CloseDocument(doc);
}
void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event))
// Check if the id is in the range assigned to MRU list entries.
const int id = event.GetId();
if ( id >= wxID_FILE1 &&
- id < wxID_FILE1 + m_fileHistory->GetBaseId() )
+ id < wxID_FILE1 + static_cast<int>(m_fileHistory->GetCount()) )
{
DoOpenMRUFile(id - wxID_FILE1);
}
wxString errMsg; // must contain exactly one "%s" if non-empty
if ( wxFile::Exists(filename) )
{
- // try to open it
- if ( CreateDocument(filename, wxDOC_SILENT) )
- return;
-
- errMsg = _("The file '%s' couldn't be opened.");
+ // Try to open it but don't give an error if it failed: this could be
+ // normal, e.g. because the user cancelled opening it, and we don't
+ // have any useful information to put in the error message anyhow, so
+ // we assume that in case of an error the appropriate message had been
+ // already logged.
+ (void)CreateDocument(filename, wxDOC_SILENT);
}
else // file doesn't exist
{
- errMsg = _("The file '%s' doesn't exist and couldn't be opened.");
+ OnMRUFileNotExist(n, filename);
}
+}
-
- wxASSERT_MSG( !errMsg.empty(), "should have an error message" );
-
+void wxDocManager::OnMRUFileNotExist(unsigned n, const wxString& filename)
+{
// remove the file which we can't open from the MRU list
RemoveFileFromHistory(n);
// and tell the user about it
- wxLogError(errMsg + '\n' +
- _("It has been removed from the most recently used files list."),
+ wxLogError(_("The file '%s' doesn't exist and couldn't be opened.\n"
+ "It has been removed from the most recently used files list."),
filename);
}
preview = new wxPrintPreview(printout,
view->OnCreatePrintout(),
&printDialogData);
- if ( !preview->Ok() )
+ if ( !preview->IsOk() )
{
delete preview;
wxLogError(_("Print preview creation failed."));
void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event)
{
wxDocument * const doc = GetCurrentDocument();
- event.Enable( doc && !doc->AlreadySaved() );
+ event.Enable( doc && !doc->IsChildDocument() && !doc->AlreadySaved() );
+}
+
+void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event)
+{
+ wxDocument * const doc = GetCurrentDocument();
+ event.Enable( doc && !doc->IsChildDocument() );
}
void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event)
wxCommandProcessor * const cmdproc = GetCurrentCommandProcessor();
if ( !cmdproc )
{
- event.Enable(false);
+ // If we don't have any document at all, the menu item should really be
+ // disabled.
+ if ( !GetCurrentDocument() )
+ event.Enable(false);
+ else // But if we do have it, it might handle wxID_UNDO on its own
+ event.Skip();
return;
}
-
event.Enable(cmdproc->CanUndo());
cmdproc->SetMenuStrings();
}
wxCommandProcessor * const cmdproc = GetCurrentCommandProcessor();
if ( !cmdproc )
{
- event.Enable(false);
+ // Use same logic as in OnUpdateUndo() above.
+ if ( !GetCurrentDocument() )
+ event.Enable(false);
+ else
+ event.Skip();
return;
}
-
event.Enable(cmdproc->CanRedo());
cmdproc->SetMenuStrings();
}
{
// helper function: return only the visible templates
-wxDocTemplates GetVisibleTemplates(const wxList& allTemplates)
+wxDocTemplateVector GetVisibleTemplates(const wxList& allTemplates)
{
// select only the visible templates
const size_t totalNumTemplates = allTemplates.GetCount();
- wxDocTemplates templates;
+ wxDocTemplateVector templates;
if ( totalNumTemplates )
{
templates.reserve(totalNumTemplates);
view->Activate(true);
if ( wxWindow *win = view->GetFrame() )
- win->SetFocus();
+ win->Raise();
}
wxDocument *wxDocManager::CreateDocument(const wxString& pathOrig, long flags)
// this ought to be const but SelectDocumentType/Path() are not
// const-correct and can't be changed as, being virtual, this risks
// breaking user code overriding them
- wxDocTemplates templates(GetVisibleTemplates(m_templates));
+ wxDocTemplateVector templates(GetVisibleTemplates(m_templates));
const size_t numTemplates = templates.size();
if ( !numTemplates )
{
{
// file already open, just activate it and return
ActivateDocument(doc);
+ return doc;
}
}
}
wxView *wxDocManager::CreateView(wxDocument *doc, long flags)
{
- wxDocTemplates templates(GetVisibleTemplates(m_templates));
+ wxDocTemplateVector templates(GetVisibleTemplates(m_templates));
const size_t numTemplates = templates.size();
if ( numTemplates == 0 )
m_templates.DeleteObject(temp);
}
+wxDocTemplate* wxDocManager::FindTemplate(const wxClassInfo* classinfo)
+{
+ for ( wxList::compatibility_iterator node = m_templates.GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxDocTemplate* t = wxStaticCast(node->GetData(), wxDocTemplate);
+ if ( t->GetDocClassInfo() == classinfo )
+ return t;
+ }
+
+ return NULL;
+}
+
// Add and remove a document from the manager's list
void wxDocManager::AddDocument(wxDocument *doc)
{
#if wxUSE_PRINTING_ARCHITECTURE
+namespace
+{
+
+wxString GetAppropriateTitle(const wxView *view, const wxString& titleGiven)
+{
+ wxString title(titleGiven);
+ if ( title.empty() )
+ {
+ if ( view && view->GetDocument() )
+ title = view->GetDocument()->GetUserReadableName();
+ else
+ title = _("Printout");
+ }
+
+ return title;
+}
+
+} // anonymous namespace
+
wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title)
- : wxPrintout(title)
+ : wxPrintout(GetAppropriateTitle(view, title))
{
m_printoutView = view;
}