1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/common/filehistorycmn.cpp
3
// Purpose: wxFileHistory class
4
// Author: Julian Smart, Vaclav Slavik, Vadim Zeitlin
6
// Copyright: (c) Julian Smart
7
// Licence: wxWindows licence
8
/////////////////////////////////////////////////////////////////////////////
10
// ============================================================================
12
// ============================================================================
14
// ----------------------------------------------------------------------------
16
// ----------------------------------------------------------------------------
18
// For compilers that support precompilation, includes "wx.h".
19
#include "wx/wxprec.h"
25
#include "wx/filehistory.h"
27
#if wxUSE_FILE_HISTORY
30
#include "wx/confbase.h"
31
#include "wx/filename.h"
33
// ============================================================================
35
// ============================================================================
37
// ----------------------------------------------------------------------------
39
// ----------------------------------------------------------------------------
44
// return the string used for the MRU list items in the menu
46
// NB: the index n is 0-based, as usual, but the strings start from 1
47
wxString GetMRUEntryLabel(int n, const wxString& path)
49
// we need to quote '&' characters which are used for mnemonics
50
wxString pathInMenu(path);
51
pathInMenu.Replace("&", "&&");
53
return wxString::Format("&%d %s", n + 1, pathInMenu);
56
} // anonymous namespace
58
// ----------------------------------------------------------------------------
59
// File history (a.k.a. MRU, most recently used, files list)
60
// ----------------------------------------------------------------------------
62
IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
64
wxFileHistoryBase::wxFileHistoryBase(size_t maxFiles, wxWindowID idBase)
66
m_fileMaxFiles = maxFiles;
71
wxString wxFileHistoryBase::NormalizeFileName(const wxFileName& fn)
73
// We specifically exclude wxPATH_NORM_LONG here as it can take a long time
74
// (several seconds) for network file paths under MSW, resulting in huge
75
// delays when opening a program using wxFileHistory. We also exclude
76
// wxPATH_NORM_ENV_VARS as the file names here are supposed to be "real"
77
// file names and not have any environment variables in them.
78
wxFileName fnNorm(fn);
79
fnNorm.Normalize(wxPATH_NORM_DOTS |
82
wxPATH_NORM_ABSOLUTE);
83
return fnNorm.GetFullPath();
86
void wxFileHistoryBase::AddFileToHistory(const wxString& file)
88
// Check if we don't already have this file. Notice that we avoid
89
// wxFileName::operator==(wxString) here as it converts the string to
90
// wxFileName and then normalizes it using all normalizations which is too
91
// slow (see the comment above), so we use our own quick normalization
92
// functions and a string comparison.
93
const wxFileName fnNew(file);
94
const wxString newFile = NormalizeFileName(fnNew);
96
numFiles = m_fileHistory.size();
97
for ( i = 0; i < numFiles; i++ )
99
if ( newFile == NormalizeFileName(m_fileHistory[i]) )
101
// we do have it, move it to the top of the history
102
RemoveFileFromHistory(i);
108
// if we already have a full history, delete the one at the end
109
if ( numFiles == m_fileMaxFiles )
111
RemoveFileFromHistory(--numFiles);
114
// add a new menu item to all file menus (they will be updated below)
115
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
117
node = node->GetNext() )
119
wxMenu * const menu = (wxMenu *)node->GetData();
121
if ( !numFiles && menu->GetMenuItemCount() )
122
menu->AppendSeparator();
124
// label doesn't matter, it will be set below anyhow, but it can't
125
// be empty (this is supposed to indicate a stock item)
126
menu->Append(m_idBase + numFiles, " ");
129
// insert the new file in the beginning of the file history
130
m_fileHistory.insert(m_fileHistory.begin(), file);
133
// update the labels in all menus
134
for ( i = 0; i < numFiles; i++ )
136
// if in same directory just show the filename; otherwise the full path
137
const wxFileName fnOld(m_fileHistory[i]);
140
if ( fnOld.GetPath() == fnNew.GetPath() )
142
pathInMenu = fnOld.GetFullName();
144
else // file in different directory
146
// absolute path; could also set relative path
147
pathInMenu = m_fileHistory[i];
150
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
152
node = node->GetNext() )
154
wxMenu * const menu = (wxMenu *)node->GetData();
156
menu->SetLabel(m_idBase + i, GetMRUEntryLabel(i, pathInMenu));
161
void wxFileHistoryBase::RemoveFileFromHistory(size_t i)
163
size_t numFiles = m_fileHistory.size();
164
wxCHECK_RET( i < numFiles,
165
wxT("invalid index in wxFileHistoryBase::RemoveFileFromHistory") );
167
// delete the element from the array
168
m_fileHistory.RemoveAt(i);
171
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
173
node = node->GetNext() )
175
wxMenu * const menu = (wxMenu *) node->GetData();
177
// shift filenames up
178
for ( size_t j = i; j < numFiles; j++ )
180
menu->SetLabel(m_idBase + j, GetMRUEntryLabel(j, m_fileHistory[j]));
183
// delete the last menu item which is unused now
184
const wxWindowID lastItemId = m_idBase + numFiles;
185
if ( menu->FindItem(lastItemId) )
186
menu->Delete(lastItemId);
188
// delete the last separator too if no more files are left
189
if ( m_fileHistory.empty() )
191
const wxMenuItemList::compatibility_iterator
192
nodeLast = menu->GetMenuItems().GetLast();
195
wxMenuItem * const lastMenuItem = nodeLast->GetData();
196
if ( lastMenuItem->IsSeparator() )
197
menu->Delete(lastMenuItem);
199
//else: menu is empty somehow
204
void wxFileHistoryBase::UseMenu(wxMenu *menu)
206
if ( !m_fileMenus.Member(menu) )
207
m_fileMenus.Append(menu);
210
void wxFileHistoryBase::RemoveMenu(wxMenu *menu)
212
m_fileMenus.DeleteObject(menu);
216
void wxFileHistoryBase::Load(const wxConfigBase& config)
218
m_fileHistory.Clear();
221
buf.Printf(wxT("file%d"), 1);
223
wxString historyFile;
224
while ((m_fileHistory.GetCount() < m_fileMaxFiles) &&
225
config.Read(buf, &historyFile) && !historyFile.empty())
227
m_fileHistory.Add(historyFile);
229
buf.Printf(wxT("file%d"), (int)m_fileHistory.GetCount()+1);
230
historyFile = wxEmptyString;
236
void wxFileHistoryBase::Save(wxConfigBase& config)
239
for (i = 0; i < m_fileMaxFiles; i++)
242
buf.Printf(wxT("file%d"), (int)i+1);
243
if (i < m_fileHistory.GetCount())
244
config.Write(buf, wxString(m_fileHistory[i]));
246
config.Write(buf, wxEmptyString);
249
#endif // wxUSE_CONFIG
251
void wxFileHistoryBase::AddFilesToMenu()
253
if ( m_fileHistory.empty() )
256
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
258
node = node->GetNext() )
260
AddFilesToMenu((wxMenu *) node->GetData());
264
void wxFileHistoryBase::AddFilesToMenu(wxMenu* menu)
266
if ( m_fileHistory.empty() )
269
if ( menu->GetMenuItemCount() )
270
menu->AppendSeparator();
272
for ( size_t i = 0; i < m_fileHistory.GetCount(); i++ )
274
menu->Append(m_idBase + i, GetMRUEntryLabel(i, m_fileHistory[i]));
278
#endif // wxUSE_FILE_HISTORY