97d672f2589eaf62ae0c5f3577113d9895744b5a
[reactos.git] / reactos / dll / win32 / browseui / addressband.cpp
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 IUnknown_SetSite(fAddressEditBox, NULL);
201
202 if (fAddressEditBox) fAddressEditBox.Release();
203 if (fSite) fSite.Release();
204
205 return S_OK;
206 }
207
208 HRESULT STDMETHODCALLTYPE CAddressBand::ResizeBorderDW(
209 const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
210 {
211 return E_NOTIMPL;
212 }
213
214 HRESULT STDMETHODCALLTYPE CAddressBand::ShowDW(BOOL fShow)
215 {
216 if (m_hWnd)
217 {
218 if (fShow)
219 ShowWindow(SW_SHOW);
220 else
221 ShowWindow(SW_HIDE);
222 }
223 return S_OK;
224 }
225
226 HRESULT STDMETHODCALLTYPE CAddressBand::QueryStatus(
227 const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
228 {
229 return IUnknown_QueryStatus(fAddressEditBox, *pguidCmdGroup, cCmds, prgCmds, pCmdText);
230 }
231
232 HRESULT STDMETHODCALLTYPE CAddressBand::Exec(const GUID *pguidCmdGroup,
233 DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
234 {
235 // incomplete
236 return E_NOTIMPL;
237 }
238
239 HRESULT STDMETHODCALLTYPE CAddressBand::HasFocusIO()
240 {
241 if (GetFocus() == fEditControl || SendMessage(CB_GETDROPPEDSTATE, 0, 0))
242 return S_OK;
243 return S_FALSE;
244 }
245
246 HRESULT STDMETHODCALLTYPE CAddressBand::TranslateAcceleratorIO(LPMSG lpMsg)
247 {
248 if (lpMsg->hwnd == fEditControl)
249 {
250 switch (lpMsg->message)
251 {
252 case WM_SYSKEYDOWN:
253 case WM_SYSKEYUP:
254 case WM_SYSCOMMAND:
255 case WM_SYSDEADCHAR:
256 case WM_SYSCHAR:
257 return S_FALSE;
258 }
259
260 TranslateMessage(lpMsg);
261 DispatchMessage(lpMsg);
262 return S_OK;
263 }
264 return S_FALSE;
265 }
266
267 HRESULT STDMETHODCALLTYPE CAddressBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
268 {
269 if (fActivate)
270 {
271 IUnknown_OnFocusChangeIS(fSite, static_cast<IDeskBand *>(this), fActivate);
272 SetFocus();
273 }
274 return S_OK;
275 }
276
277 HRESULT STDMETHODCALLTYPE CAddressBand::OnWinEvent(
278 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
279 {
280 CComPtr<IWinEventHandler> winEventHandler;
281 HRESULT hResult;
282 RECT rect;
283
284 *theResult = 0;
285
286 switch (uMsg)
287 {
288 case WM_WININICHANGE:
289 break;
290 case WM_COMMAND:
291 if (wParam == IDM_TOOLBARS_GOBUTTON)
292 {
293 fGoButtonShown = !SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", FALSE, TRUE);
294 SHRegSetUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", REG_SZ, fGoButtonShown ? (LPVOID)L"yes" : (LPVOID)L"no", fGoButtonShown ? 8 : 6, SHREGSET_FORCE_HKCU);
295 if (!fGoButton)
296 CreateGoButton();
297 ::ShowWindow(fGoButton,fGoButtonShown ? SW_HIDE : SW_SHOW);
298 GetWindowRect(&rect);
299 SendMessage(m_hWnd,WM_SIZE,0,MAKELPARAM(rect.right-rect.left,rect.bottom-rect.top));
300 // broadcast change notification to all explorer windows
301 }
302 break;
303 }
304 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
305 if (FAILED_UNEXPECTEDLY(hResult))
306 return hResult;
307 return winEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
308 }
309
310 HRESULT STDMETHODCALLTYPE CAddressBand::IsWindowOwner(HWND hWnd)
311 {
312 CComPtr<IWinEventHandler> winEventHandler;
313 HRESULT hResult;
314
315 if (fAddressEditBox)
316 {
317 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
318 if (FAILED_UNEXPECTEDLY(hResult))
319 return hResult;
320 return winEventHandler->IsWindowOwner(hWnd);
321 }
322 return S_FALSE;
323 }
324
325 HRESULT STDMETHODCALLTYPE CAddressBand::FileSysChange(long param8, long paramC)
326 {
327 CComPtr<IAddressBand> addressBand;
328 HRESULT hResult;
329
330 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
331 if (FAILED_UNEXPECTEDLY(hResult))
332 return hResult;
333 return addressBand->FileSysChange(param8, paramC);
334 }
335
336 HRESULT STDMETHODCALLTYPE CAddressBand::Refresh(long param8)
337 {
338 CComPtr<IAddressBand> addressBand;
339 HRESULT hResult;
340
341 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
342 if (FAILED_UNEXPECTEDLY(hResult))
343 return hResult;
344 return addressBand->Refresh(param8);
345 }
346
347 HRESULT STDMETHODCALLTYPE CAddressBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
348 {
349 return E_NOTIMPL;
350 }
351
352 HRESULT STDMETHODCALLTYPE CAddressBand::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
353 {
354 return E_NOTIMPL;
355 }
356
357 HRESULT STDMETHODCALLTYPE CAddressBand::GetClassID(CLSID *pClassID)
358 {
359 if (pClassID == NULL)
360 return E_POINTER;
361 *pClassID = CLSID_SH_AddressBand;
362 return S_OK;
363 }
364
365 HRESULT STDMETHODCALLTYPE CAddressBand::IsDirty()
366 {
367 return E_NOTIMPL;
368 }
369
370 HRESULT STDMETHODCALLTYPE CAddressBand::Load(IStream *pStm)
371 {
372 // incomplete
373 return E_NOTIMPL;
374 }
375
376 HRESULT STDMETHODCALLTYPE CAddressBand::Save(IStream *pStm, BOOL fClearDirty)
377 {
378 // incomplete
379 return E_NOTIMPL;
380 }
381
382 HRESULT STDMETHODCALLTYPE CAddressBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
383 {
384 // incomplete
385 return E_NOTIMPL;
386 }
387
388 LRESULT CAddressBand::OnNotifyClick(WPARAM wParam, NMHDR *notifyHeader, BOOL &bHandled)
389 {
390 if (notifyHeader->hwndFrom == fGoButton)
391 {
392 fAddressEditBox->Execute(0);
393 }
394 return 0;
395 }
396
397 LRESULT CAddressBand::OnTipText(UINT idControl, NMHDR *notifyHeader, BOOL &bHandled)
398 {
399 if (notifyHeader->hwndFrom == fGoButton)
400 {
401 // TODO
402 // Go to "destination path"
403 }
404 return 0;
405 }
406
407 LRESULT CAddressBand::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
408 {
409 POINT pt;
410 POINT ptOrig;
411 HWND parentWindow;
412 LRESULT result;
413
414 if (fGoButtonShown == false)
415 {
416 bHandled = FALSE;
417 return 0;
418 }
419 pt.x = 0;
420 pt.y = 0;
421 parentWindow = GetParent();
422 ::MapWindowPoints(m_hWnd, parentWindow, &pt, 1);
423 OffsetWindowOrgEx(reinterpret_cast<HDC>(wParam), pt.x, pt.y, &ptOrig);
424 result = SendMessage(parentWindow, WM_ERASEBKGND, wParam, 0);
425 SetWindowOrgEx(reinterpret_cast<HDC>(wParam), ptOrig.x, ptOrig.y, NULL);
426 if (result == 0)
427 {
428 bHandled = FALSE;
429 return 0;
430 }
431 return result;
432 }
433
434 LRESULT CAddressBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
435 {
436 RECT goButtonBounds;
437 RECT buttonBounds;
438 long buttonWidth;
439 long buttonHeight;
440 RECT comboBoxBounds;
441 long newHeight;
442 long newWidth;
443
444 if (fGoButtonShown == false)
445 {
446 bHandled = FALSE;
447 return 0;
448 }
449
450 newHeight = HIWORD(lParam);
451 newWidth = LOWORD(lParam);
452
453 if (!fGoButton)
454 CreateGoButton();
455
456 SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
457 buttonWidth = buttonBounds.right - buttonBounds.left;
458 buttonHeight = buttonBounds.bottom - buttonBounds.top;
459
460 DefWindowProc(WM_SIZE, wParam, MAKELONG(newWidth - buttonWidth - 2, newHeight));
461 ::GetWindowRect(fComboBox, &comboBoxBounds);
462 ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
463 buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
464
465 goButtonBounds.left = newWidth - buttonWidth;
466 goButtonBounds.top = 0;
467 goButtonBounds.right = newWidth - buttonWidth;
468 goButtonBounds.bottom = newHeight;
469 InvalidateRect(&goButtonBounds, TRUE);
470
471 SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
472 return 0;
473 }
474
475 LRESULT CAddressBand::OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
476 {
477 RECT goButtonBounds;
478 RECT buttonBounds;
479 long buttonWidth;
480 long buttonHeight;
481 RECT comboBoxBounds;
482 WINDOWPOS positionInfoCopy;
483 long newHeight;
484 long newWidth;
485
486 if (!fGoButtonShown)
487 {
488 bHandled = FALSE;
489 return 0;
490 }
491
492 if (!fGoButton)
493 CreateGoButton();
494
495 positionInfoCopy = *reinterpret_cast<WINDOWPOS *>(lParam);
496 newHeight = positionInfoCopy.cy;
497 newWidth = positionInfoCopy.cx;
498 SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
499
500 buttonWidth = buttonBounds.right - buttonBounds.left;
501 buttonHeight = buttonBounds.bottom - buttonBounds.top;
502 positionInfoCopy.cx = newWidth - 2 - buttonWidth;
503 DefWindowProc(WM_WINDOWPOSCHANGING, wParam, reinterpret_cast<LPARAM>(&positionInfoCopy));
504 ::GetWindowRect(fComboBox, &comboBoxBounds);
505 ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
506 buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
507
508 goButtonBounds.left = newWidth - buttonWidth;
509 goButtonBounds.top = 0;
510 goButtonBounds.right = newWidth - buttonWidth;
511 goButtonBounds.bottom = newHeight;
512 InvalidateRect(&goButtonBounds, TRUE);
513
514 SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
515 return 0;
516 }
517
518 void CAddressBand::CreateGoButton()
519 {
520 const TBBUTTON buttonInfo [] = { { 0, 1, TBSTATE_ENABLED, 0 } };
521 HIMAGELIST normalImagelist;
522 HIMAGELIST hotImageList;
523 HINSTANCE shellInstance;
524
525
526 shellInstance = GetModuleHandle(_T("shell32.dll"));
527 normalImagelist = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_NORMAL),
528 20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
529 hotImageList = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_HOT),
530 20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
531
532 fGoButton = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAMEW, 0, WS_CHILD | WS_CLIPSIBLINGS |
533 WS_CLIPCHILDREN | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER |
534 CCS_NOPARENTALIGN | CCS_NORESIZE,
535 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
536 SendMessage(fGoButton, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
537 SendMessage(fGoButton, TB_SETMAXTEXTROWS, 1, 0);
538 if (normalImagelist)
539 SendMessage(fGoButton, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(normalImagelist));
540 if (hotImageList)
541 SendMessage(fGoButton, TB_SETHOTIMAGELIST, 0, reinterpret_cast<LPARAM>(hotImageList));
542 SendMessage(fGoButton, TB_ADDSTRINGW,
543 reinterpret_cast<WPARAM>(_AtlBaseModule.GetResourceInstance()), IDS_GOBUTTONLABEL);
544 SendMessage(fGoButton, TB_ADDBUTTONSW, 1, (LPARAM) &buttonInfo);
545 }