1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/common/filehistorycmn.cpp
3
// Purpose: wxFileHistory class
4
// Author: Julian Smart, Vaclav Slavik, Vadim Zeitlin
6
// RCS-ID: $Id: filehistorycmn.cpp 70503 2012-02-03 17:27:13Z VZ $
7
// Copyright: (c) Julian Smart
8
// Licence: wxWindows licence
9
/////////////////////////////////////////////////////////////////////////////
11
// ============================================================================
13
// ============================================================================
15
// ----------------------------------------------------------------------------
17
// ----------------------------------------------------------------------------
19
// For compilers that support precompilation, includes "wx.h".
20
#include "wx/wxprec.h"
26
#include "wx/filehistory.h"
28
#if wxUSE_FILE_HISTORY
31
#include "wx/confbase.h"
32
#include "wx/filename.h"
34
// ============================================================================
36
// ============================================================================
38
// ----------------------------------------------------------------------------
40
// ----------------------------------------------------------------------------
45
// return the string used for the MRU list items in the menu
47
// NB: the index n is 0-based, as usual, but the strings start from 1
48
wxString GetMRUEntryLabel(int n, const wxString& path)
50
// we need to quote '&' characters which are used for mnemonics
51
wxString pathInMenu(path);
52
pathInMenu.Replace("&", "&&");
54
return wxString::Format("&%d %s", n + 1, pathInMenu);
57
} // anonymous namespace
59
// ----------------------------------------------------------------------------
60
// File history (a.k.a. MRU, most recently used, files list)
61
// ----------------------------------------------------------------------------
63
IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
65
wxFileHistoryBase::wxFileHistoryBase(size_t maxFiles, wxWindowID idBase)
67
m_fileMaxFiles = maxFiles;
72
wxString wxFileHistoryBase::NormalizeFileName(const wxFileName& fn)
74
// We specifically exclude wxPATH_NORM_LONG here as it can take a long time
75
// (several seconds) for network file paths under MSW, resulting in huge
76
// delays when opening a program using wxFileHistory. We also exclude
77
// wxPATH_NORM_ENV_VARS as the file names here are supposed to be "real"
78
// file names and not have any environment variables in them.
79
wxFileName fnNorm(fn);
80
fnNorm.Normalize(wxPATH_NORM_DOTS |
83
wxPATH_NORM_ABSOLUTE);
84
return fnNorm.GetFullPath();
87
void wxFileHistoryBase::AddFileToHistory(const wxString& file)
89
// Check if we don't already have this file. Notice that we avoid
90
// wxFileName::operator==(wxString) here as it converts the string to
91
// wxFileName and then normalizes it using all normalizations which is too
92
// slow (see the comment above), so we use our own quick normalization
93
// functions and a string comparison.
94
const wxFileName fnNew(file);
95
const wxString newFile = NormalizeFileName(fnNew);
97
numFiles = m_fileHistory.size();
98
for ( i = 0; i < numFiles; i++ )
100
if ( newFile == NormalizeFileName(m_fileHistory[i]) )
102
// we do have it, move it to the top of the history
103
RemoveFileFromHistory(i);
109
// if we already have a full history, delete the one at the end
110
if ( numFiles == m_fileMaxFiles )
112
RemoveFileFromHistory(--numFiles);
115
// add a new menu item to all file menus (they will be updated below)
116
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
118
node = node->GetNext() )
120
wxMenu * const menu = (wxMenu *)node->GetData();
122
if ( !numFiles && menu->GetMenuItemCount() )
123
menu->AppendSeparator();
125
// label doesn't matter, it will be set below anyhow, but it can't
126
// be empty (this is supposed to indicate a stock item)
127
menu->Append(m_idBase + numFiles, " ");
130
// insert the new file in the beginning of the file history
131
m_fileHistory.insert(m_fileHistory.begin(), file);
134
// update the labels in all menus
135
for ( i = 0; i < numFiles; i++ )
137
// if in same directory just show the filename; otherwise the full path
138
const wxFileName fnOld(m_fileHistory[i]);
141
if ( fnOld.GetPath() == fnNew.GetPath() )
143
pathInMenu = fnOld.GetFullName();
145
else // file in different directory
147
// absolute path; could also set relative path
148
pathInMenu = m_fileHistory[i];
151
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
153
node = node->GetNext() )
155
wxMenu * const menu = (wxMenu *)node->GetData();
157
menu->SetLabel(m_idBase + i, GetMRUEntryLabel(i, pathInMenu));
162
void wxFileHistoryBase::RemoveFileFromHistory(size_t i)
164
size_t numFiles = m_fileHistory.size();
165
wxCHECK_RET( i < numFiles,
166
wxT("invalid index in wxFileHistoryBase::RemoveFileFromHistory") );
168
// delete the element from the array
169
m_fileHistory.RemoveAt(i);
172
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
174
node = node->GetNext() )
176
wxMenu * const menu = (wxMenu *) node->GetData();
178
// shift filenames up
179
for ( size_t j = i; j < numFiles; j++ )
181
menu->SetLabel(m_idBase + j, GetMRUEntryLabel(j, m_fileHistory[j]));
184
// delete the last menu item which is unused now
185
const wxWindowID lastItemId = m_idBase + numFiles;
186
if ( menu->FindItem(lastItemId) )
187
menu->Delete(lastItemId);
189
// delete the last separator too if no more files are left
190
if ( m_fileHistory.empty() )
192
const wxMenuItemList::compatibility_iterator
193
nodeLast = menu->GetMenuItems().GetLast();
196
wxMenuItem * const lastMenuItem = nodeLast->GetData();
197
if ( lastMenuItem->IsSeparator() )
198
menu->Delete(lastMenuItem);
200
//else: menu is empty somehow
205
void wxFileHistoryBase::UseMenu(wxMenu *menu)
207
if ( !m_fileMenus.Member(menu) )
208
m_fileMenus.Append(menu);
211
void wxFileHistoryBase::RemoveMenu(wxMenu *menu)
213
m_fileMenus.DeleteObject(menu);
217
void wxFileHistoryBase::Load(const wxConfigBase& config)
219
m_fileHistory.Clear();
222
buf.Printf(wxT("file%d"), 1);
224
wxString historyFile;
225
while ((m_fileHistory.GetCount() < m_fileMaxFiles) &&
226
config.Read(buf, &historyFile) && !historyFile.empty())
228
m_fileHistory.Add(historyFile);
230
buf.Printf(wxT("file%d"), (int)m_fileHistory.GetCount()+1);
231
historyFile = wxEmptyString;
237
void wxFileHistoryBase::Save(wxConfigBase& config)
240
for (i = 0; i < m_fileMaxFiles; i++)
243
buf.Printf(wxT("file%d"), (int)i+1);
244
if (i < m_fileHistory.GetCount())
245
config.Write(buf, wxString(m_fileHistory[i]));
247
config.Write(buf, wxEmptyString);
250
#endif // wxUSE_CONFIG
252
void wxFileHistoryBase::AddFilesToMenu()
254
if ( m_fileHistory.empty() )
257
for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
259
node = node->GetNext() )
261
AddFilesToMenu((wxMenu *) node->GetData());
265
void wxFileHistoryBase::AddFilesToMenu(wxMenu* menu)
267
if ( m_fileHistory.empty() )
270
if ( menu->GetMenuItemCount() )
271
menu->AppendSeparator();
273
for ( size_t i = 0; i < m_fileHistory.GetCount(); i++ )
275
menu->Append(m_idBase + i, GetMRUEntryLabel(i, m_fileHistory[i]));
279
#endif // wxUSE_FILE_HISTORY