2b0aaf48ddabca73f091072a62956985799617f3
[reactos.git] / reactos / dll / win32 / browseui / addresseditbox.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 This class handles the combo box of the address band.
23 */
24
25 #include "precomp.h"
26
27 /*
28 TODO:
29 Add auto completion support
30 Subclass windows in Init method
31 Connect to browser connection point
32 Handle navigation complete messages to set edit box text
33 Handle listbox dropdown message and fill contents
34 Add drag and drop of icon in edit box
35 Handle enter in edit box to browse to typed path
36 Handle change notifies to update appropriately
37 Add handling of enter in edit box
38 Fix so selection in combo listbox navigates
39 Fix so editing text and typing enter navigates
40 */
41
42 CAddressEditBox::CAddressEditBox() :
43 fCombobox(NULL, this, 1),
44 fEditWindow(NULL, this, 1),
45 fSite(NULL)
46 {
47 }
48
49 CAddressEditBox::~CAddressEditBox()
50 {
51 }
52
53 HRESULT STDMETHODCALLTYPE CAddressEditBox::SetOwner(IUnknown *)
54 {
55 // connect to browser connection point
56 return 0;
57 }
58
59 HRESULT STDMETHODCALLTYPE CAddressEditBox::FileSysChange(long param8, long paramC)
60 {
61 return E_NOTIMPL;
62 }
63
64 HRESULT STDMETHODCALLTYPE CAddressEditBox::Refresh(long param8)
65 {
66 return E_NOTIMPL;
67 }
68
69 HRESULT STDMETHODCALLTYPE CAddressEditBox::Init(HWND comboboxEx, HWND editControl, long param14, IUnknown *param18)
70 {
71 CComPtr<IBrowserService> browserService;
72
73 fCombobox.SubclassWindow(comboboxEx);
74 fEditWindow.SubclassWindow(editControl);
75 fSite = param18;
76
77 SHAutoComplete(fEditWindow.m_hWnd, SHACF_FILESYSTEM | SHACF_URLALL | SHACF_USETAB);
78
79 // take advice to watch events
80 HRESULT hResult = IUnknown_QueryService(param18, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
81 if (SUCCEEDED(hResult))
82 {
83 hResult = AtlAdvise(browserService, static_cast<IDispatch *>(this), DIID_DWebBrowserEvents, &fAdviseCookie);
84 }
85
86 return hResult;
87 }
88
89 HRESULT STDMETHODCALLTYPE CAddressEditBox::SetCurrentDir(long paramC)
90 {
91 return E_NOTIMPL;
92 }
93
94 HRESULT STDMETHODCALLTYPE CAddressEditBox::ParseNow(long paramC)
95 {
96 ULONG eaten;
97 ULONG attributes;
98 HRESULT hr;
99 HWND topLevelWindow;
100
101 CComPtr<IShellBrowser> pisb;
102 hr = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pisb));
103 if (FAILED_UNEXPECTEDLY(hr))
104 return hr;
105
106 hr = IUnknown_GetWindow(pisb, &topLevelWindow);
107 if (FAILED_UNEXPECTEDLY(hr))
108 return hr;
109
110 LPWSTR input;
111 int inputLength = fCombobox.GetWindowTextLength() + 2;
112
113 input = new WCHAR[inputLength];
114 fCombobox.GetWindowText(input, inputLength);
115
116 LPWSTR address;
117 int addressLength = ExpandEnvironmentStrings(input, NULL, 0);
118
119 if (addressLength <= 0)
120 {
121 address = input;
122 }
123 else
124 {
125 addressLength += 2;
126 address = new WCHAR[addressLength];
127 if (!ExpandEnvironmentStrings(input, address, addressLength))
128 {
129 delete[] address;
130 address = input;
131 }
132 }
133
134 CComPtr<IShellFolder> psfDesktop;
135 hr = SHGetDesktopFolder(&psfDesktop);
136 if (SUCCEEDED(hr))
137 {
138 hr = psfDesktop->ParseDisplayName(topLevelWindow, NULL, address, &eaten, &pidlLastParsed, &attributes);
139 }
140
141 if (address != input)
142 delete [] address;
143 delete [] input;
144
145 return hr;
146 }
147
148 HRESULT STDMETHODCALLTYPE CAddressEditBox::Execute(long paramC)
149 {
150 HRESULT hr;
151
152 /*
153 * Parse the path is it wasn't parsed
154 */
155 if (!pidlLastParsed)
156 ParseNow(0);
157
158 if (!pidlLastParsed)
159 return E_FAIL;
160
161 /*
162 * Get the IShellBrowser and IBrowserService interfaces of the shell browser
163 */
164 CComPtr<IShellBrowser> pisb;
165 hr = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pisb));
166 if (FAILED(hr))
167 return hr;
168
169 CComPtr<IBrowserService> pbs;
170 pisb->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs));
171 if (FAILED(hr))
172 return hr;
173
174 /*
175 * Get the current pidl of the shellbrowser and check if it is the same with the parsed one
176 */
177 PIDLIST_ABSOLUTE pidl;
178 hr = pbs->GetPidl(&pidl);
179 if (FAILED(hr))
180 return hr;
181
182 CComPtr<IShellFolder> psf;
183 hr = SHGetDesktopFolder(&psf);
184 if (FAILED(hr))
185 return hr;
186
187 hr = psf->CompareIDs(0, pidl, pidlLastParsed);
188
189 SHFree(pidl);
190 if (hr == 0)
191 return S_OK;
192
193 /*
194 * Attempt to browse to the parsed pidl
195 */
196 hr = pisb->BrowseObject(pidlLastParsed, 0);
197 if (SUCCEEDED(hr))
198 return hr;
199
200 /*
201 * Browsing to the pidl failed so it's not a folder. So invoke its defaule command.
202 */
203 HWND topLevelWindow;
204 hr = IUnknown_GetWindow(pisb, &topLevelWindow);
205 if (FAILED(hr))
206 return hr;
207
208 LPCITEMIDLIST pidlChild;
209 CComPtr<IShellFolder> sf;
210 hr = SHBindToParent(pidlLastParsed, IID_PPV_ARG(IShellFolder, &sf), &pidlChild);
211 if (FAILED(hr))
212 return hr;
213
214 hr = SHInvokeDefaultCommand(topLevelWindow, sf, pidlChild);
215 if (FAILED(hr))
216 return hr;
217
218 return hr;
219 }
220
221 HRESULT STDMETHODCALLTYPE CAddressEditBox::Save(long paramC)
222 {
223 return E_NOTIMPL;
224 }
225
226 HRESULT STDMETHODCALLTYPE CAddressEditBox::OnWinEvent(
227 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
228 {
229 LPNMHDR hdr;
230
231 *theResult = 0;
232
233 switch (uMsg)
234 {
235 case WM_NOTIFY:
236 hdr = (LPNMHDR) lParam;
237 if (hdr->code == CBEN_ENDEDIT)
238 {
239 NMCBEENDEDITW *endEdit = (NMCBEENDEDITW*) lParam;
240 if (endEdit->iWhy == CBENF_RETURN)
241 {
242 Execute(0);
243 }
244 else if (endEdit->iWhy == CBENF_ESCAPE)
245 {
246 /* Reset the contents of the combo box */
247 }
248 }
249 break;
250 }
251 return S_OK;
252 }
253
254 HRESULT STDMETHODCALLTYPE CAddressEditBox::IsWindowOwner(HWND hWnd)
255 {
256 if (fCombobox.m_hWnd == hWnd)
257 return S_OK;
258 if (fEditWindow.m_hWnd == hWnd)
259 return S_OK;
260 return S_FALSE;
261 }
262
263 HRESULT STDMETHODCALLTYPE CAddressEditBox::QueryStatus(
264 const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
265 {
266 return E_NOTIMPL;
267 }
268
269 HRESULT STDMETHODCALLTYPE CAddressEditBox::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
270 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
271 {
272 return E_NOTIMPL;
273 }
274
275 HRESULT STDMETHODCALLTYPE CAddressEditBox::GetTypeInfoCount(UINT *pctinfo)
276 {
277 return E_NOTIMPL;
278 }
279
280 HRESULT STDMETHODCALLTYPE CAddressEditBox::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
281 {
282 return E_NOTIMPL;
283 }
284
285 HRESULT STDMETHODCALLTYPE CAddressEditBox::GetIDsOfNames(
286 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
287 {
288 return E_NOTIMPL;
289 }
290
291 HRESULT STDMETHODCALLTYPE CAddressEditBox::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
292 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
293 {
294 if (pDispParams == NULL)
295 return E_INVALIDARG;
296
297 switch (dispIdMember)
298 {
299 case DISPID_NAVIGATECOMPLETE2:
300 case DISPID_DOCUMENTCOMPLETE:
301 pidlLastParsed = NULL;
302 }
303 return S_OK;
304 }
305
306 HRESULT STDMETHODCALLTYPE CAddressEditBox::GetClassID(CLSID *pClassID)
307 {
308 if (pClassID == NULL)
309 return E_POINTER;
310 *pClassID = CLSID_AddressEditBox;
311 return S_OK;
312 }
313
314 HRESULT STDMETHODCALLTYPE CAddressEditBox::IsDirty()
315 {
316 return E_NOTIMPL;
317 }
318
319 HRESULT STDMETHODCALLTYPE CAddressEditBox::Load(IStream *pStm)
320 {
321 return E_NOTIMPL;
322 }
323
324 HRESULT STDMETHODCALLTYPE CAddressEditBox::Save(IStream *pStm, BOOL fClearDirty)
325 {
326 return E_NOTIMPL;
327 }
328
329 HRESULT STDMETHODCALLTYPE CAddressEditBox::GetSizeMax(ULARGE_INTEGER *pcbSize)
330 {
331 return E_NOTIMPL;
332 }
333
334 HRESULT CreateAddressEditBox(REFIID riid, void **ppv)
335 {
336 return ShellObjectCreator<CAddressEditBox>(riid, ppv);
337 }