X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4fedd384a1c85dfb94212edbd8ae8e1c973d3c8c..3ba18664fc65e3494695bbd57250bcee36625c91:/src/common/docview.cpp diff --git a/src/common/docview.cpp b/src/common/docview.cpp index 2081dbc49c..17fcf47504 100644 --- a/src/common/docview.cpp +++ b/src/common/docview.cpp @@ -5,7 +5,7 @@ // Modified by: // Created: 01/02/97 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem +// Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -101,6 +101,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject) // ---------------------------------------------------------------------------- static inline wxString FindExtension(const wxChar *path); +static wxWindow* wxFindSuitableParent(void); // ---------------------------------------------------------------------------- // local constants @@ -274,8 +275,6 @@ bool wxDocument::SaveAs() SetFilename(fileName); SetTitle(wxFileNameFromPath(fileName)); - GetDocumentManager()->AddFileToHistory(fileName); - // Notify the views that the filename has changed wxNode *node = m_documentViews.GetFirst(); while (node) @@ -285,7 +284,22 @@ bool wxDocument::SaveAs() node = node->GetNext(); } - return OnSaveDocument(m_documentFile); + // Files that were not saved correctly are not added to the FileHistory. + if (!OnSaveDocument(m_documentFile)) + return FALSE; + + // 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; } bool wxDocument::OnSaveDocument(const wxString& file) @@ -774,6 +788,24 @@ wxDocManager::~wxDocManager() sm_docManager = (wxDocManager*) NULL; } +// closes the specified document +bool wxDocManager::CloseDocument(wxDocument* doc, bool force) +{ + if (doc->Close() || force) + { + // Implicitly deletes the document when + // the last view is deleted + doc->DeleteAllViews(); + + // Check we're really deleted + if (m_docs.Member(doc)) + delete doc; + + return TRUE; + } + return FALSE; +} + bool wxDocManager::CloseDocuments(bool force) { wxNode *node = m_docs.GetFirst(); @@ -781,18 +813,10 @@ bool wxDocManager::CloseDocuments(bool force) { wxDocument *doc = (wxDocument *)node->GetData(); wxNode *next = node->GetNext(); - - if (!doc->Close() && !force) + + if (!CloseDocument(doc, force)) return FALSE; - // Implicitly deletes the document when the last - // view is removed (deleted) - doc->DeleteAllViews(); - - // Check document is deleted - if (m_docs.Member(doc)) - delete doc; - // This assumes that documents are not connected in // any way, i.e. deleting one document does NOT // delete another. @@ -940,22 +964,26 @@ void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event)) #endif // wxUSE_PRINTING_ARCHITECTURE } -void wxDocManager::OnUndo(wxCommandEvent& WXUNUSED(event)) +void wxDocManager::OnUndo(wxCommandEvent& event) { wxDocument *doc = GetCurrentDocument(); if (!doc) return; if (doc->GetCommandProcessor()) doc->GetCommandProcessor()->Undo(); + else + event.Skip(); } -void wxDocManager::OnRedo(wxCommandEvent& WXUNUSED(event)) +void wxDocManager::OnRedo(wxCommandEvent& event) { wxDocument *doc = GetCurrentDocument(); if (!doc) return; if (doc->GetCommandProcessor()) doc->GetCommandProcessor()->Redo(); + else + event.Skip(); } // Handlers for UI update commands @@ -997,17 +1025,29 @@ void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event) void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event) { wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc && doc->GetCommandProcessor() && doc->GetCommandProcessor()->CanUndo()) ); - if (doc && doc->GetCommandProcessor()) + if (!doc) + event.Enable(FALSE); + else if (!doc->GetCommandProcessor()) + event.Skip(); + else + { + event.Enable( doc->GetCommandProcessor()->CanUndo() ); doc->GetCommandProcessor()->SetMenuStrings(); + } } void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event) { wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc && doc->GetCommandProcessor() && doc->GetCommandProcessor()->CanRedo()) ); - if (doc && doc->GetCommandProcessor()) + if (!doc) + event.Enable(FALSE); + else if (!doc->GetCommandProcessor()) + event.Skip(); + else + { + event.Enable( doc->GetCommandProcessor()->CanRedo() ); doc->GetCommandProcessor()->SetMenuStrings(); + } } void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event) @@ -1070,27 +1110,15 @@ wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) delete[] templates; return (wxDocument *) NULL; } + + wxDocument* docToClose = NULL; // If we've reached the max number of docs, close the // first one. if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen ) { wxDocument *doc = (wxDocument *)GetDocuments().GetFirst()->GetData(); - if (doc->Close()) - { - // Implicitly deletes the document when - // the last view is deleted - doc->DeleteAllViews(); - - // Check we're really deleted - if (m_docs.Member(doc)) - delete doc; - } - else - { - delete[] templates; - return (wxDocument *) NULL; - } + docToClose = doc; } // New document: user chooses a template, unless there's only one. @@ -1098,9 +1126,19 @@ wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) { if (n == 1) { + if (docToClose) + { + if (!CloseDocument(docToClose, FALSE)) + { + delete[] templates; + return NULL; + } + } + wxDocTemplate *temp = templates[0]; delete[] templates; wxDocument *newDoc = temp->CreateDocument(path, flags); + if (newDoc) { newDoc->SetDocumentName(temp->GetDocumentName()); @@ -1114,7 +1152,16 @@ wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) delete[] templates; if (temp) { + if (docToClose) + { + if (!CloseDocument(docToClose, FALSE)) + { + return NULL; + } + } + wxDocument *newDoc = temp->CreateDocument(path, flags); + if (newDoc) { newDoc->SetDocumentName(temp->GetDocumentName()); @@ -1135,7 +1182,17 @@ wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) path2 = path; if (flags & wxDOC_SILENT) + { temp = FindTemplateForPath(path2); + if (!temp) + { + // Since we do not add files with non-default extensions to the FileHistory this + // can only happen if the application changes the allowed templates in runtime. + (void)wxMessageBox(_("Sorry, the format for this file is unknown."), + _("Open File"), + wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); + } + } else temp = SelectDocumentPath(templates, n, path2, flags); @@ -1143,6 +1200,14 @@ wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) if (temp) { + if (docToClose) + { + if (!CloseDocument(docToClose, FALSE)) + { + return NULL; + } + } + wxDocument *newDoc = temp->CreateDocument(path2, flags); if (newDoc) { @@ -1154,7 +1219,11 @@ wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) // delete newDoc; // Implicitly deleted by DeleteAllViews return (wxDocument *) NULL; } - AddFileToHistory(path2); + // 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 (temp->FileMatchesTemplate(path2)) + AddFileToHistory(path2); } return newDoc; } @@ -1267,13 +1336,13 @@ void wxDocManager::AddFileToHistory(const wxString& file) m_fileHistory->AddFileToHistory(file); } -void wxDocManager::RemoveFileFromHistory(int i) +void wxDocManager::RemoveFileFromHistory(size_t i) { if (m_fileHistory) m_fileHistory->RemoveFileFromHistory(i); } -wxString wxDocManager::GetHistoryFile(int i) const +wxString wxDocManager::GetHistoryFile(size_t i) const { wxString histFile; @@ -1321,12 +1390,9 @@ void wxDocManager::FileHistoryAddFilesToMenu() m_fileHistory->AddFilesToMenu(); } -int wxDocManager::GetNoHistoryFiles() const +size_t wxDocManager::GetHistoryFilesCount() const { - if (m_fileHistory) - return m_fileHistory->GetNoHistoryFiles(); - else - return 0; + return m_fileHistory ? m_fileHistory->GetCount() : 0; } @@ -1372,9 +1438,8 @@ static wxWindow* wxFindSuitableParent() } // Prompts user to open a file, using file specs in templates. -// How to implement in wxWindows? Must extend the file selector -// dialog or implement own; OR match the extension to the -// template extension. +// Must extend the file selector dialog or implement own; OR +// match the extension to the template extension. wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, #if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) @@ -1447,6 +1512,14 @@ wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, theTemplate = templates[FilterIndex]; if ( !theTemplate ) theTemplate = FindTemplateForPath(path); + if ( !theTemplate ) + { + // Since we do not add files with non-default extensions to the FileHistory this + // can only happen if the application changes the allowed templates in runtime. + (void)wxMessageBox(_("Sorry, the format for this file is unknown."), + _("Open File"), + wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); + } } else { @@ -1801,7 +1874,14 @@ void wxDocParentFrame::OnMRUFile(wxCommandEvent& event) if ( wxFile::Exists(filename) ) { // try to open it - (void)m_docManager->CreateDocument(filename, wxDOC_SILENT); + if (!m_docManager->CreateDocument(filename, wxDOC_SILENT)) + { + // remove the file from the MRU list. The user should already be notified. + m_docManager->RemoveFileFromHistory(n); + + wxLogError(_("The file '%s' couldn't be opened.\nIt has been removed from the most recently used files list."), + filename.c_str()); + } } else { @@ -1908,16 +1988,17 @@ void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, in // File history processor // ---------------------------------------------------------------------------- -wxFileHistory::wxFileHistory(int maxFiles) +wxFileHistory::wxFileHistory(size_t maxFiles, wxWindowID idBase) { m_fileMaxFiles = maxFiles; + m_idBase = idBase; m_fileHistoryN = 0; m_fileHistory = new wxChar *[m_fileMaxFiles]; } wxFileHistory::~wxFileHistory() { - int i; + size_t i; for (i = 0; i < m_fileHistoryN; i++) delete[] m_fileHistory[i]; delete[] m_fileHistory; @@ -1926,12 +2007,19 @@ wxFileHistory::~wxFileHistory() // File history management void wxFileHistory::AddFileToHistory(const wxString& file) { - int i; + size_t i; // Check we don't already have this file for (i = 0; i < m_fileHistoryN; i++) { - if ( m_fileHistory[i] && (file == m_fileHistory[i]) ) +#if defined( __WXMSW__ ) // Add any other OSes with case insensitive file names + wxString testString; + if ( m_fileHistory[i] ) + testString = m_fileHistory[i]; + if ( m_fileHistory[i] && ( file.Lower() == testString.Lower() ) ) +#else + if ( m_fileHistory[i] && ( file == m_fileHistory[i] ) ) +#endif { // we do have it, move it to the top of the history RemoveFileFromHistory (i); @@ -1960,7 +2048,7 @@ void wxFileHistory::AddFileToHistory(const wxString& file) { menu->AppendSeparator(); } - menu->Append(wxID_FILE1+m_fileHistoryN, _("[EMPTY]")); + menu->Append(m_idBase+m_fileHistoryN, _("[EMPTY]")); node = node->GetNext(); } m_fileHistoryN ++; @@ -2001,46 +2089,48 @@ void wxFileHistory::AddFileToHistory(const wxString& file) while (node) { wxMenu* menu = (wxMenu*) node->GetData(); - menu->SetLabel(wxID_FILE1 + i, buf); + menu->SetLabel(m_idBase + i, buf); node = node->GetNext(); } } } } -void wxFileHistory::RemoveFileFromHistory(int i) +void wxFileHistory::RemoveFileFromHistory(size_t i) { wxCHECK_RET( i < m_fileHistoryN, wxT("invalid index in wxFileHistory::RemoveFileFromHistory") ); - // delete the element from the array (could use memmove() too...) - delete [] m_fileHistory[i]; + // delete the element from the array (could use memmove() too...) + delete [] m_fileHistory[i]; - int j; - for ( j = i; j < m_fileHistoryN - 1; j++ ) - { - m_fileHistory[j] = m_fileHistory[j + 1]; - } + size_t j; + for ( j = i; j < m_fileHistoryN - 1; j++ ) + { + m_fileHistory[j] = m_fileHistory[j + 1]; + } wxNode* node = m_fileMenus.GetFirst(); while ( node ) { - wxMenu* menu = (wxMenu*) node->GetData(); + wxMenu* menu = (wxMenu*) node->GetData(); + // shuffle filenames up + wxString buf; + for ( j = i; j < m_fileHistoryN - 1; j++ ) + { + buf.Printf(s_MRUEntryFormat, j + 1, m_fileHistory[j]); + menu->SetLabel(m_idBase + j, buf); + } - // shuffle filenames up - wxString buf; - for ( j = i; j < m_fileHistoryN - 1; j++ ) - { - buf.Printf(s_MRUEntryFormat, j + 1, m_fileHistory[j]); - menu->SetLabel(wxID_FILE1 + j, buf); - } - - node = node->GetNext(); + node = node->GetNext(); // delete the last menu item which is unused now - if (menu->FindItem(wxID_FILE1 + m_fileHistoryN - 1)) - menu->Delete(wxID_FILE1 + m_fileHistoryN - 1); + wxWindowID lastItemId = m_idBase + m_fileHistoryN - 1; + if (menu->FindItem(lastItemId)) + { + menu->Delete(lastItemId); + } // delete the last separator too if no more files are left if ( m_fileHistoryN == 1 ) @@ -2062,7 +2152,7 @@ void wxFileHistory::RemoveFileFromHistory(int i) m_fileHistoryN--; } -wxString wxFileHistory::GetHistoryFile(int i) const +wxString wxFileHistory::GetHistoryFile(size_t i) const { wxString s; if ( i < m_fileHistoryN ) @@ -2093,13 +2183,13 @@ void wxFileHistory::Load(wxConfigBase& config) { m_fileHistoryN = 0; wxString buf; - buf.Printf(wxT("file%d"), m_fileHistoryN+1); + buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); wxString historyFile; while ((m_fileHistoryN < m_fileMaxFiles) && config.Read(buf, &historyFile) && (historyFile != wxT(""))) { m_fileHistory[m_fileHistoryN] = copystring((const wxChar*) historyFile); m_fileHistoryN ++; - buf.Printf(wxT("file%d"), m_fileHistoryN+1); + buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); historyFile = wxT(""); } AddFilesToMenu(); @@ -2107,12 +2197,15 @@ void wxFileHistory::Load(wxConfigBase& config) void wxFileHistory::Save(wxConfigBase& config) { - int i; - for (i = 0; i < m_fileHistoryN; i++) + size_t i; + for (i = 0; i < m_fileMaxFiles; i++) { wxString buf; - buf.Printf(wxT("file%d"), i+1); - config.Write(buf, wxString(m_fileHistory[i])); + buf.Printf(wxT("file%d"), (int)i+1); + if (i < m_fileHistoryN) + config.Write(buf, wxString(m_fileHistory[i])); + else + config.Write(buf, wxEmptyString); } } #endif // wxUSE_CONFIG @@ -2130,14 +2223,14 @@ void wxFileHistory::AddFilesToMenu() menu->AppendSeparator(); } - int i; + size_t i; for (i = 0; i < m_fileHistoryN; i++) { if (m_fileHistory[i]) { wxString buf; buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); - menu->Append(wxID_FILE1+i, buf); + menu->Append(m_idBase+i, buf); } } node = node->GetNext(); @@ -2154,14 +2247,14 @@ void wxFileHistory::AddFilesToMenu(wxMenu* menu) menu->AppendSeparator(); } - int i; + size_t i; for (i = 0; i < m_fileHistoryN; i++) { if (m_fileHistory[i]) { wxString buf; buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); - menu->Append(wxID_FILE1+i, buf); + menu->Append(m_idBase+i, buf); } } }