]> git.saurik.com Git - wxWidgets.git/blame - src/common/filehistorycmn.cpp
Use C locale representation for floating point numbers in wxAny.
[wxWidgets.git] / src / common / filehistorycmn.cpp
CommitLineData
a0219e45
VS
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/filehistorycmn.cpp
3// Purpose: wxFileHistory class
4// Author: Julian Smart, Vaclav Slavik, Vadim Zeitlin
5// Created: 2010-05-03
6// RCS-ID: $Id$
7// Copyright: (c) Julian Smart
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
26#include "wx/filehistory.h"
27
28#if wxUSE_FILE_HISTORY
29
30#include "wx/menu.h"
31#include "wx/confbase.h"
32#include "wx/filename.h"
33
34// ============================================================================
35// implementation
36// ============================================================================
37
38// ----------------------------------------------------------------------------
39// private helpers
40// ----------------------------------------------------------------------------
41
42namespace
43{
44
45// return the string used for the MRU list items in the menu
46//
47// NB: the index n is 0-based, as usual, but the strings start from 1
48wxString GetMRUEntryLabel(int n, const wxString& path)
49{
50 // we need to quote '&' characters which are used for mnemonics
51 wxString pathInMenu(path);
52 pathInMenu.Replace("&", "&&");
53
54 return wxString::Format("&%d %s", n + 1, pathInMenu);
55}
56
57} // anonymous namespace
58
59// ----------------------------------------------------------------------------
60// File history (a.k.a. MRU, most recently used, files list)
61// ----------------------------------------------------------------------------
62
63IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject)
64
690ddfec 65wxFileHistoryBase::wxFileHistoryBase(size_t maxFiles, wxWindowID idBase)
a0219e45
VS
66{
67 m_fileMaxFiles = maxFiles;
68 m_idBase = idBase;
69}
70
406a0ab3
VZ
71/* static */
72wxString wxFileHistoryBase::NormalizeFileName(const wxFileName& fn)
73{
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 |
81 wxPATH_NORM_TILDE |
82 wxPATH_NORM_CASE |
83 wxPATH_NORM_ABSOLUTE);
84 return fnNorm.GetFullPath();
85}
86
690ddfec 87void wxFileHistoryBase::AddFileToHistory(const wxString& file)
a0219e45 88{
406a0ab3
VZ
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.
a0219e45 94 const wxFileName fnNew(file);
406a0ab3 95 const wxString newFile = NormalizeFileName(fnNew);
a0219e45
VS
96 size_t i,
97 numFiles = m_fileHistory.size();
98 for ( i = 0; i < numFiles; i++ )
99 {
406a0ab3 100 if ( newFile == NormalizeFileName(m_fileHistory[i]) )
a0219e45
VS
101 {
102 // we do have it, move it to the top of the history
103 RemoveFileFromHistory(i);
104 numFiles--;
105 break;
106 }
107 }
108
109 // if we already have a full history, delete the one at the end
110 if ( numFiles == m_fileMaxFiles )
111 {
112 RemoveFileFromHistory(--numFiles);
113 }
114
115 // add a new menu item to all file menus (they will be updated below)
116 for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
117 node;
118 node = node->GetNext() )
119 {
120 wxMenu * const menu = (wxMenu *)node->GetData();
121
122 if ( !numFiles && menu->GetMenuItemCount() )
123 menu->AppendSeparator();
124
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, " ");
128 }
129
130 // insert the new file in the beginning of the file history
131 m_fileHistory.insert(m_fileHistory.begin(), file);
132 numFiles++;
133
134 // update the labels in all menus
135 for ( i = 0; i < numFiles; i++ )
136 {
137 // if in same directory just show the filename; otherwise the full path
138 const wxFileName fnOld(m_fileHistory[i]);
139
140 wxString pathInMenu;
141 if ( fnOld.GetPath() == fnNew.GetPath() )
142 {
143 pathInMenu = fnOld.GetFullName();
144 }
145 else // file in different directory
146 {
147 // absolute path; could also set relative path
148 pathInMenu = m_fileHistory[i];
149 }
150
151 for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
152 node;
153 node = node->GetNext() )
154 {
155 wxMenu * const menu = (wxMenu *)node->GetData();
156
157 menu->SetLabel(m_idBase + i, GetMRUEntryLabel(i, pathInMenu));
158 }
159 }
160}
161
690ddfec 162void wxFileHistoryBase::RemoveFileFromHistory(size_t i)
a0219e45
VS
163{
164 size_t numFiles = m_fileHistory.size();
165 wxCHECK_RET( i < numFiles,
690ddfec 166 wxT("invalid index in wxFileHistoryBase::RemoveFileFromHistory") );
a0219e45
VS
167
168 // delete the element from the array
169 m_fileHistory.RemoveAt(i);
170 numFiles--;
171
172 for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
173 node;
174 node = node->GetNext() )
175 {
176 wxMenu * const menu = (wxMenu *) node->GetData();
177
178 // shift filenames up
179 for ( size_t j = i; j < numFiles; j++ )
180 {
181 menu->SetLabel(m_idBase + j, GetMRUEntryLabel(j, m_fileHistory[j]));
182 }
183
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);
188
189 // delete the last separator too if no more files are left
190 if ( m_fileHistory.empty() )
191 {
192 const wxMenuItemList::compatibility_iterator
193 nodeLast = menu->GetMenuItems().GetLast();
194 if ( nodeLast )
195 {
196 wxMenuItem * const lastMenuItem = nodeLast->GetData();
197 if ( lastMenuItem->IsSeparator() )
198 menu->Delete(lastMenuItem);
199 }
200 //else: menu is empty somehow
201 }
202 }
203}
204
690ddfec 205void wxFileHistoryBase::UseMenu(wxMenu *menu)
a0219e45
VS
206{
207 if ( !m_fileMenus.Member(menu) )
208 m_fileMenus.Append(menu);
209}
210
690ddfec 211void wxFileHistoryBase::RemoveMenu(wxMenu *menu)
a0219e45
VS
212{
213 m_fileMenus.DeleteObject(menu);
214}
215
216#if wxUSE_CONFIG
690ddfec 217void wxFileHistoryBase::Load(const wxConfigBase& config)
a0219e45
VS
218{
219 m_fileHistory.Clear();
220
221 wxString buf;
222 buf.Printf(wxT("file%d"), 1);
223
224 wxString historyFile;
225 while ((m_fileHistory.GetCount() < m_fileMaxFiles) &&
226 config.Read(buf, &historyFile) && !historyFile.empty())
227 {
228 m_fileHistory.Add(historyFile);
229
230 buf.Printf(wxT("file%d"), (int)m_fileHistory.GetCount()+1);
231 historyFile = wxEmptyString;
232 }
233
234 AddFilesToMenu();
235}
236
690ddfec 237void wxFileHistoryBase::Save(wxConfigBase& config)
a0219e45
VS
238{
239 size_t i;
240 for (i = 0; i < m_fileMaxFiles; i++)
241 {
242 wxString buf;
243 buf.Printf(wxT("file%d"), (int)i+1);
244 if (i < m_fileHistory.GetCount())
245 config.Write(buf, wxString(m_fileHistory[i]));
246 else
247 config.Write(buf, wxEmptyString);
248 }
249}
250#endif // wxUSE_CONFIG
251
690ddfec 252void wxFileHistoryBase::AddFilesToMenu()
a0219e45
VS
253{
254 if ( m_fileHistory.empty() )
255 return;
256
257 for ( wxList::compatibility_iterator node = m_fileMenus.GetFirst();
258 node;
259 node = node->GetNext() )
260 {
261 AddFilesToMenu((wxMenu *) node->GetData());
262 }
263}
264
690ddfec 265void wxFileHistoryBase::AddFilesToMenu(wxMenu* menu)
a0219e45
VS
266{
267 if ( m_fileHistory.empty() )
268 return;
269
270 if ( menu->GetMenuItemCount() )
271 menu->AppendSeparator();
272
273 for ( size_t i = 0; i < m_fileHistory.GetCount(); i++ )
274 {
275 menu->Append(m_idBase + i, GetMRUEntryLabel(i, m_fileHistory[i]));
276 }
277}
278
279#endif // wxUSE_FILE_HISTORY