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