GTK+ provides GtkRecentManager for this purpose since 2.10. Use it in wxFileHistory if available. Integration is simple, we just add a file to GtkRecentManager in addition to normal wxFileHistory handling. A well-behaved GNOME application would use GtkRecentManager as the primary store for recent files, so that it reflects when the user works with supported files in another editor(s) too. But for now, this is much better than no support at all. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64240 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
259 lines
7.3 KiB
C++
259 lines
7.3 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// 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)
|
|
|
|
wxFileHistoryBase::wxFileHistoryBase(size_t maxFiles, wxWindowID idBase)
|
|
{
|
|
m_fileMaxFiles = maxFiles;
|
|
m_idBase = idBase;
|
|
}
|
|
|
|
void wxFileHistoryBase::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 wxFileHistoryBase::RemoveFileFromHistory(size_t i)
|
|
{
|
|
size_t numFiles = m_fileHistory.size();
|
|
wxCHECK_RET( i < numFiles,
|
|
wxT("invalid index in wxFileHistoryBase::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 wxFileHistoryBase::UseMenu(wxMenu *menu)
|
|
{
|
|
if ( !m_fileMenus.Member(menu) )
|
|
m_fileMenus.Append(menu);
|
|
}
|
|
|
|
void wxFileHistoryBase::RemoveMenu(wxMenu *menu)
|
|
{
|
|
m_fileMenus.DeleteObject(menu);
|
|
}
|
|
|
|
#if wxUSE_CONFIG
|
|
void wxFileHistoryBase::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 wxFileHistoryBase::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 wxFileHistoryBase::AddFilesToMenu()
|
|
{
|
|
if ( m_fileHistory.empty() )
|
|
return;
|
|
|
|
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
|
|
node;
|
|
node = node->GetNext() )
|
|
{
|
|
AddFilesToMenu((wxMenu *) node->GetData());
|
|
}
|
|
}
|
|
|
|
void wxFileHistoryBase::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
|