+/////////////////////////////////////////////////////////////////////////////
+// Name: src/common/filehistorycmn.cpp
+// Purpose: wxFileHistory class
+// Author: Julian Smart, Vaclav Slavik, Vadim Zeitlin
+// Created: 2010-05-03
+// RCS-ID: $Id$
+// Copyright: (c) Julian Smart
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#include "wx/filehistory.h"
+
+#if wxUSE_FILE_HISTORY
+
+#include "wx/menu.h"
+#include "wx/confbase.h"
+#include "wx/filename.h"
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// private helpers
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// return the string used for the MRU list items in the menu
+//
+// NB: the index n is 0-based, as usual, but the strings start from 1
+wxString GetMRUEntryLabel(int n, const wxString& path)
+{
+ // we need to quote '&' characters which are used for mnemonics
+ wxString pathInMenu(path);
+ pathInMenu.Replace("&", "&&");
+
+ return wxString::Format("&%d %s", n + 1, pathInMenu);
+}
+
+} // anonymous namespace
+
+// ----------------------------------------------------------------------------
+// File history (a.k.a. MRU, most recently used, files list)
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
+
+wxFileHistory::wxFileHistory(size_t maxFiles, wxWindowID idBase)
+{
+ m_fileMaxFiles = maxFiles;
+ m_idBase = idBase;
+}
+
+void wxFileHistory::AddFileToHistory(const wxString& file)
+{
+ // check if we don't already have this file
+ const wxFileName fnNew(file);
+ size_t i,
+ numFiles = m_fileHistory.size();
+ for ( i = 0; i < numFiles; i++ )
+ {
+ if ( fnNew == m_fileHistory[i] )
+ {
+ // we do have it, move it to the top of the history
+ RemoveFileFromHistory(i);
+ numFiles--;
+ break;
+ }
+ }
+
+ // if we already have a full history, delete the one at the end
+ if ( numFiles == m_fileMaxFiles )
+ {
+ RemoveFileFromHistory(--numFiles);
+ }
+
+ // add a new menu item to all file menus (they will be updated below)
+ for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxMenu * const menu = (wxMenu *)node->GetData();
+
+ if ( !numFiles && menu->GetMenuItemCount() )
+ menu->AppendSeparator();
+
+ // label doesn't matter, it will be set below anyhow, but it can't
+ // be empty (this is supposed to indicate a stock item)
+ menu->Append(m_idBase + numFiles, " ");
+ }
+
+ // insert the new file in the beginning of the file history
+ m_fileHistory.insert(m_fileHistory.begin(), file);
+ numFiles++;
+
+ // update the labels in all menus
+ for ( i = 0; i < numFiles; i++ )
+ {
+ // if in same directory just show the filename; otherwise the full path
+ const wxFileName fnOld(m_fileHistory[i]);
+
+ wxString pathInMenu;
+ if ( fnOld.GetPath() == fnNew.GetPath() )
+ {
+ pathInMenu = fnOld.GetFullName();
+ }
+ else // file in different directory
+ {
+ // absolute path; could also set relative path
+ pathInMenu = m_fileHistory[i];
+ }
+
+ for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxMenu * const menu = (wxMenu *)node->GetData();
+
+ menu->SetLabel(m_idBase + i, GetMRUEntryLabel(i, pathInMenu));
+ }
+ }
+}
+
+void wxFileHistory::RemoveFileFromHistory(size_t i)
+{
+ size_t numFiles = m_fileHistory.size();
+ wxCHECK_RET( i < numFiles,
+ wxT("invalid index in wxFileHistory::RemoveFileFromHistory") );
+
+ // delete the element from the array
+ m_fileHistory.RemoveAt(i);
+ numFiles--;
+
+ for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxMenu * const menu = (wxMenu *) node->GetData();
+
+ // shift filenames up
+ for ( size_t j = i; j < numFiles; j++ )
+ {
+ menu->SetLabel(m_idBase + j, GetMRUEntryLabel(j, m_fileHistory[j]));
+ }
+
+ // delete the last menu item which is unused now
+ const wxWindowID lastItemId = m_idBase + numFiles;
+ if ( menu->FindItem(lastItemId) )
+ menu->Delete(lastItemId);
+
+ // delete the last separator too if no more files are left
+ if ( m_fileHistory.empty() )
+ {
+ const wxMenuItemList::compatibility_iterator
+ nodeLast = menu->GetMenuItems().GetLast();
+ if ( nodeLast )
+ {
+ wxMenuItem * const lastMenuItem = nodeLast->GetData();
+ if ( lastMenuItem->IsSeparator() )
+ menu->Delete(lastMenuItem);
+ }
+ //else: menu is empty somehow
+ }
+ }
+}
+
+void wxFileHistory::UseMenu(wxMenu *menu)
+{
+ if ( !m_fileMenus.Member(menu) )
+ m_fileMenus.Append(menu);
+}
+
+void wxFileHistory::RemoveMenu(wxMenu *menu)
+{
+ m_fileMenus.DeleteObject(menu);
+}
+
+#if wxUSE_CONFIG
+void wxFileHistory::Load(const wxConfigBase& config)
+{
+ m_fileHistory.Clear();
+
+ wxString buf;
+ buf.Printf(wxT("file%d"), 1);
+
+ wxString historyFile;
+ while ((m_fileHistory.GetCount() < m_fileMaxFiles) &&
+ config.Read(buf, &historyFile) && !historyFile.empty())
+ {
+ m_fileHistory.Add(historyFile);
+
+ buf.Printf(wxT("file%d"), (int)m_fileHistory.GetCount()+1);
+ historyFile = wxEmptyString;
+ }
+
+ AddFilesToMenu();
+}
+
+void wxFileHistory::Save(wxConfigBase& config)
+{
+ size_t i;
+ for (i = 0; i < m_fileMaxFiles; i++)
+ {
+ wxString buf;
+ buf.Printf(wxT("file%d"), (int)i+1);
+ if (i < m_fileHistory.GetCount())
+ config.Write(buf, wxString(m_fileHistory[i]));
+ else
+ config.Write(buf, wxEmptyString);
+ }
+}
+#endif // wxUSE_CONFIG
+
+void wxFileHistory::AddFilesToMenu()
+{
+ if ( m_fileHistory.empty() )
+ return;
+
+ for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ AddFilesToMenu((wxMenu *) node->GetData());
+ }
+}
+
+void wxFileHistory::AddFilesToMenu(wxMenu* menu)
+{
+ if ( m_fileHistory.empty() )
+ return;
+
+ if ( menu->GetMenuItemCount() )
+ menu->AppendSeparator();
+
+ for ( size_t i = 0; i < m_fileHistory.GetCount(); i++ )
+ {
+ menu->Append(m_idBase + i, GetMRUEntryLabel(i, m_fileHistory[i]));
+ }
+}
+
+#endif // wxUSE_FILE_HISTORY