xref: /reactos/dll/win32/browseui/addressband.cpp (revision d5b576b2)
1 /*
2  * ReactOS Explorer
3  *
4  * Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 /*
22 Implements the navigation band of the cabinet window
23 */
24 
25 #include "precomp.h"
26 #include <commoncontrols.h>
27 #include <shlwapi_undoc.h>
28 #include <shellapi.h>
29 
30 /*
31 TODO:
32 ****Add tooltip notify handler
33   **Properly implement GetBandInfo
34     Implement Exec
35     Implement QueryService
36     Implement Load
37     Implement Save
38 */
39 
40 CAddressBand::CAddressBand()
41 {
42     fEditControl = NULL;
43     fGoButton = NULL;
44     fComboBox = NULL;
45     fGoButtonShown = false;
46 }
47 
48 CAddressBand::~CAddressBand()
49 {
50 }
51 
52 void CAddressBand::FocusChange(BOOL bFocus)
53 {
54 //    m_bFocus = bFocus;
55 
56     //Inform the input object site that the focus has changed.
57     if (fSite)
58     {
59 #if 0
60         fSite->OnFocusChangeIS((IDockingWindow *)this, bFocus);
61 #endif
62     }
63 }
64 
65 HRESULT STDMETHODCALLTYPE CAddressBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
66 {
67     if (pdbi->dwMask & DBIM_MINSIZE)
68     {
69         pdbi->ptMinSize.x = 100;
70         pdbi->ptMinSize.y = 22;
71     }
72     if (pdbi->dwMask & DBIM_MAXSIZE)
73     {
74         pdbi->ptMaxSize.x = 0;
75         pdbi->ptMaxSize.y = 0;
76     }
77     if (pdbi->dwMask & DBIM_INTEGRAL)
78     {
79         pdbi->ptIntegral.x = 0;
80         pdbi->ptIntegral.y = 0;
81     }
82     if (pdbi->dwMask & DBIM_ACTUAL)
83     {
84         pdbi->ptActual.x = 100;
85         pdbi->ptActual.y = 22;
86     }
87     if (pdbi->dwMask & DBIM_TITLE)
88     {
89         if (!LoadStringW(_AtlBaseModule.GetResourceInstance(), IDS_ADDRESSBANDLABEL, pdbi->wszTitle, _countof(pdbi->wszTitle)))
90             return HRESULT_FROM_WIN32(GetLastError());
91     }
92 
93     if (pdbi->dwMask & DBIM_MODEFLAGS)
94         pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
95     if (pdbi->dwMask & DBIM_BKCOLOR)
96         pdbi->crBkgnd = 0;
97     return S_OK;
98 }
99 
100 HRESULT STDMETHODCALLTYPE CAddressBand::SetSite(IUnknown *pUnkSite)
101 {
102     CComPtr<IShellService>                  shellService;
103     HWND                                    parentWindow;
104     HWND                                    combobox;
105     HRESULT                                 hResult;
106     IImageList                              *piml;
107 
108     if (pUnkSite == NULL)
109     {
110         fSite.Release();
111         return S_OK;
112     }
113 
114     fSite.Release();
115 
116     hResult = pUnkSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &fSite));
117     if (FAILED_UNEXPECTEDLY(hResult))
118         return hResult;
119 
120     // get window handle of parent
121     parentWindow = NULL;
122     hResult = IUnknown_GetWindow(fSite, &parentWindow);
123 
124     if (!::IsWindow(parentWindow))
125         return E_FAIL;
126 
127     // create combo box ex
128     combobox = CreateWindowEx(WS_EX_TOOLWINDOW, WC_COMBOBOXEXW, NULL, WS_CHILD | WS_VISIBLE |
129         WS_CLIPCHILDREN | WS_TABSTOP | CCS_NODIVIDER | CCS_NOMOVEY | CBS_OWNERDRAWFIXED,
130                     0, 0, 500, 250, parentWindow, (HMENU)IDM_TOOLBARS_ADDRESSBAR, _AtlBaseModule.GetModuleInstance(), 0);
131     if (combobox == NULL)
132         return E_FAIL;
133     SubclassWindow(combobox);
134 
135     HRESULT hr = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &piml));
136     if (FAILED_UNEXPECTEDLY(hr))
137     {
138         SendMessageW(combobox, CBEM_SETIMAGELIST, 0, 0);
139     }
140     else
141     {
142         SendMessageW(combobox, CBEM_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(piml));
143     }
144 
145     SendMessage(CBEM_SETEXTENDEDSTYLE,
146         CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT, CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT);
147 
148     fEditControl = reinterpret_cast<HWND>(SendMessage(CBEM_GETEDITCONTROL, 0, 0));
149     fComboBox = reinterpret_cast<HWND>(SendMessage(CBEM_GETCOMBOCONTROL, 0, 0));
150     hResult = CAddressEditBox_CreateInstance(IID_PPV_ARG(IAddressEditBox, &fAddressEditBox));
151     if (FAILED_UNEXPECTEDLY(hResult))
152         return hResult;
153 
154     hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &shellService));
155     if (FAILED_UNEXPECTEDLY(hResult))
156         return hResult;
157     hResult = fAddressEditBox->Init(combobox, fEditControl, 8, fSite /*(IAddressBand *)this*/);
158     if (FAILED_UNEXPECTEDLY(hResult))
159         return hResult;
160     hResult = shellService->SetOwner(fSite);
161     if (FAILED_UNEXPECTEDLY(hResult))
162         return hResult;
163 
164     fGoButtonShown = SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", FALSE, TRUE);
165     if (fGoButtonShown)
166         CreateGoButton();
167 
168     return hResult;
169 }
170 
171 HRESULT STDMETHODCALLTYPE CAddressBand::GetSite(REFIID riid, void **ppvSite)
172 {
173     if (fSite == NULL)
174         return E_FAIL;
175     return fSite->QueryInterface(riid, ppvSite);
176 }
177 
178 HRESULT STDMETHODCALLTYPE CAddressBand::GetWindow(HWND *lphwnd)
179 {
180     if (lphwnd == NULL)
181         return E_POINTER;
182     *lphwnd = m_hWnd;
183     return S_OK;
184 }
185 
186 HRESULT STDMETHODCALLTYPE CAddressBand::ContextSensitiveHelp(BOOL fEnterMode)
187 {
188     return E_NOTIMPL;
189 }
190 
191 HRESULT STDMETHODCALLTYPE CAddressBand::CloseDW(DWORD dwReserved)
192 {
193     ShowDW(FALSE);
194 
195     if (IsWindow())
196         DestroyWindow();
197 
198     m_hWnd = NULL;
199 
200     CComPtr<IShellService> pservice;
201     HRESULT hres = fAddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &pservice));
202     if (SUCCEEDED(hres ))
203         pservice->SetOwner(NULL);
204 
205     if (fAddressEditBox) fAddressEditBox.Release();
206     if (fSite) fSite.Release();
207 
208     if (m_himlNormal)
209         ImageList_Destroy(m_himlNormal);
210 
211     if (m_himlHot)
212         ImageList_Destroy(m_himlHot);
213 
214     return S_OK;
215 }
216 
217 HRESULT STDMETHODCALLTYPE CAddressBand::ResizeBorderDW(
218     const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
219 {
220     return E_NOTIMPL;
221 }
222 
223 HRESULT STDMETHODCALLTYPE CAddressBand::ShowDW(BOOL fShow)
224 {
225     if (m_hWnd)
226     {
227         if (fShow)
228             ShowWindow(SW_SHOW);
229         else
230             ShowWindow(SW_HIDE);
231     }
232     return S_OK;
233 }
234 
235 HRESULT STDMETHODCALLTYPE CAddressBand::QueryStatus(
236     const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[  ], OLECMDTEXT *pCmdText)
237 {
238     return IUnknown_QueryStatus(fAddressEditBox, *pguidCmdGroup, cCmds, prgCmds, pCmdText);
239 }
240 
241 HRESULT STDMETHODCALLTYPE CAddressBand::Exec(const GUID *pguidCmdGroup,
242     DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
243 {
244     // incomplete
245     return E_NOTIMPL;
246 }
247 
248 HRESULT STDMETHODCALLTYPE CAddressBand::HasFocusIO()
249 {
250     if (GetFocus() == fEditControl || SendMessage(CB_GETDROPPEDSTATE, 0, 0))
251         return S_OK;
252     return S_FALSE;
253 }
254 
255 HRESULT STDMETHODCALLTYPE CAddressBand::TranslateAcceleratorIO(LPMSG lpMsg)
256 {
257     if (lpMsg->hwnd == fEditControl)
258     {
259         switch (lpMsg->message)
260         {
261         case WM_SYSKEYDOWN:
262         case WM_SYSKEYUP:
263         case WM_SYSCOMMAND:
264         case WM_SYSDEADCHAR:
265         case WM_SYSCHAR:
266             return S_FALSE;
267         }
268 
269         TranslateMessage(lpMsg);
270         DispatchMessage(lpMsg);
271         return S_OK;
272     }
273     return S_FALSE;
274 }
275 
276 HRESULT STDMETHODCALLTYPE CAddressBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
277 {
278     if (fActivate)
279     {
280         IUnknown_OnFocusChangeIS(fSite, static_cast<IDeskBand *>(this), fActivate);
281         SetFocus();
282     }
283     return S_OK;
284 }
285 
286 HRESULT STDMETHODCALLTYPE CAddressBand::OnWinEvent(
287     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
288 {
289     CComPtr<IWinEventHandler>               winEventHandler;
290     HRESULT                                 hResult;
291     RECT                                    rect;
292 
293     if (theResult)
294         *theResult = 0;
295 
296     switch (uMsg)
297     {
298         case WM_WININICHANGE:
299             break;
300         case WM_COMMAND:
301             if (wParam == IDM_TOOLBARS_GOBUTTON)
302             {
303                 fGoButtonShown = !SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", FALSE, TRUE);
304                 SHRegSetUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", REG_SZ, fGoButtonShown ? (LPVOID)L"yes" : (LPVOID)L"no", fGoButtonShown ? 8 : 6, SHREGSET_FORCE_HKCU);
305                 if (!fGoButton)
306                     CreateGoButton();
307                 ::ShowWindow(fGoButton,fGoButtonShown ? SW_HIDE : SW_SHOW);
308                 GetWindowRect(&rect);
309                 SendMessage(m_hWnd,WM_SIZE,0,MAKELPARAM(rect.right-rect.left,rect.bottom-rect.top));
310                 // broadcast change notification to all explorer windows
311             }
312             break;
313     }
314     hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
315     if (FAILED_UNEXPECTEDLY(hResult))
316         return hResult;
317     return winEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
318 }
319 
320 HRESULT STDMETHODCALLTYPE CAddressBand::IsWindowOwner(HWND hWnd)
321 {
322     CComPtr<IWinEventHandler>               winEventHandler;
323     HRESULT                                 hResult;
324 
325     if (fAddressEditBox)
326     {
327         hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
328         if (FAILED_UNEXPECTEDLY(hResult))
329             return hResult;
330         return winEventHandler->IsWindowOwner(hWnd);
331     }
332     return S_FALSE;
333 }
334 
335 HRESULT STDMETHODCALLTYPE CAddressBand::FileSysChange(long param8, long paramC)
336 {
337     CComPtr<IAddressBand>                   addressBand;
338     HRESULT                                 hResult;
339 
340     hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
341     if (FAILED_UNEXPECTEDLY(hResult))
342         return hResult;
343     return addressBand->FileSysChange(param8, paramC);
344 }
345 
346 HRESULT STDMETHODCALLTYPE CAddressBand::Refresh(long param8)
347 {
348     CComPtr<IAddressBand>                   addressBand;
349     HRESULT                                 hResult;
350 
351     hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
352     if (FAILED_UNEXPECTEDLY(hResult))
353         return hResult;
354     return addressBand->Refresh(param8);
355 }
356 
357 HRESULT STDMETHODCALLTYPE CAddressBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
358 {
359     return E_NOTIMPL;
360 }
361 
362 HRESULT STDMETHODCALLTYPE CAddressBand::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
363 {
364     return E_NOTIMPL;
365 }
366 
367 HRESULT STDMETHODCALLTYPE CAddressBand::GetClassID(CLSID *pClassID)
368 {
369     if (pClassID == NULL)
370         return E_POINTER;
371     *pClassID = CLSID_SH_AddressBand;
372     return S_OK;
373 }
374 
375 HRESULT STDMETHODCALLTYPE CAddressBand::IsDirty()
376 {
377     return E_NOTIMPL;
378 }
379 
380 HRESULT STDMETHODCALLTYPE CAddressBand::Load(IStream *pStm)
381 {
382     // incomplete
383     return E_NOTIMPL;
384 }
385 
386 HRESULT STDMETHODCALLTYPE CAddressBand::Save(IStream *pStm, BOOL fClearDirty)
387 {
388     // incomplete
389     return E_NOTIMPL;
390 }
391 
392 HRESULT STDMETHODCALLTYPE CAddressBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
393 {
394     // incomplete
395     return E_NOTIMPL;
396 }
397 
398 LRESULT CAddressBand::OnNotifyClick(WPARAM wParam, NMHDR *notifyHeader, BOOL &bHandled)
399 {
400     if (notifyHeader->hwndFrom == fGoButton)
401     {
402         fAddressEditBox->Execute(0);
403     }
404     return 0;
405 }
406 
407 LRESULT CAddressBand::OnTipText(UINT idControl, NMHDR *notifyHeader, BOOL &bHandled)
408 {
409     if (notifyHeader->hwndFrom == fGoButton)
410     {
411         // TODO
412         // Go to "destination path"
413     }
414     return 0;
415 }
416 
417 LRESULT CAddressBand::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
418 {
419     POINT                                   pt;
420     POINT                                   ptOrig;
421     HWND                                    parentWindow;
422     LRESULT                                 result;
423 
424     if (fGoButtonShown == false)
425     {
426         bHandled = FALSE;
427         return 0;
428     }
429     pt.x = 0;
430     pt.y = 0;
431     parentWindow = GetParent();
432     ::MapWindowPoints(m_hWnd, parentWindow, &pt, 1);
433     OffsetWindowOrgEx(reinterpret_cast<HDC>(wParam), pt.x, pt.y, &ptOrig);
434     result = SendMessage(parentWindow, WM_ERASEBKGND, wParam, 0);
435     SetWindowOrgEx(reinterpret_cast<HDC>(wParam), ptOrig.x, ptOrig.y, NULL);
436     if (result == 0)
437     {
438         bHandled = FALSE;
439         return 0;
440     }
441     return result;
442 }
443 
444 LRESULT CAddressBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
445 {
446     RECT                                    goButtonBounds;
447     RECT                                    buttonBounds;
448     long                                    buttonWidth;
449     long                                    buttonHeight;
450     RECT                                    comboBoxBounds;
451     long                                    newHeight;
452     long                                    newWidth;
453 
454     if (fGoButtonShown == false)
455     {
456         bHandled = FALSE;
457         return 0;
458     }
459 
460     newHeight = HIWORD(lParam);
461     newWidth = LOWORD(lParam);
462 
463     if (!fGoButton)
464         CreateGoButton();
465 
466     SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
467     buttonWidth = buttonBounds.right - buttonBounds.left;
468     buttonHeight = buttonBounds.bottom - buttonBounds.top;
469 
470     DefWindowProc(WM_SIZE, wParam, MAKELONG(newWidth - buttonWidth - 2, newHeight));
471     ::GetWindowRect(fComboBox, &comboBoxBounds);
472     ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
473                     buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
474 
475     goButtonBounds.left = newWidth - buttonWidth;
476     goButtonBounds.top = 0;
477     goButtonBounds.right = newWidth - buttonWidth;
478     goButtonBounds.bottom = newHeight;
479     InvalidateRect(&goButtonBounds, TRUE);
480 
481     SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
482     return 0;
483 }
484 
485 LRESULT CAddressBand::OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
486 {
487     RECT                                    goButtonBounds;
488     RECT                                    buttonBounds;
489     long                                    buttonWidth;
490     long                                    buttonHeight;
491     RECT                                    comboBoxBounds;
492     WINDOWPOS                               positionInfoCopy;
493     long                                    newHeight;
494     long                                    newWidth;
495 
496     if (!fGoButtonShown)
497     {
498         bHandled = FALSE;
499         return 0;
500     }
501 
502     if (!fGoButton)
503         CreateGoButton();
504 
505     positionInfoCopy = *reinterpret_cast<WINDOWPOS *>(lParam);
506     newHeight = positionInfoCopy.cy;
507     newWidth = positionInfoCopy.cx;
508     SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
509 
510     buttonWidth = buttonBounds.right - buttonBounds.left;
511     buttonHeight = buttonBounds.bottom - buttonBounds.top;
512     positionInfoCopy.cx = newWidth - 2 - buttonWidth;
513     DefWindowProc(WM_WINDOWPOSCHANGING, wParam, reinterpret_cast<LPARAM>(&positionInfoCopy));
514     ::GetWindowRect(fComboBox, &comboBoxBounds);
515     ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
516                     buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
517 
518     goButtonBounds.left = newWidth - buttonWidth;
519     goButtonBounds.top = 0;
520     goButtonBounds.right = newWidth - buttonWidth;
521     goButtonBounds.bottom = newHeight;
522     InvalidateRect(&goButtonBounds, TRUE);
523 
524     SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
525     return 0;
526 }
527 
528 void CAddressBand::CreateGoButton()
529 {
530     const TBBUTTON buttonInfo [] = { { 0, 1, TBSTATE_ENABLED, 0 } };
531     HINSTANCE             shellInstance;
532 
533     shellInstance = _AtlBaseModule.GetResourceInstance();
534     m_himlNormal = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_NORMAL),
535                                            20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
536     m_himlHot = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_HOT),
537                                         20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
538 
539     fGoButton = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAMEW, 0, WS_CHILD | WS_CLIPSIBLINGS |
540                                WS_CLIPCHILDREN | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER |
541                                CCS_NOPARENTALIGN | CCS_NORESIZE,
542                                0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
543     SendMessage(fGoButton, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
544     SendMessage(fGoButton, TB_SETMAXTEXTROWS, 1, 0);
545     if (m_himlNormal)
546         SendMessage(fGoButton, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(m_himlNormal));
547     if (m_himlHot)
548         SendMessage(fGoButton, TB_SETHOTIMAGELIST, 0, reinterpret_cast<LPARAM>(m_himlHot));
549     SendMessage(fGoButton, TB_ADDSTRINGW,
550                 reinterpret_cast<WPARAM>(_AtlBaseModule.GetResourceInstance()), IDS_GOBUTTONLABEL);
551     SendMessage(fGoButton, TB_ADDBUTTONSW, 1, (LPARAM) &buttonInfo);
552 }
553