diff --git a/reactos/subsys/system/explorer/dialogs/searchprogram.cpp b/reactos/subsys/system/explorer/dialogs/searchprogram.cpp index 1c941c4b62e..ff43aec495c 100644 --- a/reactos/subsys/system/explorer/dialogs/searchprogram.cpp +++ b/reactos/subsys/system/explorer/dialogs/searchprogram.cpp @@ -49,38 +49,49 @@ int CollectProgramsThread::Run() } catch(COMException&) { } + if (_alive) + _cache_valid = true; + return 0; } void CollectProgramsThread::collect_programs(const ShellPath& path) { - ShellDirectory dir(Desktop(), path, 0); + ShellDirectory* dir = new ShellDirectory(Desktop(), path, 0); + _dirs.push(dir); - dir.smart_scan(); + dir->smart_scan(); - for(const Entry*entry=dir._down; entry; entry=entry->_next) { + for(Entry*entry=dir->_down; entry; entry=entry->_next) { if (!_alive) break; if (entry->_shell_attribs & SFGAO_HIDDEN) continue; - const ShellEntry* shell_entry = static_cast(entry); + ShellEntry* shell_entry = static_cast(entry); if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) collect_programs(shell_entry->create_absolute_pidl()); else if (entry->_shell_attribs & SFGAO_LINK) if (_alive) - _callback(dir._folder, shell_entry, _para); + _callback(dir->_folder, shell_entry, _para); } +} - dir.free_subentries(); +void CollectProgramsThread::free_dirs() +{ + while(!_dirs.empty()) { + ShellDirectory* dir = _dirs.top(); + dir->free_subentries(); + _dirs.pop(); + } } #pragma warning(disable: 4355) -FindProgramTopicDlg::FindProgramTopicDlg(HWND hwnd) +FindProgramDlg::FindProgramDlg(HWND hwnd) : super(hwnd), _list_ctrl(GetDlgItem(hwnd, IDC_MAILS_FOUND)), _himl(ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32, 0, 0)), @@ -103,22 +114,36 @@ FindProgramTopicDlg::FindProgramTopicDlg(HWND hwnd) column.pszText = _T("Name"); ListView_InsertColumn(_list_ctrl, 0, &column); - column.cx = 400; + column.cx = 300; column.pszText = _T("Path"); ListView_InsertColumn(_list_ctrl, 1, &column); + column.cx = 400; + column.pszText = _T("Menu Path"); + ListView_InsertColumn(_list_ctrl, 2, &column); + ListView_SetExtendedListViewStyleEx(_list_ctrl, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); + _common_programs = SpecialFolderFSPath(CSIDL_COMMON_PROGRAMS, hwnd); + if (!_common_programs.empty()) + _common_programs.append(_T("\\")); + + _user_programs = SpecialFolderFSPath(CSIDL_PROGRAMS, hwnd); + if (!_user_programs.empty()) + _user_programs.append(_T("\\")); + + CenterWindow(hwnd); + Refresh(); } -FindProgramTopicDlg::~FindProgramTopicDlg() +FindProgramDlg::~FindProgramDlg() { ImageList_Destroy(_himl); } -void FindProgramTopicDlg::Refresh() +void FindProgramDlg::Refresh(bool delete_cache) { WaitCursor wait; @@ -126,82 +151,112 @@ void FindProgramTopicDlg::Refresh() TCHAR buffer[1024]; GetWindowText(GetDlgItem(_hwnd, IDC_TOPIC), buffer, 1024); - _filter = buffer; +#ifndef __WINE__ //TODO + _tcslwr(buffer); +#endif + _lwr_filter = buffer; ListView_DeleteAllItems(_list_ctrl); - _thread.Start(); + if (delete_cache || !_thread._cache_valid) { + _thread.free_dirs(); + _thread.Start(); + } else { + for(FPDCache::const_iterator it=_cache.begin(); it!=_cache.end(); ++it) + add_entry(*it); + } } -void FindProgramTopicDlg::collect_programs_callback(ShellFolder& folder, const ShellEntry* entry, void* param) +void FindProgramDlg::collect_programs_callback(ShellFolder& folder, ShellEntry* shell_entry, void* param) { - LPCITEMIDLIST pidl = entry->_pidl; + FindProgramDlg* pThis = (FindProgramDlg*) param; + LPCITEMIDLIST pidl = shell_entry->_pidl; IShellLink* pShellLink; HRESULT hr = folder->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (LPVOID*)&pShellLink); if (SUCCEEDED(hr)) { - WIN32_FIND_DATA wfd; + ShellLinkPtr shell_link(pShellLink); - /*hr = pShellLink->Resolve(_hwnd, SLR_NO_UI); - if (SUCCEEDED(NOERROR))*/ { + /*hr = pShellLink->Resolve(pThis->_hwnd, SLR_NO_UI); + if (SUCCEEDED(hr))*/ { + WIN32_FIND_DATA wfd; TCHAR path[MAX_PATH]; hr = pShellLink->GetPath(path, MAX_PATH-1, (WIN32_FIND_DATA*)&wfd, SLGP_UNCPRIORITY); if (SUCCEEDED(hr)) { - FindProgramTopicDlg* pThis = (FindProgramTopicDlg*) param; + FileSysShellPath entry_path(shell_entry->create_absolute_pidl()); + String menu_path; - String lwr_path = path; - String lwr_name = entry->_display_name; - String filter = pThis->_filter; + int len = pThis->_common_programs.size(); + if (len && !_tcsnicmp(entry_path, pThis->_common_programs, len)) + menu_path = ResString(IDS_ALL_USERS) + (String(entry_path)+len); + else if ((len=pThis->_user_programs.size()) && !_tcsnicmp(entry_path, pThis->_user_programs, len)) + menu_path = String(entry_path)+len; -#ifndef __WINE__ //TODO - _tcslwr((LPTSTR)lwr_path.c_str()); - _tcslwr((LPTSTR)lwr_name.c_str()); - _tcslwr((LPTSTR)filter.c_str()); -#endif + // store info in cache + FPDEntry new_entry; - //if (_tcsstr(lwr_path, _T(".exe"))) //@@ filter on ".exe" suffix - //if (!_tcsstr(lwr_name, _T("uninstal")) && !_tcsstr(lwr_name, _T("deinstal"))) //@@ filter out deinstallation links - if (_tcsstr(lwr_path, filter) || _tcsstr(lwr_name, filter)) { - LV_ITEM item = {LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, INT_MAX}; + new_entry._shell_entry = shell_entry; + new_entry._menu_path = menu_path; + new_entry._path = path; - item.pszText = entry->_display_name; + if (shell_entry->_hIcon != (HICON)-1) + new_entry._idxIcon = ImageList_AddIcon(pThis->_himl, shell_entry->_hIcon); + else + new_entry._idxIcon = pThis->_idxNoIcon; - if (entry->_hIcon != (HICON)-1) - item.iImage = ImageList_AddIcon(pThis->_himl, entry->_hIcon); - else - item.iImage = pThis->_idxNoIcon; + pThis->_cache.push_front(new_entry); + FPDEntry& cache_entry = pThis->_cache.front(); - item.lParam = 0; //@@ + Lock lock(pThis->_thread._crit_sect); - //TODO: store info in ShellPathWithFolder + // resolve deadlocks while executing Thread::Stop() + if (!pThis->_thread.is_alive()) + return; - Lock lock(pThis->_thread._crit_sect); - - // resolve deadlocks while executing Thread::Stop() - if (!pThis->_thread.is_alive()) - return; - - item.iItem = ListView_InsertItem(pThis->_list_ctrl, &item); - - item.mask = LVIF_TEXT; - item.iSubItem = 1; - item.pszText = path; - - if (!pThis->_thread.is_alive()) - return; - - ListView_SetItem(pThis->_list_ctrl, &item); - } + pThis->add_entry(cache_entry); } } } - - pShellLink->Release(); } -LRESULT FindProgramTopicDlg::WndProc(UINT message, WPARAM wparam, LPARAM lparam) +void FindProgramDlg::add_entry(const FPDEntry& cache_entry) +{ + String lwr_path = cache_entry._path; + String lwr_name = cache_entry._shell_entry->_display_name; + +#ifndef __WINE__ //TODO + _tcslwr((LPTSTR)lwr_path.c_str()); + _tcslwr((LPTSTR)lwr_name.c_str()); +#endif + + if (_lwr_filter.empty()) + if (_tcsstr(lwr_name, _T("uninstal")) || _tcsstr(lwr_name, _T("deinstal"))) // filter out deinstallation links + return; + + if (!_tcsstr(lwr_path, _lwr_filter) && !_tcsstr(lwr_name, _lwr_filter)) + return; + + LV_ITEM item = {LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, INT_MAX}; + + item.pszText = cache_entry._shell_entry->_display_name; + item.iImage = cache_entry._idxIcon; + item.lParam = (LPARAM) &cache_entry; + + item.iItem = ListView_InsertItem(_list_ctrl, &item); + + item.mask = LVIF_TEXT; + item.iSubItem = 1; + item.pszText = (LPTSTR)(LPCTSTR)cache_entry._path; + ListView_SetItem(_list_ctrl, &item); + + item.iSubItem = 2; + item.pszText = (LPTSTR)(LPCTSTR)cache_entry._menu_path; + ListView_SetItem(_list_ctrl, &item); +} + +LRESULT FindProgramDlg::WndProc(UINT message, WPARAM wparam, LPARAM lparam) { switch(message) { default: @@ -211,12 +266,12 @@ LRESULT FindProgramTopicDlg::WndProc(UINT message, WPARAM wparam, LPARAM lparam) return FALSE; } -int FindProgramTopicDlg::Command(int id, int code) +int FindProgramDlg::Command(int id, int code) { if (code == BN_CLICKED) switch(id) { case ID_REFRESH: - Refresh(); + Refresh(true); break; default: @@ -231,14 +286,13 @@ int FindProgramTopicDlg::Command(int id, int code) return TRUE; } -int FindProgramTopicDlg::Notify(int id, NMHDR* pnmh) +int FindProgramDlg::Notify(int id, NMHDR* pnmh) { switch(pnmh->code) { - case LVN_GETDISPINFO: { + case LVN_GETDISPINFO: {/* LV_DISPINFO* pDispInfo = (LV_DISPINFO*) pnmh; if (pnmh->hwndFrom == _list_ctrl) { -/* if (pDispInfo->item.mask & LVIF_IMAGE) { int icon; HRESULT hr = pShellLink->GetIconLocation(path, MAX_PATH-1, &icon); @@ -250,9 +304,18 @@ int FindProgramTopicDlg::Notify(int id, NMHDR* pnmh) return 1; } -*/ + }*/} + break; + + case NM_DBLCLK: { + LPNMLISTVIEW pnmv = (LPNMLISTVIEW) pnmh; + LPARAM lparam = ListView_GetItemData(pnmh->hwndFrom, pnmv->iItem); + + if (lparam) { + FPDEntry& cache_entry = *(FPDEntry*)lparam; + cache_entry._shell_entry->launch_entry(_hwnd); } - break;} + break;} } return 0; diff --git a/reactos/subsys/system/explorer/dialogs/searchprogram.h b/reactos/subsys/system/explorer/dialogs/searchprogram.h index f049e5b7376..b1ca21673a8 100644 --- a/reactos/subsys/system/explorer/dialogs/searchprogram.h +++ b/reactos/subsys/system/explorer/dialogs/searchprogram.h @@ -27,61 +27,79 @@ // Martin Fuchs, 02.10.2003 // - -struct ShellPathWithFolder -{ - ShellPathWithFolder(const ShellFolder& folder, const ShellPath& path) - : _folder(folder), _path(path) {} - - ShellFolder _folder; - ShellPath _path; -}; +#include -typedef void (*COLLECT_CALLBACK)(ShellFolder& folder, const ShellEntry* entry, void* param); +typedef void (*COLLECT_CALLBACK)(ShellFolder& folder, ShellEntry* shell_entry, void* param); +typedef stack ShellDirectoryStack; struct CollectProgramsThread : public Thread { CollectProgramsThread(COLLECT_CALLBACK callback, HWND hwnd, void* para) - : _callback(callback), + : _cache_valid(false), + _callback(callback), _hwnd(hwnd), _para(para) { } - int Run(); + ~CollectProgramsThread() + { + free_dirs(); + } + + int Run(); + void free_dirs(); + + bool _cache_valid; protected: COLLECT_CALLBACK _callback; HWND _hwnd; void* _para; + ShellDirectoryStack _dirs; - void CollectProgramsThread::collect_programs(const ShellPath& path); + void collect_programs(const ShellPath& path); }; -struct FindProgramTopicDlg : public ResizeController +struct FPDEntry +{ + ShellEntry* _shell_entry; + int _idxIcon; + String _menu_path; + String _path; +}; + +typedef list FPDCache; + + +struct FindProgramDlg : public ResizeController { typedef ResizeController super; - FindProgramTopicDlg(HWND hwnd); - ~FindProgramTopicDlg(); + FindProgramDlg(HWND hwnd); + ~FindProgramDlg(); protected: CommonControlInit _usingCmnCtrl; HWND _list_ctrl; HACCEL _haccel; HIMAGELIST _himl; - int _idxNoIcon; // Ersatzicon für Links ohne Symbole - String _filter; + int _idxNoIcon; // replacement icon + String _lwr_filter; CollectProgramsThread _thread; + FPDCache _cache; + + String _common_programs, _user_programs; virtual LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam); - virtual int Command(int id, int code); + virtual int Command(int id, int code); virtual int Notify(int id, NMHDR* pnmh); - void Refresh(); + void Refresh(bool delete_cache=false); + void add_entry(const FPDEntry& cache_entry); - static void collect_programs_callback(ShellFolder& folder, const ShellEntry* entry, void* param); + static void collect_programs_callback(ShellFolder& folder, ShellEntry* entry, void* param); }; diff --git a/reactos/subsys/system/explorer/explorer_intres.h b/reactos/subsys/system/explorer/explorer_intres.h index 629234b165a..16c244f4507 100644 --- a/reactos/subsys/system/explorer/explorer_intres.h +++ b/reactos/subsys/system/explorer/explorer_intres.h @@ -26,6 +26,7 @@ #define IDS_PRINTERS 22 #define IDS_BROWSE 23 #define IDS_SEARCH_PRG 24 +#define IDS_ALL_USERS 25 #define IDI_REACTOS 100 #define IDI_EXPLORER 101 #define IDI_STARTMENU 102 @@ -77,6 +78,7 @@ #define ID_FILE_EXIT 0xE141 #define ID_HELP_USING 0xE144 #define ID_HELP 0xE146 +#define IDC_STATIC -1 // Next default values for new objects // diff --git a/reactos/subsys/system/explorer/explorer_intres.rc b/reactos/subsys/system/explorer/explorer_intres.rc index 82aa1cf556e..eae407b40b3 100644 --- a/reactos/subsys/system/explorer/explorer_intres.rc +++ b/reactos/subsys/system/explorer/explorer_intres.rc @@ -112,6 +112,7 @@ BEGIN IDS_PRINTERS "Printers" IDS_BROWSE "Browse Files..." IDS_SEARCH_PRG "Search Programm..." + IDS_ALL_USERS "All Users\\" END #endif // Romanian resources @@ -381,6 +382,7 @@ BEGIN IDS_PRINTERS "Drucker" IDS_BROWSE "Dateien..." IDS_SEARCH_PRG "Suche Programm..." + IDS_ALL_USERS "Alle Benutzer\\" END #endif // German (Germany) resources @@ -565,11 +567,13 @@ STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME EXSTYLE WS_EX_APPWINDOW CAPTION "Search Program in Startmenu" -FONT 8, "MS Sans Serif", 0, 0, 0x1 +FONT 8, "MS Sans Serif" BEGIN - EDITTEXT IDC_TOPIC,7,7,130,14,ES_AUTOHSCROLL + LTEXT "Filter:",IDC_STATIC,7,9,18,8 + EDITTEXT IDC_TOPIC,34,7,103,14,ES_AUTOHSCROLL CONTROL "List1",IDC_MAILS_FOUND,"SysListView32",LVS_REPORT | - LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,25,130,33 + LVS_SHOWSELALWAYS | LVS_SORTASCENDING | WS_BORDER | + WS_TABSTOP,7,25,130,33 END @@ -627,6 +631,7 @@ BEGIN IDS_PRINTERS "Printers" IDS_BROWSE "Browse Files..." IDS_SEARCH_PRG "Search Programm..." + IDS_ALL_USERS "All Users\\" END #endif // English (U.S.) resources diff --git a/reactos/subsys/system/explorer/taskbar/startmenu.cpp b/reactos/subsys/system/explorer/taskbar/startmenu.cpp index f93452c23df..143f2d6be55 100644 --- a/reactos/subsys/system/explorer/taskbar/startmenu.cpp +++ b/reactos/subsys/system/explorer/taskbar/startmenu.cpp @@ -788,7 +788,7 @@ int StartMenuRoot::Command(int id, int code) case IDC_SEARCH_PROGRAM: CloseStartMenu(id); - Dialog::DoModal(IDD_SEARCH_PROGRAM, WINDOW_CREATOR(FindProgramTopicDlg)); + Dialog::DoModal(IDD_SEARCH_PROGRAM, WINDOW_CREATOR(FindProgramDlg)); break; case IDC_EXPLORE: diff --git a/reactos/subsys/system/explorer/utility/shellclasses.cpp b/reactos/subsys/system/explorer/utility/shellclasses.cpp index 44715793c81..128882f39b9 100644 --- a/reactos/subsys/system/explorer/utility/shellclasses.cpp +++ b/reactos/subsys/system/explorer/utility/shellclasses.cpp @@ -162,7 +162,7 @@ ShellFolder::ShellFolder() } ShellFolder::ShellFolder(IShellFolder* p) - : IShellFolderPtr(p) + : super(p) { p->AddRef(); } @@ -220,7 +220,7 @@ ShellFolder::ShellFolder() } ShellFolder::ShellFolder(IShellFolder* p) - : SIfacePtr(p) + : super(p) { _p->AddRef(); } diff --git a/reactos/subsys/system/explorer/utility/shellclasses.h b/reactos/subsys/system/explorer/utility/shellclasses.h index eb1695a888b..b7be6fb3760 100644 --- a/reactos/subsys/system/explorer/utility/shellclasses.h +++ b/reactos/subsys/system/explorer/utility/shellclasses.h @@ -392,6 +392,25 @@ struct ShellFolder : public IShellFolderPtr // IShellFolderPtr uses intrinsic ex bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty() }; +#ifdef UNICODE +#define IShellLinkPtr IShellLinkWPtr +#else +#define IShellLinkPtr IShellLinkAPtr +#endif + +struct ShellLinkPtr : public IShellLinkPtr +{ + typedef IShellLinkPtr super; + + ShellLinkPtr(IShellLink* p) + : super(p) + { + p->AddRef(); + } + + bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty() +}; + #else // _com_ptr not available -> use SIfacePtr struct ShellFolder : public SIfacePtr @@ -407,6 +426,18 @@ struct ShellFolder : public SIfacePtr String get_name(LPCITEMIDLIST pidl, SHGDNF flags=SHGDN_NORMAL) const; }; +struct ShellLinkPtr : public SIfacePtr +{ + typedef SIfacePtr super; + + ShellLinkPtr(IShellLink* p) + : super(p) + { + _p->AddRef(); + } + +}; + #endif diff --git a/reactos/subsys/system/explorer/utility/utility.cpp b/reactos/subsys/system/explorer/utility/utility.cpp index cdfa761039a..a568ed1d0a7 100644 --- a/reactos/subsys/system/explorer/utility/utility.cpp +++ b/reactos/subsys/system/explorer/utility/utility.cpp @@ -44,6 +44,55 @@ DWORD WINAPI Thread::ThreadProc(void* para) } +void CenterWindow(HWND hwnd) +{ + RECT rt, prt; + GetWindowRect(hwnd, &rt); + + DWORD style; + HWND owner = 0; + + for(HWND wh=hwnd; (wh=GetWindow(wh,GW_OWNER))!=0; ) + if (((style=GetWindowStyle(wh))&WS_VISIBLE) && !(style&WS_MINIMIZE)) + {owner=wh; break;} + + if (owner) + GetWindowRect(owner, &prt); + else + SystemParametersInfo(SPI_GETWORKAREA, 0, &prt, 0); //@@ GetDesktopWindow() wäre auch hilfreich. + + SetWindowPos(hwnd, 0, (prt.left+prt.right+rt.left-rt.right)/2, + (prt.top+prt.bottom+rt.top-rt.bottom)/2, 0,0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER); + + MoveVisible(hwnd); +} + +void MoveVisible(HWND hwnd) +{ + RECT rc; + GetWindowRect(hwnd, &rc); + int left=rc.left, top=rc.top; + + int xmax = GetSystemMetrics(SM_CXSCREEN); + int ymax = GetSystemMetrics(SM_CYSCREEN); + + if (rc.left < 0) + rc.left = 0; + else if (rc.right > xmax) + if ((rc.left-=rc.right-xmax) < 0) + rc.left = 0; + + if (rc.top < 0) + rc.top = 0; + else if (rc.bottom > ymax) + if ((rc.top-=rc.bottom-ymax) < 0) + rc.top = 0; + + if (rc.left!=left || rc.top!=top) + SetWindowPos(hwnd, 0, rc.left,rc.top, 0,0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE); +} + + void display_error(HWND hwnd, DWORD error) { PTSTR msg; diff --git a/reactos/subsys/system/explorer/utility/utility.h b/reactos/subsys/system/explorer/utility/utility.h index c1438651104..be22968daa1 100644 --- a/reactos/subsys/system/explorer/utility/utility.h +++ b/reactos/subsys/system/explorer/utility/utility.h @@ -449,9 +449,12 @@ struct String String() {} String(LPCTSTR s) : super(s) {} + String(const super& other) : super(other) {} String(const String& other) : super(other) {} String& operator=(LPCTSTR s) {assign(s); return *this;} + String& operator=(const super& s) {assign(s); return *this;} + operator LPCTSTR() const {return c_str();} }; @@ -551,7 +554,14 @@ extern void _splitpath(const CHAR* path, CHAR* drv, CHAR* dir, CHAR* name, CHAR* #define Window_SetIcon(hwnd, type, hicon) (HICON)SendMessage(hwnd, WM_SETICON, type, (LPARAM)(hicon)) - // display + + // center window in respect to its parent window +extern void CenterWindow(HWND hwnd); + + // move window into visibility +extern void MoveVisible(HWND hwnd); + + // display error message extern void display_error(HWND hwnd, DWORD error); // convert time_t to WIN32 FILETIME diff --git a/reactos/subsys/system/explorer/utility/window.h b/reactos/subsys/system/explorer/utility/window.h index 462d40a0049..89d82a3ac54 100644 --- a/reactos/subsys/system/explorer/utility/window.h +++ b/reactos/subsys/system/explorer/utility/window.h @@ -627,3 +627,17 @@ struct ToolTip : public WindowHandle SendMessage(_hwnd, TTM_ADDTOOL, 0, (LPARAM)&ti); } }; + + +inline int ListView_GetItemData(HWND list_ctrl, int idx) +{ + LV_ITEM item; + + item.mask = LVIF_PARAM; + item.iItem = idx; + + if (!ListView_GetItem(list_ctrl, &item)) + return 0; + + return item.lParam; +}