mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-11 17:37:22 +10:00
266 lines
6.9 KiB
C++
266 lines
6.9 KiB
C++
// Classic Shell (c) 2009-2017, Ivo Beltchev
|
|
// Open-Shell (c) 2017-2018, The Open-Shell Team
|
|
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
|
|
|
|
#pragma once
|
|
|
|
#include "ItemManager.h"
|
|
#include <atldbcli.h>
|
|
#include <vector>
|
|
#include <list>
|
|
|
|
const int MAX_SEARCH_RESULTS=100; // per category
|
|
|
|
class CSearchManager
|
|
{
|
|
public:
|
|
CSearchManager( void );
|
|
~CSearchManager( void );
|
|
void Init( void );
|
|
void Close( void );
|
|
|
|
|
|
enum TItemCategory
|
|
{
|
|
CATEGORY_INVALID,
|
|
CATEGORY_PROGRAM,
|
|
CATEGORY_SETTING,
|
|
CATEGORY_METROSETTING,
|
|
CATEGORY_FILE,
|
|
CATEGORY_ITEM,
|
|
CATEGORY_INTERNET,
|
|
CATEGORY_AUTOCOMPLETE,
|
|
|
|
CATEGORY_MASK=15
|
|
};
|
|
|
|
struct SearchCategory
|
|
{
|
|
SearchCategory( void ) = default;
|
|
SearchCategory( const SearchCategory &cat )
|
|
{
|
|
search.Clone(cat.search);
|
|
categoryHash=cat.categoryHash;
|
|
name=cat.name;
|
|
items=cat.items;
|
|
}
|
|
CAbsolutePidl search;
|
|
unsigned int categoryHash;
|
|
CString name;
|
|
struct Item
|
|
{
|
|
CString name;
|
|
CAbsolutePidl pidl;
|
|
};
|
|
std::vector<Item> items;
|
|
};
|
|
|
|
struct SearchResults
|
|
{
|
|
bool bSearching;
|
|
bool bResults;
|
|
CString currentString;
|
|
CString autoCompletePath;
|
|
std::vector<const CItemManager::ItemInfo*> programs;
|
|
std::vector<const CItemManager::ItemInfo*> settings;
|
|
std::vector<const CItemManager::ItemInfo*> metrosettings;
|
|
std::vector<const CItemManager::ItemInfo*> autocomplete;
|
|
std::list<SearchCategory> indexed;
|
|
};
|
|
|
|
void BeginSearch( const CString &searchText );
|
|
void GetSearchResults( SearchResults &results );
|
|
void AddItemRank( unsigned int hash );
|
|
void CloseMenu( void );
|
|
|
|
void LaunchExternalSearch( PIDLIST_ABSOLUTE root, unsigned int categoryHash, const CString &searchText );
|
|
void LaunchInternetSearch( const CString &searchText );
|
|
|
|
private:
|
|
struct ItemRank
|
|
{
|
|
unsigned int hash; // hash of the item name in caps
|
|
int rank; // number of times it was used
|
|
int lastTime; // the last time it was updated (hi dword of FILETIME)
|
|
|
|
ItemRank( unsigned int _hash=0, int _rank=0, int _lastTime=0 ) { hash=_hash; rank=_rank; lastTime=_lastTime; }
|
|
bool operator<( const ItemRank &rank ) const { return hash<rank.hash; }
|
|
};
|
|
|
|
bool m_bRanksLoaded;
|
|
|
|
struct SearchItem
|
|
{
|
|
TItemCategory category;
|
|
CString name; // uppercase
|
|
CString keywords; // uppercase
|
|
const CItemManager::ItemInfo *pInfo;
|
|
int rank; // ignore the item if rank<0
|
|
bool bMetroLink;
|
|
|
|
SearchItem( void ) { category=CATEGORY_INVALID; pInfo=NULL; rank=0; bMetroLink=false; }
|
|
|
|
// 0 - no match, 1 - match name, 2 - match keywords
|
|
int MatchText( const wchar_t *search, bool bSearchSubWord ) const { return MatchTextInt(search,name,bSearchSubWord)?2:(MatchTextInt(search,keywords,bSearchSubWord)?1:0); }
|
|
bool operator<( const SearchItem &item ) const { return rank>item.rank || (rank==item.rank && wcscmp(name,item.name)<0); }
|
|
|
|
private:
|
|
static bool MatchTextInt( const wchar_t *search, const CString &text, bool bSearchSubWord );
|
|
};
|
|
|
|
bool m_bInitialized;
|
|
|
|
CString m_SearchText;
|
|
CString m_AutoCompletePath;
|
|
|
|
volatile int m_LastRequestId;
|
|
volatile int m_LastProgramsRequestId;
|
|
volatile int m_LastCompletedId;
|
|
|
|
struct SearchRequest
|
|
{
|
|
int requestId;
|
|
bool bSearchPrograms;
|
|
bool bSearchPath;
|
|
bool bSearchMetroApps;
|
|
bool bSearchMetroSettings;
|
|
bool bSearchSettings;
|
|
bool bSearchKeywords;
|
|
bool bSearchFiles;
|
|
bool bSearchMetadata;
|
|
bool bSearchTypes;
|
|
bool bSearchSubWord;
|
|
bool bUseRanks;
|
|
bool bNoCommonFolders;
|
|
bool bPinnedFolder;
|
|
DWORD searchTime;
|
|
CString searchText;
|
|
CString autoCompletePath;
|
|
};
|
|
|
|
// LOCK_DATA
|
|
SearchRequest m_SearchRequest;
|
|
std::vector<SearchItem> m_ProgramItems; // also LOCK_PROGRAMS
|
|
std::vector<SearchItem> m_SettingsItems; // also LOCK_PROGRAMS
|
|
std::vector<SearchItem> m_ProgramItemsOld;
|
|
std::vector<SearchItem> m_SettingsItemsOld;
|
|
unsigned int m_ProgramsHash;
|
|
unsigned int m_ProgramsHashOld;
|
|
unsigned int m_SettingsHash;
|
|
unsigned int m_SettingsHashOld;
|
|
bool m_bProgramsFound;
|
|
bool m_bSettingsFound;
|
|
bool m_bMetroSettingsFound = false;
|
|
std::vector<SearchItem> m_AutoCompleteItems;
|
|
std::list<SearchCategory> m_IndexedItems;
|
|
std::vector<ItemRank> m_ItemRanks;
|
|
CString m_LastAutoCompletePath;
|
|
|
|
enum
|
|
{
|
|
COLLECT_RECURSIVE =0x01, // go into subfolders
|
|
COLLECT_PROGRAMS =0x02, // only collect programs (.exe, .com, etc)
|
|
COLLECT_FOLDERS =0x04, // include folder items
|
|
COLLECT_METRO =0x08, // check for metro links (non-recursive)
|
|
COLLECT_ONLY_METRO =0x10, // collect only metro links
|
|
COLLECT_KEYWORDS =0x20, // include the keywords
|
|
COLLECT_LIBRARY =0x40, // the folder is a library
|
|
COLLECT_NOREFRESH =0x80, // suppress the refresh message
|
|
|
|
COLLECT_IS_FOLDER =0x8000
|
|
};
|
|
|
|
bool AddSearchItem( IShellItem *pItem, const wchar_t *name, int flags, TItemCategory category, SearchRequest &searchRequest );
|
|
void CollectSearchItems( IShellItem *pFolder, int flags, TItemCategory category, SearchRequest &searchRequest );
|
|
void CollectIndexItems( IShellItem *pFolder, int flags, TItemCategory category, const wchar_t *groupName );
|
|
|
|
enum TLock
|
|
{
|
|
LOCK_DATA,
|
|
LOCK_PROGRAMS,
|
|
LOCK_RANKS,
|
|
LOCK_COUNT,
|
|
};
|
|
|
|
CRITICAL_SECTION m_CriticalSections[LOCK_COUNT];
|
|
DWORD m_CriticalSectionOwners[LOCK_COUNT];
|
|
|
|
class Lock
|
|
{
|
|
public:
|
|
Lock( CSearchManager *pThis, TLock index )
|
|
{
|
|
m_pSection=&pThis->m_CriticalSections[index];
|
|
EnterCriticalSection(m_pSection);
|
|
m_pOwner=&pThis->m_CriticalSectionOwners[index];
|
|
if (!*m_pOwner)
|
|
*m_pOwner=GetCurrentThreadId();
|
|
else
|
|
m_pOwner=NULL;
|
|
}
|
|
|
|
~Lock( void )
|
|
{
|
|
if (m_pOwner) *m_pOwner=0;
|
|
LeaveCriticalSection(m_pSection);
|
|
}
|
|
|
|
private:
|
|
CRITICAL_SECTION *m_pSection;
|
|
DWORD *m_pOwner;
|
|
};
|
|
|
|
bool ThreadHasLock( TLock index ) { return m_CriticalSectionOwners[index]==GetCurrentThreadId(); }
|
|
|
|
HANDLE m_SearchEvent;
|
|
HANDLE m_ExitEvent;
|
|
HANDLE m_SearchThreads[8];
|
|
volatile long m_SearchThreadCount;
|
|
DWORD m_MainThreadId;
|
|
|
|
void LoadItemRanks( void );
|
|
void SearchThread( void );
|
|
static DWORD CALLBACK StaticSearchThread( void *param );
|
|
|
|
static bool CmpRankTime( const CSearchManager::ItemRank &rank1, const CSearchManager::ItemRank &rank2 );
|
|
static unsigned int CalcItemsHash( const std::vector<SearchItem> &items );
|
|
|
|
struct SearchScope
|
|
{
|
|
SearchScope( void ) { resultCount=0; categoryHash=0; bFiles=true; bCommunications=false; }
|
|
CAbsolutePidl search;
|
|
unsigned int categoryHash;
|
|
CString name;
|
|
bool bFiles;
|
|
bool bCommunications;
|
|
|
|
std::vector<CString> roots;
|
|
int resultCount;
|
|
|
|
bool ParseSearchConnector( const wchar_t *fname );
|
|
};
|
|
|
|
class CDataAccessor
|
|
{
|
|
public:
|
|
wchar_t itemUrl[_MAX_PATH];
|
|
wchar_t itemType[_MAX_PATH];
|
|
wchar_t parsingPath[_MAX_PATH];
|
|
wchar_t displayPath[_MAX_PATH];
|
|
wchar_t displayName[_MAX_PATH];
|
|
|
|
//Output Accessor
|
|
BEGIN_COLUMN_MAP(CDataAccessor)
|
|
COLUMN_ENTRY(1, itemUrl)
|
|
COLUMN_ENTRY(2, itemType)
|
|
COLUMN_ENTRY(3, parsingPath)
|
|
COLUMN_ENTRY(4, displayPath)
|
|
COLUMN_ENTRY(5, displayName)
|
|
END_COLUMN_MAP()
|
|
};
|
|
};
|
|
|
|
extern CSearchManager g_SearchManager;
|
|
|
|
bool HasSearchService( void );
|