[SHELLFIND] Remove redundant check
[reactos.git] / dll / win32 / browseui / shellfind / CSearchBar.cpp
index d09c478..bcb7016 100644 (file)
@@ -1,23 +1,16 @@
 /*
- * ReactOS Explorer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * PROJECT:     ReactOS Search Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Search UI
+ * COPYRIGHT:   Copyright 2019 Brock Mammen
  */
 
 #include "CSearchBar.h"
 #include <psdk/wingdi.h>
+#include <commoncontrols.h>
+#include <../browseui.h>
+#include <shellapi.h>
+#include <exdispid.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
 
@@ -28,9 +21,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
 #endif
 
 CSearchBar::CSearchBar() :
-    pSite(NULL),
-    fVisible(FALSE),
-    bFocused(FALSE)
+    m_pSite(NULL),
+    m_bVisible(FALSE)
 {
 }
 
@@ -38,53 +30,38 @@ CSearchBar::~CSearchBar()
 {
 }
 
-void CSearchBar::InitializeSearchBar()
-{
-    CreateWindowExW(0, WC_STATIC, L"Search by any or all of the criteria below.",
-        WS_CHILD | WS_VISIBLE,
-        10, 10, 200, 40,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-
-    CreateWindowExW(0, WC_STATIC, L"All or part &of the file name:",
-        WS_CHILD | WS_VISIBLE,
-        10, 50, 500, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-    m_fileName = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
-        WS_BORDER | WS_CHILD | WS_VISIBLE,
-        10, 70, 100, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-
-    CreateWindowExW(0, WC_STATIC, L"A &word or phrase in the file:",
-        WS_CHILD | WS_VISIBLE,
-        10, 100, 500, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-    m_query = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
-        WS_BORDER | WS_CHILD | WS_VISIBLE,
-        10, 120, 100, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-    Edit_LimitText(m_query, MAX_PATH);
-
-    CreateWindowExW(0, WC_STATIC, L"&Look in:",
-        WS_CHILD | WS_VISIBLE,
-        10, 150, 500, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-    m_path = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
-        WS_BORDER | WS_CHILD | WS_VISIBLE,
-        10, 180, 100, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-
-    CreateWindowExW(0, WC_BUTTON, L"Sea&rch",
-        WS_BORDER | WS_CHILD | WS_VISIBLE,
-        10, 210, 100, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
+LRESULT CSearchBar::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+    SetSearchInProgress(FALSE);
+
+    HWND hCombobox = GetDlgItem(IDC_SEARCH_COMBOBOX);
+    CComPtr<IImageList> pImageList;
+    HRESULT hResult = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &pImageList));
+    SendMessage(hCombobox, CBEM_SETIMAGELIST, 0, FAILED_UNEXPECTEDLY(hResult) ? 0 : reinterpret_cast<LPARAM>(pImageList.p));
+
+    SendMessage(hCombobox, CBEM_SETEXTENDEDSTYLE,
+        CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT, CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT);
+    HWND hEditControl = reinterpret_cast<HWND>(SendMessage(hCombobox, CBEM_GETEDITCONTROL, 0, 0));
+    hResult = CAddressEditBox_CreateInstance(IID_PPV_ARG(IAddressEditBox, &m_AddressEditBox));
+    if (FAILED_UNEXPECTEDLY(hResult))
+        return hResult;
+
+    hResult = m_AddressEditBox->Init(hCombobox, hEditControl, 0, m_pSite);
+    if (FAILED_UNEXPECTEDLY(hResult))
+        return hResult;
+
+    // Subscribe to navigation events
+    CComPtr<IShellBrowser> pShellBrowser;
+    hResult = IUnknown_QueryService(m_pSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pShellBrowser));
+    DWORD dwAdviseCookie;
+    if (SUCCEEDED(hResult))
+        AtlAdvise(pShellBrowser, static_cast<IDispatch *>(this), DIID_DWebBrowserEvents, &dwAdviseCookie);
+
+    // Invoke the navigate event in case a search results folder is already open
+    DISPPARAMS params = {0};
+    Invoke(DISPID_NAVIGATECOMPLETE2, GUID_NULL, 0, DISPATCH_METHOD, &params, NULL, NULL, NULL);
+
+    return 0;
 }
 
 HRESULT CSearchBar::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
@@ -94,7 +71,7 @@ HRESULT CSearchBar::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
     HWND                                browserWnd;
     HRESULT                             hr;
 
-    hr = IUnknown_QueryService(pSite, SID_SShellBrowser, IID_PPV_ARG(IOleWindow, &pBrowserOleWnd));
+    hr = IUnknown_QueryService(m_pSite, SID_SShellBrowser, IID_PPV_ARG(IOleWindow, &pBrowserOleWnd));
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
@@ -118,8 +95,7 @@ HRESULT CSearchBar::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
 // *** ATL event handlers ***
 LRESULT CSearchBar::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
 {
-    bFocused = TRUE;
-    IUnknown_OnFocusChangeIS(pSite, reinterpret_cast<IUnknown*>(this), TRUE);
+    IUnknown_OnFocusChangeIS(m_pSite, static_cast<IDeskBand *>(this), TRUE);
     bHandled = FALSE;
     return TRUE;
 }
@@ -173,14 +149,24 @@ HRESULT CSearchBar::GetSearchResultsFolder(IShellBrowser **ppShellBrowser, HWND
 
 LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
 {
+    CComHeapPtr<SearchStart> pSearchStart(static_cast<SearchStart *>(CoTaskMemAlloc(sizeof(SearchStart))));
+    GetDlgItemText(IDC_SEARCH_FILENAME, pSearchStart->szFileName, _countof(pSearchStart->szFileName));
+    GetDlgItemText(IDC_SEARCH_QUERY, pSearchStart->szQuery, _countof(pSearchStart->szQuery));
+    if (!GetAddressEditBoxPath(pSearchStart->szPath))
+    {
+        ShellMessageBoxW(_AtlBaseModule.GetResourceInstance(), m_hWnd, MAKEINTRESOURCEW(IDS_SEARCHINVALID), MAKEINTRESOURCEW(IDS_SEARCHLABEL), MB_OK | MB_ICONERROR, pSearchStart->szPath);
+        return TRUE;
+    }
+
     CComPtr<IShellBrowser> pShellBrowser;
-    HRESULT hr = IUnknown_QueryService(pSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pShellBrowser));
+    HRESULT hr = IUnknown_QueryService(m_pSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pShellBrowser));
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
     HWND hwnd;
     if (FAILED(GetSearchResultsFolder(&pShellBrowser, &hwnd, NULL)))
     {
+        // Open a new search results folder
         WCHAR szShellGuid[MAX_PATH];
         const WCHAR shellGuidPrefix[] = L"shell:::";
         memcpy(szShellGuid, shellGuidPrefix, sizeof(shellGuidPrefix));
@@ -197,26 +183,81 @@ LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndC
         hr = pShellBrowser->BrowseObject(findFolderPidl, 0);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
+
+        hr = GetSearchResultsFolder(&pShellBrowser, &hwnd, NULL);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
     }
 
-    hr = GetSearchResultsFolder(*pShellBrowser, &hwnd, NULL);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
+    ::PostMessageW(hwnd, WM_SEARCH_START, 0, (LPARAM) pSearchStart.Detach());
 
-    ::PostMessageW(hwnd, WM_SEARCH_START, 0, (LPARAM) StrDupW(L"Starting search..."));
+    SetSearchInProgress(TRUE);
 
-    return S_OK;
+    return TRUE;
 }
 
-LRESULT CSearchBar::OnClicked(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+LRESULT CSearchBar::OnStopButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
 {
     HWND hwnd;
     HRESULT hr = GetSearchResultsFolder(NULL, &hwnd, NULL);
     if (SUCCEEDED(hr))
+        ::PostMessageW(hwnd, WM_SEARCH_STOP, 0, 0);
+
+    return TRUE;
+}
+
+BOOL CSearchBar::GetAddressEditBoxPath(WCHAR (&szPath)[MAX_PATH])
+{
+    HWND hComboboxEx = GetDlgItem(IDC_SEARCH_COMBOBOX);
+    ::GetWindowTextW(hComboboxEx, szPath, _countof(szPath));
+    INT iSelectedIndex = SendMessageW(hComboboxEx, CB_GETCURSEL, 0, 0);
+    if (iSelectedIndex != CB_ERR)
+    {
+        WCHAR szItemText[MAX_PATH];
+        COMBOBOXEXITEMW item = {0};
+        item.mask = CBEIF_LPARAM | CBEIF_TEXT;
+        item.iItem = iSelectedIndex;
+        item.pszText = szItemText;
+        item.cchTextMax = _countof(szItemText);
+        SendMessageW(hComboboxEx, CBEM_GETITEMW, 0, (LPARAM)&item);
+
+        if (!wcscmp(szItemText, szPath) && SHGetPathFromIDListW((LPCITEMIDLIST)item.lParam, szItemText))
+        {
+            StringCbCopyW(szPath, MAX_PATH * sizeof(WCHAR), szItemText);
+            return TRUE;
+        }
+    }
+
+    DWORD dwAttributes = GetFileAttributesW(szPath);
+    return dwAttributes != INVALID_FILE_ATTRIBUTES
+        && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY);
+}
+
+LRESULT CSearchBar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+    INT iWidth = LOWORD(lParam);
+    INT iPadding = 10;
+
+    ((CWindow)GetDlgItem(IDC_SEARCH_LABEL)).SetWindowPos(NULL, 0, 0, iWidth - iPadding, 40, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
+
+    int inputs[] = { IDC_SEARCH_FILENAME, IDC_SEARCH_QUERY, IDC_SEARCH_COMBOBOX, IDC_SEARCH_BUTTON, IDC_SEARCH_STOP_BUTTON, IDC_PROGRESS_BAR };
+    HDWP hdwp = BeginDeferWindowPos(_countof(inputs));
+    for (SIZE_T i = 0; i < _countof(inputs); i++)
     {
-        LPCWSTR path = L"C:\\readme.txt";
-        ::PostMessageW(hwnd, WM_SEARCH_ADD_RESULT, 0, (LPARAM) StrDupW(path));
+        CWindow wnd = (CWindow) GetDlgItem(inputs[i]);
+        RECT rect;
+        wnd.GetWindowRect(&rect);
+        POINT pt = { rect.left, rect.top };
+        ScreenToClient(&pt);
+        hdwp = wnd.DeferWindowPos(hdwp,
+                                  HWND_TOP,
+                                  iPadding,
+                                  pt.y,
+                                  iWidth - iPadding * 2,
+                                  rect.bottom - rect.top,
+                                  SWP_NOZORDER | SWP_NOACTIVATE);
     }
+    EndDeferWindowPos(hdwp);
 
     return 0;
 }
@@ -254,7 +295,7 @@ HRESULT STDMETHODCALLTYPE CSearchBar::ResizeBorderDW(const RECT *prcBorder, IUnk
 
 HRESULT STDMETHODCALLTYPE CSearchBar::ShowDW(BOOL fShow)
 {
-    fVisible = fShow;
+    m_bVisible = fShow;
     ShowWindow(fShow);
     return S_OK;
 }
@@ -308,15 +349,6 @@ HRESULT STDMETHODCALLTYPE CSearchBar::GetBandInfo(DWORD dwBandID, DWORD dwViewMo
     return S_OK;
 }
 
-LRESULT CALLBACK MyWindowProc(
-    _In_ HWND   hwnd,
-    _In_ UINT   uMsg,
-    _In_ WPARAM wParam,
-    _In_ LPARAM lParam
-)
-{
-    return 0;
-}
 
 // *** IObjectWithSite methods ***
 HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
@@ -324,7 +356,7 @@ HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
     HRESULT hr;
     HWND parentWnd;
 
-    if (pUnkSite == pSite)
+    if (pUnkSite == m_pSite)
         return S_OK;
 
     TRACE("SetSite called \n");
@@ -332,15 +364,8 @@ HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
     {
         DestroyWindow();
         m_hWnd = NULL;
-    }
-
-    if (pUnkSite != pSite)
-    {
-        pSite = NULL;
-    }
-
-    if(!pUnkSite)
         return S_OK;
+    }
 
     hr = IUnknown_GetWindow(pUnkSite, &parentWnd);
     if (!SUCCEEDED(hr))
@@ -349,7 +374,7 @@ HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
         return E_INVALIDARG;
     }
 
-    pSite = pUnkSite;
+    m_pSite = pUnkSite;
 
     if (m_hWnd)
     {
@@ -358,9 +383,8 @@ HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
     }
     else
     {
-        CWindowImpl::Create(parentWnd);
+        CDialogImpl::Create(parentWnd);
 
-        InitializeSearchBar();
     }
     return S_OK;
 }
@@ -369,7 +393,7 @@ HRESULT STDMETHODCALLTYPE CSearchBar::GetSite(REFIID riid, void **ppvSite)
 {
     if (!ppvSite)
         return E_POINTER;
-    *ppvSite = pSite;
+    *ppvSite = m_pSite;
     return S_OK;
 }
 
@@ -392,7 +416,7 @@ HRESULT STDMETHODCALLTYPE CSearchBar::Exec(const GUID *pguidCmdGroup, DWORD nCmd
 HRESULT STDMETHODCALLTYPE CSearchBar::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
 {
     /* FIXME: we probably want to handle more services here */
-    return IUnknown_QueryService(pSite, SID_SShellBrowser, riid, ppvObject);
+    return IUnknown_QueryService(m_pSite, SID_SShellBrowser, riid, ppvObject);
 }
 
 
@@ -415,12 +439,15 @@ HRESULT STDMETHODCALLTYPE CSearchBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
 
 HRESULT STDMETHODCALLTYPE CSearchBar::HasFocusIO()
 {
-    return bFocused ? S_OK : S_FALSE;
+    return S_OK;
 }
 
 HRESULT STDMETHODCALLTYPE CSearchBar::TranslateAcceleratorIO(LPMSG lpMsg)
 {
-    if (lpMsg->hwnd == m_hWnd)
+    if (IsDialogMessage(lpMsg))
+        return S_OK;
+
+    if ((lpMsg->hwnd == m_hWnd || IsChild(lpMsg->hwnd)))
     {
         TranslateMessage(lpMsg);
         DispatchMessage(lpMsg);
@@ -435,7 +462,7 @@ HRESULT STDMETHODCALLTYPE CSearchBar::GetClassID(CLSID *pClassID)
 {
     if (!pClassID)
         return E_POINTER;
-    memcpy(pClassID, &CLSID_FileSearchBand, sizeof(CLSID));
+    *pClassID = CLSID_FileSearchBand;
     return S_OK;
 }
 
@@ -535,8 +562,84 @@ HRESULT STDMETHODCALLTYPE CSearchBar::GetIDsOfNames(REFIID riid, LPOLESTR *rgszN
     return E_NOTIMPL;
 }
 
+void CSearchBar::SetSearchInProgress(BOOL bInProgress)
+{
+    ::ShowWindow(GetDlgItem(IDC_SEARCH_BUTTON), bInProgress ? SW_HIDE : SW_SHOW);
+    ::ShowWindow(GetDlgItem(IDC_SEARCH_STOP_BUTTON), bInProgress ? SW_SHOW : SW_HIDE);
+    HWND hProgressBar = GetDlgItem(IDC_PROGRESS_BAR);
+    ::ShowWindow(hProgressBar, bInProgress ? SW_SHOW : SW_HIDE);
+    ::PostMessage(hProgressBar, PBM_SETMARQUEE, bInProgress, 0);
+}
+
+HRESULT CSearchBar::TrySubscribeToSearchEvents()
+{
+    CComPtr<IShellFolder> pShellFolder;
+    HRESULT hr = GetSearchResultsFolder(NULL, NULL, &pShellFolder);
+    if (FAILED(hr))
+        return hr;
+
+    DWORD fAdviseCookie;
+    hr = AtlAdvise(pShellFolder, static_cast<IDispatch *>(this), DIID_DSearchCommandEvents, &fAdviseCookie);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    return S_OK;
+}
+
 HRESULT STDMETHODCALLTYPE CSearchBar::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
 {
-    TRACE("Unknown dispid requested: %08x\n", dispIdMember);
-    return E_INVALIDARG;
+    switch (dispIdMember)
+    {
+    case DISPID_NAVIGATECOMPLETE2:
+    case DISPID_DOCUMENTCOMPLETE:
+    {
+        TrySubscribeToSearchEvents();
+
+        // Remove the search results folder from the address box
+        CComPtr<IDispatch> pDispatch;
+        HRESULT hResult = m_AddressEditBox->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch));
+        if (FAILED_UNEXPECTEDLY(hResult))
+            return hResult;
+        pDispatch->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+        CComPtr<IShellService> pShellService;
+        hResult = m_AddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &pShellService));
+        if (FAILED_UNEXPECTEDLY(hResult))
+            return hResult;
+        hResult = pShellService->SetOwner(NULL);
+        if (FAILED_UNEXPECTEDLY(hResult))
+            return hResult;
+        HWND hComboboxEx = GetDlgItem(IDC_SEARCH_COMBOBOX);
+        int index = SendMessageW(hComboboxEx, CB_GETCOUNT, 0, 0);
+        if (index <= 0)
+            return S_OK;
+        COMBOBOXEXITEMW item = {0};
+        item.mask = CBEIF_LPARAM;
+        item.iItem = index - 1;
+        SendMessageW(hComboboxEx, CBEM_GETITEMW, 0, (LPARAM)&item);
+        if (!item.lParam)
+            return S_OK;
+        CComPtr<IShellFolder> pDesktopFolder;
+        hResult = SHGetDesktopFolder(&pDesktopFolder);
+        if (FAILED_UNEXPECTEDLY(hResult))
+            return hResult;
+        CComPtr<IShellFolder> pShellFolder;
+        hResult = pDesktopFolder->BindToObject((LPCITEMIDLIST)item.lParam, NULL, IID_PPV_ARG(IShellFolder, &pShellFolder));
+        if (FAILED(hResult))
+            return S_OK;
+        CLSID clsid;
+        hResult = IUnknown_GetClassID(pShellFolder, &clsid);
+        if (SUCCEEDED(hResult) && clsid == CLSID_FindFolder)
+        {
+            SendMessageW(hComboboxEx, CBEM_DELETEITEM, item.iItem, 0);
+            SendMessageW(hComboboxEx, CB_SETCURSEL, 0, 0);
+        }
+        return S_OK;
+    }
+    case DISPID_SEARCHCOMPLETE:
+    case DISPID_SEARCHABORT:
+        SetSearchInProgress(FALSE);
+        return S_OK;
+    default:
+        return E_INVALIDARG;
+    }
 }