[SHELLFIND] Use DeferWindowPos for resizing child windows
[reactos.git] / dll / win32 / browseui / shellfind / CSearchBar.cpp
index 7efcd2b..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 <commoncontrols.h>
+#include <../browseui.h>
+#include <shellapi.h>
+#include <exdispid.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
 
@@ -29,8 +22,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
 
 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)
@@ -106,7 +99,6 @@ 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);
     bHandled = FALSE;
     return TRUE;
@@ -161,6 +153,15 @@ HRESULT CSearchBar::GetSearchResultsFolder(IShellBrowser **ppShellBrowser, HWND
 
 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))
@@ -169,6 +170,7 @@ LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndC
     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));
@@ -177,7 +179,7 @@ LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndC
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
-        LPITEMIDLIST findFolderPidl;
+        CComHeapPtr<ITEMIDLIST> findFolderPidl;
         hr = SHParseDisplayName(szShellGuid, NULL, &findFolderPidl, 0, NULL);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
@@ -185,27 +187,88 @@ LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndC
         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;
     }
 
-    GetSearchResultsFolder(&pShellBrowser, &hwnd, NULL);
-    if (hwnd)
-        // TODO: Use message ID in header file
-        ::PostMessageW(hwnd, WM_USER + 1, 0, (LPARAM) StrDupW(L"Starting search..."));
+    ::PostMessageW(hwnd, WM_SEARCH_START, 0, (LPARAM) pSearchStart.Detach());
 
-    return S_OK;
+    SetSearchInProgress(TRUE);
+
+    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)
     {
-        LPCWSTR path = L"C:\\readme.txt";
-        // TODO: Use message ID in header file
-        ::PostMessageW(hwnd, WM_USER, 0, (LPARAM) StrDupW(path));
+        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;
 }
 
@@ -296,15 +359,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)
@@ -346,9 +400,8 @@ HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
     }
     else
     {
-        CWindowImpl::Create(parentWnd);
+        CDialogImpl::Create(parentWnd);
 
-        InitializeSearchBar();
     }
     return S_OK;
 }
@@ -403,12 +456,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);
@@ -423,7 +479,7 @@ HRESULT STDMETHODCALLTYPE CSearchBar::GetClassID(CLSID *pClassID)
 {
     if (!pClassID)
         return E_POINTER;
-    memcpy(pClassID, &CLSID_FileSearchBand, sizeof(CLSID));
+    *pClassID = CLSID_FileSearchBand;
     return S_OK;
 }
 
@@ -523,8 +579,21 @@ 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 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;
 }