1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/filehistorycmn.cpp
3 // Purpose: wxFileHistory class
4 // Author: Julian Smart, Vaclav Slavik, Vadim Zeitlin
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