[SHELLFIND] Use DeferWindowPos for resizing child windows
[reactos.git] / dll / win32 / browseui / shellfind / CSearchBar.cpp
index f2329b6..13f8690 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 "CSearchBar.h"
 #include <psdk/wingdi.h>
+#include <commoncontrols.h>
+#include <../browseui.h>
+#include <shellapi.h>
+#include <exdispid.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
 
 
 WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
 
@@ -29,8 +22,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
 
 CSearchBar::CSearchBar() :
     pSite(NULL),
 
 CSearchBar::CSearchBar() :
     pSite(NULL),
-    fVisible(FALSE),
-    bFocused(FALSE)
+    fVisible(FALSE)
 {
 }
 
 {
 }
 
@@ -38,41 +30,42 @@ 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"A &word or phrase in the file:",
-        WS_CHILD | WS_VISIBLE,
-        10, 50, 500, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-    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"&Look in:",
-        WS_CHILD | WS_VISIBLE,
-        10, 100, 500, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-    CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
-        WS_BORDER | WS_CHILD | WS_VISIBLE,
-        10, 120, 100, 20,
-        m_hWnd, NULL,
-        _AtlBaseModule.GetModuleInstance(), NULL);
-
-    CreateWindowExW(0, WC_BUTTON, L"Sea&rch",
-        WS_BORDER | WS_CHILD | WS_VISIBLE,
-        10, 150, 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);
+    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));
+
+    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;
+
+    CComPtr<IShellService> pShellService;
+    hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &pShellService));
+    if (FAILED_UNEXPECTEDLY(hResult))
+        return hResult;
+    hResult = fAddressEditBox->Init(hCombobox, fEditControl, 0, pSite);
+    if (FAILED_UNEXPECTEDLY(hResult))
+        return hResult;
+
+    CComPtr<IDispatch> pDispatch;
+    hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch));
+    if (FAILED_UNEXPECTEDLY(hResult))
+        return hResult;
+    DISPPARAMS params = {0};
+    hResult = pDispatch->Invoke(DISPID_NAVIGATECOMPLETE2, GUID_NULL, 0, DISPATCH_METHOD, &params, NULL, NULL, NULL);
+
+    hResult = pShellService->SetOwner(NULL);
+    if (FAILED_UNEXPECTEDLY(hResult))
+        return hResult;
+
+    return 0;
 }
 
 HRESULT CSearchBar::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
 }
 
 HRESULT CSearchBar::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
@@ -106,32 +99,177 @@ HRESULT CSearchBar::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
 // *** ATL event handlers ***
 LRESULT CSearchBar::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
 {
 // *** ATL event handlers ***
 LRESULT CSearchBar::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
 {
-    bFocused = TRUE;
     IUnknown_OnFocusChangeIS(pSite, reinterpret_cast<IUnknown*>(this), TRUE);
     bHandled = FALSE;
     return TRUE;
 }
 
     IUnknown_OnFocusChangeIS(pSite, reinterpret_cast<IUnknown*>(this), TRUE);
     bHandled = FALSE;
     return TRUE;
 }
 
-LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
+HRESULT CSearchBar::GetSearchResultsFolder(IShellBrowser **ppShellBrowser, HWND *pHwnd, IShellFolder **ppShellFolder)
 {
 {
+    HRESULT hr;
     CComPtr<IShellBrowser> pShellBrowser;
     CComPtr<IShellBrowser> pShellBrowser;
-    HRESULT hr = IUnknown_QueryService(pSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pShellBrowser));
-    if (FAILED_UNEXPECTEDLY(hr))
+    if (!ppShellBrowser)
+        ppShellBrowser = &pShellBrowser;
+    if (!*ppShellBrowser)
+    {
+        hr = IUnknown_QueryService(m_pSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, ppShellBrowser));
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+    }
+
+    CComPtr<IShellView> pShellView;
+    hr = (*ppShellBrowser)->QueryActiveShellView(&pShellView);
+    if (FAILED(hr) || !pShellView)
         return hr;
 
         return hr;
 
-    WCHAR szShellGuid[MAX_PATH];
-    const WCHAR shellGuidPrefix[] = L"shell:::";
-    memcpy(szShellGuid, shellGuidPrefix, sizeof(shellGuidPrefix));
-    hr = StringFromGUID2(CLSID_FindFolder, szShellGuid + _countof(shellGuidPrefix) - 1, _countof(szShellGuid) - _countof(shellGuidPrefix));
-    if (FAILED_UNEXPECTEDLY(hr))
+    CComPtr<IFolderView> pFolderView;
+    hr = pShellView->QueryInterface(IID_PPV_ARG(IFolderView, &pFolderView));
+    if (FAILED(hr) || !pFolderView)
+        return hr;
+
+    CComPtr<IShellFolder> pShellFolder;
+    if (!ppShellFolder)
+        ppShellFolder = &pShellFolder;
+    hr = pFolderView->GetFolder(IID_PPV_ARG(IShellFolder, ppShellFolder));
+    if (FAILED(hr) || !pShellFolder)
         return hr;
 
         return hr;
 
-    LPITEMIDLIST findFolderPidl;
-    hr = SHParseDisplayName(szShellGuid, NULL, &findFolderPidl, 0, NULL);
+    CLSID clsid;
+    hr = IUnknown_GetClassID(*ppShellFolder, &clsid);
+    if (FAILED(hr))
+        return hr;
+    if (clsid != CLSID_FindFolder)
+        return E_FAIL;
+
+    if (pHwnd)
+    {
+        hr = pShellView->GetWindow(pHwnd);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+    }
+
+    return S_OK;
+}
+
+LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
+{
+    CComHeapPtr<SearchStart> pSearchStart((SearchStart *)SHAlloc(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));
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
-    return pShellBrowser->BrowseObject(findFolderPidl, 0);
+    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));
+        hr = StringFromGUID2(CLSID_FindFolder, szShellGuid + _countof(shellGuidPrefix) - 1,
+                             _countof(szShellGuid) - _countof(shellGuidPrefix));
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        CComHeapPtr<ITEMIDLIST> findFolderPidl;
+        hr = SHParseDisplayName(szShellGuid, NULL, &findFolderPidl, 0, NULL);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        hr = pShellBrowser->BrowseObject(findFolderPidl, 0);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        CComPtr<IShellFolder> pShellFolder;
+        hr = GetSearchResultsFolder(*pShellBrowser, &hwnd, &pShellFolder);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        // Subscribe to search events
+        DWORD fAdviseCookie;
+        hr = AtlAdvise(pShellFolder, static_cast<IDispatch *>(this), DIID_DSearchCommandEvents, &fAdviseCookie);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+    }
+
+    ::PostMessageW(hwnd, WM_SEARCH_START, 0, (LPARAM) pSearchStart.Detach());
+
+    SetSearchInProgress(TRUE);
+
+    return TRUE;
+}
+
+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, szPath))
+        {
+            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++)
+    {
+        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;
 }
 
 
 }
 
 
@@ -221,15 +359,6 @@ HRESULT STDMETHODCALLTYPE CSearchBar::GetBandInfo(DWORD dwBandID, DWORD dwViewMo
     return S_OK;
 }
 
     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)
 
 // *** IObjectWithSite methods ***
 HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
@@ -271,9 +400,8 @@ HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
     }
     else
     {
     }
     else
     {
-        CWindowImpl::Create(parentWnd);
+        CDialogImpl::Create(parentWnd);
 
 
-        InitializeSearchBar();
     }
     return S_OK;
 }
     }
     return S_OK;
 }
@@ -328,12 +456,15 @@ HRESULT STDMETHODCALLTYPE CSearchBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
 
 HRESULT STDMETHODCALLTYPE CSearchBar::HasFocusIO()
 {
 
 HRESULT STDMETHODCALLTYPE CSearchBar::HasFocusIO()
 {
-    return bFocused ? S_OK : S_FALSE;
+    return S_OK;
 }
 
 HRESULT STDMETHODCALLTYPE CSearchBar::TranslateAcceleratorIO(LPMSG lpMsg)
 {
 }
 
 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);
     {
         TranslateMessage(lpMsg);
         DispatchMessage(lpMsg);
@@ -348,7 +479,7 @@ HRESULT STDMETHODCALLTYPE CSearchBar::GetClassID(CLSID *pClassID)
 {
     if (!pClassID)
         return E_POINTER;
 {
     if (!pClassID)
         return E_POINTER;
-    memcpy(pClassID, &CLSID_FileSearchBand, sizeof(CLSID));
+    *pClassID = CLSID_FileSearchBand;
     return S_OK;
 }
 
     return S_OK;
 }
 
@@ -448,8 +579,21 @@ HRESULT STDMETHODCALLTYPE CSearchBar::GetIDsOfNames(REFIID riid, LPOLESTR *rgszN
     return E_NOTIMPL;
 }
 
     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 STDMETHODCALLTYPE CSearchBar::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
 {
 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);
+    if (dispIdMember == DISPID_SEARCHCOMPLETE || dispIdMember == DISPID_SEARCHABORT)
+    {
+        SetSearchInProgress(FALSE);
+        return S_OK;
+    }
     return E_INVALIDARG;
 }
     return E_INVALIDARG;
 }