OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
rcntfile.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// ObjectWindows
3// Copyright (c) 1995, 1996 by Borland International, All Rights Reserved
4//
5/// \file
6/// Implementation of class TRecentFiles
7//----------------------------------------------------------------------------
8#include <owl/pch.h>
9
10//#if !defined(__GNUC__) //JJH added removal of pragma hdrstop for gcc
11#pragma hdrstop
12//#endif
13
14#include <owl/framewin.h>
15#include <owl/rcntfile.h>
16#include <owl/pointer.h>
17#include <owl/profile.h>
18#include <owl/registry.h>
19#include <owl/window.rh>
20#include <owl/editfile.rh>
21#include <stdio.h>
22
23#include <algorithm>
24
25#include <owl/rcntfile.rh> //for CM_MRU_FIRST
26
27namespace owl {
28
30
31const int CM_MRU_LAST = CM_MRU_FIRST + TRecentFiles::MaxMenuItems;
34
35#if defined(WINELIB) //JJH's work
36static const tchar* CountKey = _T("Count");
37static const tchar* MruPrefix = _T("File");
38static const tchar* MenuItemDefault= _T("Default");
39static const tchar* Section = _T("Recent File List");
40static const tchar* MaxCountKey = _T("MaxCount");
41#else
42const tchar* CountKey = _T("Count");
43const tchar* MruPrefix = _T("File");
44const tchar* MenuItemDefault= _T("Default");
45const tchar* Section = _T("Recent File List");
46const tchar* MaxCountKey = _T("MaxCount");
47#endif
48const int MaxMenuItemLen = 255;
50uint TRecentFiles::MruMessage = 0;
51
52//
53// Response Table to catch the items selected from the menu.
54//
56 EV_COMMAND_AND_ID(CM_MRU_FIRST + 0, CmFile),
57 EV_COMMAND_AND_ID(CM_MRU_FIRST + 1, CmFile),
58 EV_COMMAND_AND_ID(CM_MRU_FIRST + 2, CmFile),
59 EV_COMMAND_AND_ID(CM_MRU_FIRST + 3, CmFile),
60 EV_COMMAND_AND_ID(CM_MRU_FIRST + 4, CmFile),
61 EV_COMMAND_AND_ID(CM_MRU_FIRST + 5, CmFile),
62 EV_COMMAND_AND_ID(CM_MRU_FIRST + 6, CmFile),
63 EV_COMMAND_AND_ID(CM_MRU_FIRST + 7, CmFile),
64 EV_COMMAND_AND_ID(CM_MRU_FIRST + 8, CmFile),
65 EV_COMMAND_AND_ID(CM_MRU_FIRST + 9, CmFile),
66 EV_COMMAND_ENABLE(CM_EXIT, CeExit),
68
69
70static int
71TRecentFiles__ReadMaxNum(bool useRegistry, const tstring& mruName,
72 int defaultCount)
73{
74 const auto getMaxCount = [&]() -> int
75 {
76 if (useRegistry)
77 {
78 if (const auto k = TRegKey::GetCurrentUser().GetSubkey(mruName))
79 if (const auto v = k->GetValue(MaxCountKey))
80 return static_cast<int>(static_cast<uint32>(*v));
81 return defaultCount;
82 }
83 else
84 return TProfile{Section, mruName}.GetInt(MaxCountKey, defaultCount);
85 };
86 return std::min(getMaxCount(), static_cast<int>(TRecentFiles::MaxMenuItems));
87}
88
89
90
91//
92/// Constructor to initialize the external storage and the maximum number of items
93/// to save in the most-recently-used (MRU) list.
94//
95TRecentFiles::TRecentFiles(const tstring& iniName, int numSavedFiles,
96 int namelen, bool useRegistry, bool keepFullNameInMenu)
97:
98 MaxFilesToSave(0),
99 MaxDispLen(namelen),
100 AddedSeparator(false),
101 UseRegistry(useRegistry),
102 LastHMenu(nullptr),
103 MruCount(0),
104 keepFullNameInMenu(keepFullNameInMenu)
105{
106 int filestosave = std::min(numSavedFiles, static_cast<int>(MaxMenuItems));
107 MruName = iniName;
108 if(UseRegistry){
109 MruName += _T("\\");
110 MruName += Section;
111 }
112 else
113 MruName = TFileName(iniName).Canonical();
114
115 if(filestosave < 0)
116 filestosave = TRecentFiles__ReadMaxNum(UseRegistry, MruName, filestosave);
117
118 SetMaxMruItems(filestosave);
119 MruMessage = ::RegisterWindowMessage(MruFileMessage);
120
121 Read();
122}
123
124//
125/// Deletes the allocated profile.
126//
128{
129 Write();
130}
131
132//
133/// Sets the maximum number of items that can be saved with this MRU.
134//
135void
137{
138 if(numItems > MaxFilesToSave){
139 TFileName* items = new TFileName[numItems];
140 for(int i = 0; i < MaxFilesToSave && i < numItems; i++)
141 items[i] = MruNames[i];
142 MruNames = items;
143 }
144 MaxFilesToSave = numItems;
145}
146
147//
148/// Responds to a menu item selection.
149//
150void
152{
154 TFrameWindow* window = app ? app->GetMainWindow() : nullptr;
155
156 if (window) {
157 // Foward menu selection command to specified target
158 //
159 window->SendMessage(MruMessage, id, 0);
160 }
161}
162
163//
164/// Searches the menu to find the position of a menu item.
165//
166int
168{
169 for (int i = ::GetMenuItemCount(menu) - 1; i >= 0; i--)
170 if (::GetMenuItemID(menu, i) == id)
171 return i;
172 return -1;
173}
174
175//
176/// Retrieves the menu position of the CM_EXIT menu item. Returns -1 if not found.
177//
178int
180{
181 int exitPos = GetMenuPos(hMenu, CM_EXIT);
182 return exitPos;
183}
184
185//
186/// Returns true if the menu has any MRU items in it.
187//
188bool
190{
191 int menuPos = GetMenuPos(hMenu, CM_MRU_FIRST + 0);
192 return menuPos != -1;
193}
194
195//
196/// Removes the MRU items from the menu.
197//
198void
200{
201 int exitPos = GetExitMenuPos(hMenu);
202 if (exitPos > 1)
203 if (::GetMenuItemID(hMenu, exitPos - 1) == 0 && AddedSeparator) {
204 AddedSeparator = false;
205 if (LastHMenu == hMenu)
206 ::RemoveMenu(hMenu, exitPos - 1, MF_BYPOSITION);
207 }
208
209 // remove MRU items
210 //
211 if (MruItemsInsertedIntoMenu(hMenu)) {
212 for (int i = CM_MRU_FIRST; i < CM_MRU_LAST; i++) {
213 int menuPos = GetMenuPos(hMenu, i);
214 if (menuPos != -1) {
215 ::RemoveMenu(hMenu, i, MF_BYCOMMAND);
216 }
217 }
218 }
219}
220
221//
222/// Reads external information and adds the MRU items into the menu. Adds a
223/// separator between the MRU items and the exit menu item.
224//
225void
227{
228 TAPointer<tchar> menuItemBuffer(new tchar[MaxMenuItemLen+4]);
229
230 TMenu menu(hMenu);
231 int exitPos = GetExitMenuPos(hMenu);
232 //int count = GetMruCount();
233 int i;
234 int numItemsAdded = 0;
235
237
238 for (i = 0; i < MruCount; i++) {
239 //if(!MruNames[i].IsValid()) //?????????????
240 // break;
241
242 numItemsAdded++;
243
244 tstring curname = MruNames[i].GetParts(FullFileName);
245 if(curdir == MruNames[i].GetParts(FullPathName))
246 curname = MruNames[i].GetParts(TFileName::File|TFileName::Ext);
247 curname = TFileName(curname).Squeezed(MaxDispLen, keepFullNameInMenu);
248 // insert mnemonic + the file name
249 if((i+1) >= 10)
250 wsprintf(menuItemBuffer, _T("%d&%d %s"), (i+1)/10, (i+1)%10, curname.c_str());
251 else
252 wsprintf(menuItemBuffer, _T("&%d %s"), (i+1), curname.c_str());
253
254 menu.InsertMenu(exitPos + i, MF_BYPOSITION | MF_STRING, CM_MRU_FIRST + i, menuItemBuffer);
255 }
256
257 if (numItemsAdded > 0) {
258 if (AddedSeparator == false) {
259 LastHMenu = hMenu;
260 AddedSeparator = true;
261 menuItemBuffer[0] = 0;
262 ::InsertMenu(hMenu, exitPos + numItemsAdded, MF_BYPOSITION|MF_SEPARATOR, 0, menuItemBuffer);
263 }
264 }
265}
266
267//
268/// Reads information in the TProfile to display the menu choices.
269//
270void
272{
273 ce.Enable(true);
274
276 if (me == nullptr)
277 return;
278
279 HMENU hMenu = me->GetMenu();
282}
283
284/// Retrieves the text of the choice based on the ID.
287{
288 id -= CM_MRU_FIRST;
289 if (id < 0 || MruCount <= id)
290 return tstring(_T(""));
291 return MruNames[id].GetParts(FullFileName);
292}
293
294//
295/// Retrieves the text of the choice based on the ID.
296//
297bool
298TRecentFiles::GetMenuText(int id, LPTSTR text, int maxTextLen)
299{
300 id -= CM_MRU_FIRST;
301 //int count = GetMruCount();
302 if (id < 0 || MruCount <= id)
303 return false;
304 tstring menuText = MruNames[id].GetParts(FullFileName);
305 if(::_tcslen(menuText.c_str()) > (size_t)maxTextLen){
306 _tcsncpy(text, menuText.c_str(), maxTextLen-1);
307 text[maxTextLen] = _T('\0');
308 }
309 else
310 ::_tcscpy(text, menuText.c_str());
311 return true;
312}
313
314//
315/// Saves the menu choice into the profile.
316//
317void
319{
320 int index = GetMruItemIndex(text);
321 RemoveMruIndex(index);
322 AddMruItem(text);
323}
324
325//
326// Remove the menu choice.
327//
328void
333
334//
335/// Removes the MRU item at index. Shuffles the items below index up.
336//
337void
339{
340 //int count = GetMruCount();
341 if (index < 0 || MruCount <= index)
342 return;
343
344 if (index != MruCount - 1) {
345 // shuffle so the item to be deleted is at index count-1
346 //
347 for(int i = index; i < MruCount - 1; i++)
348 MruNames[i] = MruNames[i+1];
349 }
350
351 // delete the last item
352 //
353 MruNames[MruCount-1] = _T("");
354 MruCount--; // decrease MRUCount
355}
356
357//
358/// Adds an item to the top of the MRU list. If there is a duplicate, the item is
359/// moved from its current position to the top of the list.
360//
361void
363{
364 if (MaxFilesToSave <= 0)
365 return;
366 tstring sFullFilePath = TFileName(text).Canonical();
367 if (sFullFilePath.empty())
368 return;
369 if(MruCount < MaxFilesToSave)
370 MruCount++;
371 if (MruCount > 1){
372 // Shuffle items down to make room at index 0
373 //
374 for (int i = MruCount - 2; i >= 0; i--)
375 MruNames[i+1] = MruNames[i];
376 }
377
378 // Add item to the top of the list
379 //
380 MruNames[0] = sFullFilePath;
381}
382
383//
384/// Returns true if there are any items in the MRU list that match the text.
385//
386bool
388{
389 return GetMruItemIndex(text) != -1;
390}
391
392//
393/// Returns the index of the MRU item containing text. Returns -1 if not found.
394//
395int
397{
398 TFileName filename(TFileName(text).Canonical());
399 for (int i = 0; i < MruCount; i++) {
400 if(MruNames[i] == filename)
401 return i;
402 }
403 return -1;
404}
405//
406// Read Data from registry or file
407//
408void
409TRecentFiles::Read()
410{
411 if (UseRegistry)
412 {
413 const auto k = TRegKey::GetCurrentUser().GetSubkey(MruName);
414 WARN(!k, _T("Registry key is missing for MRU: HKEY_CURRENT_USER\\") << MruName);
415 if (!k) return;
416 const auto c = k->GetValue(CountKey);
417 WARN(!c, _T("Registry value is missing for MRU: ") << CountKey);
418 if (!c) return;
419 MruCount = std::min(static_cast<int>(static_cast<uint32>(*c)), MaxFilesToSave);
420 for (auto i = 0; i != MruCount; ++i)
421 {
422 const auto f = k->GetValue(MruPrefix + to_tstring(i));
423 WARN(!f, _T("Registry value is missing for MRU: " << MruPrefix << i));
424 if (!f) return;
425 MruNames[i] = *f;
426 }
427 }
428 else
429 {
430 TAPointer<tchar> srcKeyBuffer(new tchar[80]);
431 TAPointer<tchar> menuText(new tchar[MaxRegValueLen]);
432 TProfile profile(Section, MruName.c_str());
433 MruCount = profile.GetInt(CountKey, 0);
434 if (MruCount > MaxFilesToSave)
435 MruCount = MaxFilesToSave;
436 for (int i = 0; i < MruCount; i++){
437 wsprintf(srcKeyBuffer, _T("%s%d"), MruPrefix, i);
438 profile.GetString(srcKeyBuffer, menuText, MaxMenuItemLen, MenuItemDefault);
439 MruNames[i] = (tchar*)menuText;
440 }
441 }
442}
443//
444// Write data to registry or file
445//
446void
447TRecentFiles::Write()
448{
449 if (UseRegistry)
450 {
451 auto& c = TRegKey::GetCurrentUser();
452 [[maybe_unused]] const auto r = c.DeleteKey(MruName);
453 CHECK(r == ERROR_SUCCESS || r == ERROR_FILE_NOT_FOUND || r == ERROR_PATH_NOT_FOUND);
454 auto k = TRegKey{c, MruName}; CHECK(k.GetHandle());
455 TRegValue{k, CountKey} = static_cast<uint32>(MruCount);
456 for (auto i = 0; i != MruCount; ++i)
457 TRegValue{k, MruPrefix + to_tstring(i)} = MruNames[i].GetParts(FullFileName);
458 }
459 else
460 {
461 TAPointer<tchar> dstKeyBuffer(new tchar[80]);
462 TProfile profile(Section, MruName.c_str());
463 profile.WriteInt(CountKey, MruCount);
464 for (int i = 0; i < MruCount; i++){
465 wsprintf(dstKeyBuffer, _T("%s%d"), MruPrefix, i);
466 profile.WriteString(dstKeyBuffer, MruNames[i].GetParts(FullFileName));
467 }
468 }
469}
470
471} // OWL namespace
472
473/* ========================================================================== */
474
#define CHECK(condition)
Definition checks.h:239
#define WARN(condition, message)
Definition checks.h:273
Pointer to an array of type T.
Definition pointer.h:103
Derived from TModule and TMsgThread and virtually derived from TEventHandler, TApplication acts as an...
Definition applicat.h:141
TFrameWindow * GetMainWindow()
Return the current main window.
Definition applicat.h:592
Base class for an extensible interface for auto enabling/disabling of commands (menu items,...
Definition window.h:209
virtual void Enable(bool enable=true)
Enables or disables the command sender.
Definition window.cpp:301
TEventHandler is a base class from which you can derive classes that handle messages.
Definition eventhan.h:162
The TFileName class constructs filenames.
Definition filename.h:37
TFileName()
Constructs an empty filename.
Definition filename.cpp:225
@ Device
Logical device or sharename.
Definition filename.h:127
@ Path
Directory path to the file.
Definition filename.h:128
@ Ext
Extension.
Definition filename.h:130
@ File
Filename part without the extension.
Definition filename.h:129
@ Server
Server name.
Definition filename.h:126
@ CurrentDir
Current working directory if any.
Definition filename.h:94
Derived from TWindow, TFrameWindow controls such window-specific behavior as keyboard navigation and ...
Definition framewin.h:96
The TMenu class encapsulates window menus.
Definition menu.h:77
bool InsertMenu(uint item, uint flags, TMenuItem newItem=-1, LPCTSTR newStr=nullptr)
Inserts a new text menu item or pop-up menu into the menu after the menu item specified in item.
Definition menu.h:458
Derived from TCommandEnabler, TMenuItemEnabler is a command enabler for menu items.
Definition framewin.h:39
HMENU GetMenu()
Returns the menu that holds the item being enabled or disabled.
Definition framewin.h:280
An instance of TProfile encapsulates a setting within a system file, often referred to as a profile o...
Definition profile.h:44
int GetInt(LPCTSTR key, int defaultInt=0)
Looks up and returns the integer value associated with the given string, key.
Definition profile.cpp:86
TRecentFiles implements a most-recent files list, designed to be mixed in with TApplication.
Definition rcntfile.h:39
void CeExit(TCommandEnabler &ce)
Reads information in the TProfile to display the menu choices.
Definition rcntfile.cpp:271
void SaveMenuChoice(LPCTSTR text)
Saves the menu choice into the profile.
Definition rcntfile.cpp:318
void InsertMruItemsToMenu(HMENU hMenu)
Reads external information and adds the MRU items into the menu.
Definition rcntfile.cpp:226
int GetMenuPos(HMENU hMenu, uint id)
Searches the menu to find the position of a menu item.
Definition rcntfile.cpp:167
int GetExitMenuPos(HMENU hMenu)
Retrieves the menu position of the CM_EXIT menu item. Returns -1 if not found.
Definition rcntfile.cpp:179
bool GetMenuText(int id, TCHAR *text, int maxTextLen)
Retrieves the text of the choice based on the ID.
Definition rcntfile.cpp:298
void RemoveMruIndex(int index)
Removes the MRU item at index. Shuffles the items below index up.
Definition rcntfile.cpp:338
virtual ~TRecentFiles()
Deletes the allocated profile.
Definition rcntfile.cpp:127
void SetMaxMruItems(int maxValue)
Sets the maximum number of items that can be saved with this MRU.
Definition rcntfile.cpp:136
void CmFile(uint id)
Responds to a menu item selection.
Definition rcntfile.cpp:151
bool ExistMruItem(LPCTSTR text)
Returns true if there are any items in the MRU list that match the text.
Definition rcntfile.cpp:387
int GetMruItemIndex(LPCTSTR text)
Returns the index of the MRU item containing text. Returns -1 if not found.
Definition rcntfile.cpp:396
TRecentFiles(const tstring &iniOrKeyName, int numSavedFiles=MaxMenuItems, int namelen=30, bool useRegistry=false, bool keepFullNameInMenu=true)
Constructor to initialize the external storage and the maximum number of items to save in the most-re...
Definition rcntfile.cpp:95
void RemoveMruItemsFromMenu(HMENU hMenu)
Removes the MRU items from the menu.
Definition rcntfile.cpp:199
void RemoveMenuChoice(LPCTSTR text)
Definition rcntfile.cpp:329
bool MruItemsInsertedIntoMenu(HMENU hMenu)
Returns true if the menu has any MRU items in it.
Definition rcntfile.cpp:189
void AddMruItem(LPCTSTR text)
Adds an item to the top of the MRU list.
Definition rcntfile.cpp:362
static auto GetCurrentUser() -> TRegKey &
Special predefined root key defining the preferences of the current user (HKEY_CURRENT_USER).
Definition registry.cpp:72
TResult SendMessage(TMsgId, TParam1=0, TParam2=0) const
Sends a message (msg) to a specified window or windows.
Definition window.cpp:3288
#define _tcsncpy
Definition cygwin.h:80
#define _tcslen
Definition cygwin.h:74
#define _T(x)
Definition cygwin.h:51
#define DEFINE_RESPONSE_TABLE1(cls, base)
Macro to define a response table for a class with one base.
Definition eventhan.h:492
Definition of class TFrameWindow.
Object Windows Library (OWLNext Core).
Definition animctrl.h:22
const tchar * MruPrefix
Definition rcntfile.cpp:43
const int CM_MRU_LAST
Definition rcntfile.cpp:31
EV_COMMAND_AND_ID(CM_MRU_FIRST+0, CmFile)
const tchar * Section
Definition rcntfile.cpp:45
unsigned long uint32
Definition number.h:34
const tchar * MaxCountKey
Definition rcntfile.cpp:46
const uint FullPathName
Definition rcntfile.cpp:32
char tchar
Definition defs.h:77
const tchar * CountKey
Definition rcntfile.cpp:42
OWL_DIAGINFO
Definition animctrl.cpp:14
const uint FullFileName
Definition rcntfile.cpp:33
END_RESPONSE_TABLE
Definition button.cpp:26
std::string tstring
Definition defs.h:79
EV_COMMAND_ENABLE(CM_FILENEW, CeFileNew)
const int MaxMenuItemLen
Definition rcntfile.cpp:48
unsigned int uint
Definition number.h:25
const int MaxRegValueLen
Definition rcntfile.cpp:49
auto to_tstring(const T &v) -> tstring
Definition defs.h:82
const tchar * MenuItemDefault
Definition rcntfile.cpp:44
#define TYPESAFE_DOWNCAST(object, toClass)
Definition defs.h:269
Various types of smart pointer templatized classes.
Definition of TProfile class.
Definition of TRecentFiles class.
#define MruFileMessage
Derived classes should catch the following registered message to know when an item in the recent list...
Definition rcntfile.h:27
General Registry access & registration implementation TRegKey, TRegValue, TRegKeyIterator,...