c33b983bc084f4aa15b17a75141658882d749fb0
[reactos.git] / 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
27 /*
28 TODO:
29 ****Add command handler for show/hide Go button to OnWinEvent
30 ****Add tooltip notify handler
31 **Properly implement GetBandInfo
32 **Add support for showing/hiding Go button
33 **Fix so Go button will be shown/hidden properly on load
34 **Add correct text to Go button
35 **Implement TranslateAcceleratorIO
36 Implement Exec
37 Implement QueryService
38 Implement Load
39 Implement Save
40 */
41
42 CAddressBand::CAddressBand()
43 {
44 fEditControl = NULL;
45 fGoButton = NULL;
46 fComboBox = NULL;
47 fGoButtonShown = false;
48 }
49
50 CAddressBand::~CAddressBand()
51 {
52 }
53
54 void CAddressBand::FocusChange(BOOL bFocus)
55 {
56 // m_bFocus = bFocus;
57
58 //Inform the input object site that the focus has changed.
59 if (fSite)
60 {
61 #if 0
62 fSite->OnFocusChangeIS((IDockingWindow *)this, bFocus);
63 #endif
64 }
65 }
66
67 HRESULT STDMETHODCALLTYPE CAddressBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
68 {
69 if (pdbi->dwMask & DBIM_MINSIZE)
70 {
71 pdbi->ptMinSize.x = 400;
72 pdbi->ptMinSize.y = 22;
73 }
74 if (pdbi->dwMask & DBIM_MAXSIZE)
75 {
76 pdbi->ptMaxSize.x = 0;
77 pdbi->ptMaxSize.y = 0;
78 }
79 if (pdbi->dwMask & DBIM_INTEGRAL)
80 {
81 pdbi->ptIntegral.x = 0;
82 pdbi->ptIntegral.y = 0;
83 }
84 if (pdbi->dwMask & DBIM_ACTUAL)
85 {
86 pdbi->ptActual.x = 400;
87 pdbi->ptActual.y = 22;
88 }
89 if (pdbi->dwMask & DBIM_TITLE)
90 wcscpy(pdbi->wszTitle, L"Address");
91 if (pdbi->dwMask & DBIM_MODEFLAGS)
92 pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
93 if (pdbi->dwMask & DBIM_BKCOLOR)
94 pdbi->crBkgnd = 0;
95 return S_OK;
96 }
97
98 HRESULT STDMETHODCALLTYPE CAddressBand::SetSite(IUnknown *pUnkSite)
99 {
100 CComPtr<IShellService> shellService;
101 CComPtr<IUnknown> offset34;
102 HWND parentWindow;
103 HWND combobox;
104 static const TBBUTTON buttonInfo[] = { {0, 1, TBSTATE_ENABLED, 0} };
105 HIMAGELIST normalImagelist;
106 HIMAGELIST hotImageList;
107 HINSTANCE shellInstance;
108 HRESULT hResult;
109
110 fSite.Release();
111 if (pUnkSite == NULL)
112 return S_OK;
113
114 hResult = pUnkSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &fSite));
115 if (FAILED(hResult))
116 return hResult;
117
118 // get window handle of parent
119 parentWindow = NULL;
120 hResult = IUnknown_GetWindow(pUnkSite, &parentWindow);
121
122 if (!::IsWindow(parentWindow))
123 return E_FAIL;
124
125 // create combo box ex
126 combobox = CreateWindowEx(WS_EX_TOOLWINDOW, WC_COMBOBOXEXW, NULL, WS_CHILD | WS_VISIBLE |
127 WS_CLIPCHILDREN | WS_TABSTOP | CCS_NODIVIDER | CCS_NOMOVEY,
128 0, 0, 500, 250, parentWindow, (HMENU)0xa205, _AtlBaseModule.GetModuleInstance(), 0);
129 if (combobox == NULL)
130 return E_FAIL;
131 SubclassWindow(combobox);
132
133 SendMessage(CBEM_SETEXTENDEDSTYLE,
134 CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT, CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT);
135
136 fEditControl = reinterpret_cast<HWND>(SendMessage(CBEM_GETEDITCONTROL, 0, 0));
137 fComboBox = reinterpret_cast<HWND>(SendMessage(CBEM_GETCOMBOCONTROL, 0, 0));
138 #if 1
139 hResult = CoCreateInstance(CLSID_AddressEditBox, NULL, CLSCTX_INPROC_SERVER,
140 IID_PPV_ARG(IAddressEditBox, &fAddressEditBox));
141 if (FAILED(hResult))
142 return hResult;
143 #else
144 // instantiate new version
145 #endif
146
147 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &shellService));
148 if (FAILED(hResult))
149 return hResult;
150 hResult = fAddressEditBox->Init(combobox, fEditControl, 8, pUnkSite /*(IAddressBand *)this*/);
151 if (FAILED(hResult))
152 return hResult;
153 hResult = shellService->SetOwner(pUnkSite);
154 if (FAILED(hResult))
155 return hResult;
156
157 // TODO: properly initialize this from registry
158 fGoButtonShown = true;
159
160 shellInstance = GetModuleHandle(_T("shell32.dll"));
161 normalImagelist = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_NORMAL),
162 20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
163 hotImageList = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_HOT),
164 20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
165
166 fGoButton = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAMEW, 0, WS_CHILD | WS_CLIPSIBLINGS |
167 WS_CLIPCHILDREN | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER |
168 CCS_NOPARENTALIGN | CCS_NORESIZE,
169 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
170 SendMessage(fGoButton, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
171 SendMessage(fGoButton, TB_SETMAXTEXTROWS, 1, 0);
172 SendMessage(fGoButton, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(normalImagelist));
173 SendMessage(fGoButton, TB_SETHOTIMAGELIST, 0, reinterpret_cast<LPARAM>(hotImageList));
174 SendMessage(fGoButton, TB_ADDSTRINGW,
175 reinterpret_cast<WPARAM>(_AtlBaseModule.GetResourceInstance()), IDS_GOBUTTONLABEL);
176 SendMessage(fGoButton, TB_ADDBUTTONSW, 1, (LPARAM)&buttonInfo);
177
178 return hResult;
179 }
180
181 HRESULT STDMETHODCALLTYPE CAddressBand::GetSite(REFIID riid, void **ppvSite)
182 {
183 if (fSite == NULL)
184 return E_FAIL;
185 return fSite->QueryInterface(riid, ppvSite);
186 }
187
188 HRESULT STDMETHODCALLTYPE CAddressBand::GetWindow(HWND *lphwnd)
189 {
190 if (lphwnd == NULL)
191 return E_POINTER;
192 *lphwnd = m_hWnd;
193 return S_OK;
194 }
195
196 HRESULT STDMETHODCALLTYPE CAddressBand::ContextSensitiveHelp(BOOL fEnterMode)
197 {
198 return E_NOTIMPL;
199 }
200
201 HRESULT STDMETHODCALLTYPE CAddressBand::CloseDW(DWORD dwReserved)
202 {
203 ShowDW(FALSE);
204
205 if (IsWindow())
206 DestroyWindow();
207
208 m_hWnd = NULL;
209
210 return S_OK;
211 }
212
213 HRESULT STDMETHODCALLTYPE CAddressBand::ResizeBorderDW(
214 const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
215 {
216 return E_NOTIMPL;
217 }
218
219 HRESULT STDMETHODCALLTYPE CAddressBand::ShowDW(BOOL fShow)
220 {
221 if (m_hWnd)
222 {
223 if (fShow)
224 ShowWindow(SW_SHOW);
225 else
226 ShowWindow(SW_HIDE);
227 }
228 return S_OK;
229 }
230
231 HRESULT STDMETHODCALLTYPE CAddressBand::QueryStatus(
232 const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
233 {
234 CComPtr<IOleCommandTarget> oleCommandTarget;
235 HRESULT hResult;
236
237 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &oleCommandTarget));
238 if (FAILED(hResult))
239 return hResult;
240 return oleCommandTarget->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
241 }
242
243 HRESULT STDMETHODCALLTYPE CAddressBand::Exec(const GUID *pguidCmdGroup,
244 DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
245 {
246 // incomplete
247 return E_NOTIMPL;
248 }
249
250 HRESULT STDMETHODCALLTYPE CAddressBand::HasFocusIO()
251 {
252 if (GetFocus() == fEditControl || SendMessage(CB_GETDROPPEDSTATE, 0, 0))
253 return S_OK;
254 return S_FALSE;
255 }
256
257 HRESULT STDMETHODCALLTYPE CAddressBand::TranslateAcceleratorIO(LPMSG lpMsg)
258 {
259 // incomplete
260 return S_FALSE;
261 }
262
263 HRESULT STDMETHODCALLTYPE CAddressBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
264 {
265 CComPtr<IInputObjectSite> inputObjectSite;
266 HRESULT hResult;
267
268 if (fActivate)
269 {
270 hResult = fSite->QueryInterface(IID_PPV_ARG(IInputObjectSite, &inputObjectSite));
271 if (FAILED(hResult))
272 return hResult;
273 hResult = inputObjectSite->OnFocusChangeIS(static_cast<IDeskBand *>(this), fActivate);
274 SetFocus();
275 }
276 return S_OK;
277 }
278
279 HRESULT STDMETHODCALLTYPE CAddressBand::OnWinEvent(
280 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
281 {
282 CComPtr<IWinEventHandler> winEventHandler;
283 HRESULT hResult;
284
285 switch (uMsg)
286 {
287 case WM_WININICHANGE:
288 break;
289 case WM_COMMAND:
290 if (wParam == IDM_TOOLBARS_GOBUTTON)
291 {
292 // toggle whether the Go button is displayed
293 // setting is Yes or No, stored in key "Software\Microsoft\Internet Explorer\Main" in value ShowGoButton
294 // broadcast change notification to all explorer windows
295 }
296 break;
297 }
298 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
299 if (FAILED(hResult))
300 return hResult;
301 return winEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
302 }
303
304 HRESULT STDMETHODCALLTYPE CAddressBand::IsWindowOwner(HWND hWnd)
305 {
306 CComPtr<IWinEventHandler> winEventHandler;
307 HRESULT hResult;
308
309 if (fAddressEditBox)
310 {
311 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
312 if (FAILED(hResult))
313 return hResult;
314 return winEventHandler->IsWindowOwner(hWnd);
315 }
316 return S_FALSE;
317 }
318
319 HRESULT STDMETHODCALLTYPE CAddressBand::FileSysChange(long param8, long paramC)
320 {
321 CComPtr<IAddressBand> addressBand;
322 HRESULT hResult;
323
324 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
325 if (FAILED(hResult))
326 return hResult;
327 return addressBand->FileSysChange(param8, paramC);
328 }
329
330 HRESULT STDMETHODCALLTYPE CAddressBand::Refresh(long param8)
331 {
332 CComPtr<IAddressBand> addressBand;
333 HRESULT hResult;
334
335 hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
336 if (FAILED(hResult))
337 return hResult;
338 return addressBand->Refresh(param8);
339 }
340
341 HRESULT STDMETHODCALLTYPE CAddressBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
342 {
343 return E_NOTIMPL;
344 }
345
346 HRESULT STDMETHODCALLTYPE CAddressBand::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
347 {
348 return E_NOTIMPL;
349 }
350
351 HRESULT STDMETHODCALLTYPE CAddressBand::GetClassID(CLSID *pClassID)
352 {
353 if (pClassID == NULL)
354 return E_POINTER;
355 *pClassID = CLSID_SH_AddressBand;
356 return S_OK;
357 }
358
359 HRESULT STDMETHODCALLTYPE CAddressBand::IsDirty()
360 {
361 return E_NOTIMPL;
362 }
363
364 HRESULT STDMETHODCALLTYPE CAddressBand::Load(IStream *pStm)
365 {
366 // incomplete
367 return E_NOTIMPL;
368 }
369
370 HRESULT STDMETHODCALLTYPE CAddressBand::Save(IStream *pStm, BOOL fClearDirty)
371 {
372 // incomplete
373 return E_NOTIMPL;
374 }
375
376 HRESULT STDMETHODCALLTYPE CAddressBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
377 {
378 // incomplete
379 return E_NOTIMPL;
380 }
381
382 LRESULT CAddressBand::OnNotifyClick(WPARAM wParam, NMHDR *notifyHeader, BOOL &bHandled)
383 {
384 if (notifyHeader->hwndFrom == fGoButton)
385 {
386 SendMessage(fEditControl, WM_KEYDOWN, 13, 0);
387 SendMessage(fEditControl, WM_KEYUP, 13, 0);
388 }
389 return 0;
390 }
391
392 LRESULT CAddressBand::OnTipText(UINT idControl, NMHDR *notifyHeader, BOOL &bHandled)
393 {
394 if (notifyHeader->hwndFrom == fGoButton)
395 {
396 // TODO
397 // Go to "destination path"
398 }
399 return 0;
400 }
401
402 LRESULT CAddressBand::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
403 {
404 POINT pt;
405 POINT ptOrig;
406 HWND parentWindow;
407 LRESULT result;
408
409 if (fGoButtonShown == false)
410 {
411 bHandled = FALSE;
412 return 0;
413 }
414 pt.x = 0;
415 pt.y = 0;
416 parentWindow = GetParent();
417 ::MapWindowPoints(m_hWnd, parentWindow, &pt, 1);
418 OffsetWindowOrgEx(reinterpret_cast<HDC>(wParam), pt.x, pt.y, &ptOrig);
419 result = SendMessage(parentWindow, WM_ERASEBKGND, wParam, 0);
420 SetWindowOrgEx(reinterpret_cast<HDC>(wParam), ptOrig.x, ptOrig.y, NULL);
421 if (result == 0)
422 {
423 bHandled = FALSE;
424 return 0;
425 }
426 return result;
427 }
428
429 LRESULT CAddressBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
430 {
431 RECT goButtonBounds;
432 RECT buttonBounds;
433 long buttonWidth;
434 long buttonHeight;
435 RECT comboBoxBounds;
436 long newHeight;
437 long newWidth;
438
439 if (fGoButtonShown == false)
440 {
441 bHandled = FALSE;
442 return 0;
443 }
444
445 newHeight = HIWORD(lParam);
446 newWidth = LOWORD(lParam);
447
448 SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
449 buttonWidth = buttonBounds.right - buttonBounds.left;
450 buttonHeight = buttonBounds.bottom - buttonBounds.top;
451
452 DefWindowProc(WM_SIZE, wParam, MAKELONG(newWidth - buttonWidth - 2, newHeight));
453 ::GetWindowRect(fComboBox, &comboBoxBounds);
454 ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
455 buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
456
457 goButtonBounds.left = newWidth - buttonWidth;
458 goButtonBounds.top = 0;
459 goButtonBounds.right = newWidth - buttonWidth;
460 goButtonBounds.bottom = newHeight;
461 InvalidateRect(&goButtonBounds, TRUE);
462
463 SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
464 return 0;
465 }
466
467 LRESULT CAddressBand::OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
468 {
469 RECT goButtonBounds;
470 RECT buttonBounds;
471 long buttonWidth;
472 long buttonHeight;
473 RECT comboBoxBounds;
474 WINDOWPOS positionInfoCopy;
475 long newHeight;
476 long newWidth;
477
478 if (!fGoButtonShown)
479 {
480 bHandled = FALSE;
481 return 0;
482 }
483
484 positionInfoCopy = *reinterpret_cast<WINDOWPOS *>(lParam);
485 newHeight = positionInfoCopy.cy;
486 newWidth = positionInfoCopy.cx;
487 SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
488
489 buttonWidth = buttonBounds.right - buttonBounds.left;
490 buttonHeight = buttonBounds.bottom - buttonBounds.top;
491 positionInfoCopy.cx = newWidth - 2 - buttonWidth;
492 DefWindowProc(WM_WINDOWPOSCHANGING, wParam, reinterpret_cast<LPARAM>(&positionInfoCopy));
493 ::GetWindowRect(fComboBox, &comboBoxBounds);
494 ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
495 buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
496
497 goButtonBounds.left = newWidth - buttonWidth;
498 goButtonBounds.top = 0;
499 goButtonBounds.right = newWidth - buttonWidth;
500 goButtonBounds.bottom = newHeight;
501 InvalidateRect(&goButtonBounds, TRUE);
502
503 SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
504 return 0;
505 }
506
507 HRESULT CreateAddressBand(REFIID riid, void **ppv)
508 {
509 CComObject<CAddressBand> *theMenuBar;
510 HRESULT hResult;
511
512 if (ppv == NULL)
513 return E_POINTER;
514 *ppv = NULL;
515 ATLTRY (theMenuBar = new CComObject<CAddressBand>);
516 if (theMenuBar == NULL)
517 return E_OUTOFMEMORY;
518 hResult = theMenuBar->QueryInterface(riid, reinterpret_cast<void **>(ppv));
519 if (FAILED(hResult))
520 {
521 delete theMenuBar;
522 return hResult;
523 }
524 return S_OK;
525 }