Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenautocomplete.cpp
Go to the documentation of this file.
00001 /* 00002 * AutoComplete interfaces implementation. 00003 * 00004 * Copyright 2004 Maxime Bellengé <maxime.bellenge@laposte.net> 00005 * Copyright 2009 Andrew Hill 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 /* 00023 Implemented: 00024 - ACO_AUTOAPPEND style 00025 - ACO_AUTOSUGGEST style 00026 - ACO_UPDOWNKEYDROPSLIST style 00027 00028 - Handle pwzsRegKeyPath and pwszQuickComplete in Init 00029 00030 TODO: 00031 - implement ACO_SEARCH style 00032 - implement ACO_FILTERPREFIXES style 00033 - implement ACO_USETAB style 00034 - implement ACO_RTLREADING style 00035 00036 */ 00037 00038 #include <precomp.h> 00039 00040 WINE_DEFAULT_DEBUG_CHANNEL(shell); 00041 00042 static const WCHAR autocomplete_propertyW[] = {'W','i','n','e',' ','A','u','t','o', 00043 'c','o','m','p','l','e','t','e',' ', 00044 'c','o','n','t','r','o','l',0}; 00045 00046 /************************************************************************** 00047 * IAutoComplete_Constructor 00048 */ 00049 CAutoComplete::CAutoComplete() 00050 { 00051 enabled = TRUE; 00052 initialized = FALSE; 00053 options = ACO_AUTOAPPEND; 00054 wpOrigEditProc = NULL; 00055 hwndListBox = NULL; 00056 txtbackup = NULL; 00057 quickComplete = NULL; 00058 hwndEdit = NULL; 00059 wpOrigLBoxProc = NULL; 00060 } 00061 00062 /************************************************************************** 00063 * IAutoComplete_Destructor 00064 */ 00065 CAutoComplete::~CAutoComplete() 00066 { 00067 TRACE(" destroying IAutoComplete(%p)\n", this); 00068 HeapFree(GetProcessHeap(), 0, quickComplete); 00069 HeapFree(GetProcessHeap(), 0, txtbackup); 00070 RemovePropW(hwndEdit, autocomplete_propertyW); 00071 SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR)wpOrigEditProc); 00072 if (hwndListBox) 00073 DestroyWindow(hwndListBox); 00074 } 00075 00076 /****************************************************************************** 00077 * IAutoComplete_fnEnable 00078 */ 00079 HRESULT WINAPI CAutoComplete::Enable(BOOL fEnable) 00080 { 00081 HRESULT hr = S_OK; 00082 00083 TRACE("(%p)->(%s)\n", this, (fEnable) ? "true" : "false"); 00084 00085 enabled = fEnable; 00086 00087 return hr; 00088 } 00089 00090 /****************************************************************************** 00091 * IAutoComplete_fnInit 00092 */ 00093 HRESULT WINAPI CAutoComplete::Init(HWND hwndEdit, IUnknown *punkACL, LPCOLESTR pwzsRegKeyPath, LPCOLESTR pwszQuickComplete) 00094 { 00095 static const WCHAR lbName[] = {'L','i','s','t','B','o','x',0}; 00096 00097 TRACE("(%p)->(0x%08lx, %p, %s, %s)\n", 00098 this, hwndEdit, punkACL, debugstr_w(pwzsRegKeyPath), debugstr_w(pwszQuickComplete)); 00099 00100 if (options & ACO_AUTOSUGGEST) 00101 TRACE(" ACO_AUTOSUGGEST\n"); 00102 if (options & ACO_AUTOAPPEND) 00103 TRACE(" ACO_AUTOAPPEND\n"); 00104 if (options & ACO_SEARCH) 00105 FIXME(" ACO_SEARCH not supported\n"); 00106 if (options & ACO_FILTERPREFIXES) 00107 FIXME(" ACO_FILTERPREFIXES not supported\n"); 00108 if (options & ACO_USETAB) 00109 FIXME(" ACO_USETAB not supported\n"); 00110 if (options & ACO_UPDOWNKEYDROPSLIST) 00111 TRACE(" ACO_UPDOWNKEYDROPSLIST\n"); 00112 if (options & ACO_RTLREADING) 00113 FIXME(" ACO_RTLREADING not supported\n"); 00114 00115 if (!hwndEdit || !punkACL) 00116 return E_INVALIDARG; 00117 00118 if (this->initialized) 00119 { 00120 WARN("Autocompletion object is already initialized\n"); 00121 /* This->hwndEdit is set to NULL when the edit window is destroyed. */ 00122 return this->hwndEdit ? E_FAIL : E_UNEXPECTED; 00123 } 00124 00125 if (!SUCCEEDED (punkACL->QueryInterface(IID_IEnumString, (LPVOID *)&enumstr))) 00126 { 00127 TRACE("No IEnumString interface\n"); 00128 return E_NOINTERFACE; 00129 } 00130 00131 this->hwndEdit = hwndEdit; 00132 this->initialized = TRUE; 00133 wpOrigEditProc = (WNDPROC)SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR) ACEditSubclassProc); 00134 // SetWindowLongPtrW(hwndEdit, GWLP_USERDATA, (LONG_PTR)this); 00135 SetPropW( hwndEdit, autocomplete_propertyW, (HANDLE)this ); 00136 00137 if (options & ACO_AUTOSUGGEST) 00138 { 00139 HWND hwndParent; 00140 00141 hwndParent = GetParent(hwndEdit); 00142 00143 /* FIXME : The listbox should be resizable with the mouse. WS_THICKFRAME looks ugly */ 00144 hwndListBox = CreateWindowExW(0, lbName, NULL, 00145 WS_BORDER | WS_CHILD | WS_VSCROLL | LBS_HASSTRINGS | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT, 00146 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 00147 hwndParent, NULL, 00148 (HINSTANCE)GetWindowLongPtrW(hwndParent, GWLP_HINSTANCE), NULL); 00149 00150 if (hwndListBox) 00151 { 00152 wpOrigLBoxProc = (WNDPROC)SetWindowLongPtrW(hwndListBox, GWLP_WNDPROC, (LONG_PTR)ACLBoxSubclassProc); 00153 SetWindowLongPtrW(hwndListBox, GWLP_USERDATA, (LONG_PTR)this); 00154 } 00155 } 00156 00157 if (pwzsRegKeyPath) 00158 { 00159 WCHAR *key; 00160 WCHAR result[MAX_PATH]; 00161 WCHAR *value; 00162 HKEY hKey = 0; 00163 LONG res; 00164 LONG len; 00165 00166 /* pwszRegKeyPath contains the key as well as the value, so we split */ 00167 key = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pwzsRegKeyPath) + 1) * sizeof(WCHAR)); 00168 00169 if (key) 00170 { 00171 wcscpy(key, pwzsRegKeyPath); 00172 value = const_cast<WCHAR *>(strrchrW(key, '\\')); 00173 00174 if (value) 00175 { 00176 *value = 0; 00177 value++; 00178 /* Now value contains the value and buffer the key */ 00179 res = RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey); 00180 00181 if (res != ERROR_SUCCESS) 00182 { 00183 /* if the key is not found, MSDN states we must seek in HKEY_LOCAL_MACHINE */ 00184 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey); 00185 } 00186 00187 if (res == ERROR_SUCCESS) 00188 { 00189 res = RegQueryValueW(hKey, value, result, &len); 00190 if (res == ERROR_SUCCESS) 00191 { 00192 quickComplete = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 00193 wcscpy(quickComplete, result); 00194 } 00195 RegCloseKey(hKey); 00196 } 00197 } 00198 00199 HeapFree(GetProcessHeap(), 0, key); 00200 } 00201 else 00202 { 00203 TRACE("HeapAlloc Failed when trying to alloca %d bytes\n", (wcslen(pwzsRegKeyPath) + 1) * sizeof(WCHAR)); 00204 return S_FALSE; 00205 } 00206 } 00207 00208 if ((pwszQuickComplete) && (!quickComplete)) 00209 { 00210 quickComplete = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pwszQuickComplete) + 1) * sizeof(WCHAR)); 00211 00212 if (quickComplete) 00213 { 00214 wcscpy(quickComplete, pwszQuickComplete); 00215 } 00216 else 00217 { 00218 TRACE("HeapAlloc Failed when trying to alloca %d bytes\n", (wcslen(pwszQuickComplete) + 1) * sizeof(WCHAR)); 00219 return S_FALSE; 00220 } 00221 } 00222 00223 return S_OK; 00224 } 00225 00226 /************************************************************************** 00227 * IAutoComplete_fnGetOptions 00228 */ 00229 HRESULT WINAPI CAutoComplete::GetOptions(DWORD *pdwFlag) 00230 { 00231 HRESULT hr = S_OK; 00232 00233 TRACE("(%p) -> (%p)\n", this, pdwFlag); 00234 00235 *pdwFlag = options; 00236 00237 return hr; 00238 } 00239 00240 /************************************************************************** 00241 * IAutoComplete_fnSetOptions 00242 */ 00243 HRESULT WINAPI CAutoComplete::SetOptions(DWORD dwFlag) 00244 { 00245 HRESULT hr = S_OK; 00246 00247 TRACE("(%p) -> (0x%x)\n", this, dwFlag); 00248 00249 options = (AUTOCOMPLETEOPTIONS)dwFlag; 00250 00251 return hr; 00252 } 00253 00254 /* 00255 Window procedure for autocompletion 00256 */ 00257 LRESULT APIENTRY CAutoComplete::ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 00258 { 00259 CAutoComplete *pThis = (CAutoComplete *)GetPropW(hwnd, autocomplete_propertyW);;//GetWindowLongPtrW(hwnd, GWLP_USERDATA); 00260 LPOLESTR strs; 00261 HRESULT hr; 00262 WCHAR hwndText[255]; 00263 WCHAR *hwndQCText; 00264 RECT r; 00265 BOOL control, filled, displayall = FALSE; 00266 int cpt, height, sel; 00267 00268 if (!pThis->enabled) 00269 { 00270 return CallWindowProcW(pThis->wpOrigEditProc, hwnd, uMsg, wParam, lParam); 00271 } 00272 00273 switch (uMsg) 00274 { 00275 case CB_SHOWDROPDOWN: 00276 { 00277 ShowWindow(pThis->hwndListBox, SW_HIDE); 00278 }; break; 00279 00280 case WM_KILLFOCUS: 00281 { 00282 if ((pThis->options & ACO_AUTOSUGGEST) && ((HWND)wParam != pThis->hwndListBox)) 00283 { 00284 ShowWindow(pThis->hwndListBox, SW_HIDE); 00285 } 00286 return CallWindowProcW(pThis->wpOrigEditProc, hwnd, uMsg, wParam, lParam); 00287 }; break; 00288 00289 case WM_KEYUP: 00290 { 00291 GetWindowTextW(hwnd, (LPWSTR)hwndText, 255); 00292 00293 switch(wParam) 00294 { 00295 case VK_RETURN: 00296 { 00297 /* If quickComplete is set and control is pressed, replace the string */ 00298 control = GetKeyState(VK_CONTROL) & 0x8000; 00299 if (control && pThis->quickComplete) 00300 { 00301 hwndQCText = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 00302 (wcslen(pThis->quickComplete)+wcslen(hwndText))*sizeof(WCHAR)); 00303 sel = swprintf(hwndQCText, pThis->quickComplete, hwndText); 00304 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)hwndQCText); 00305 SendMessageW(hwnd, EM_SETSEL, 0, sel); 00306 HeapFree(GetProcessHeap(), 0, hwndQCText); 00307 } 00308 00309 ShowWindow(pThis->hwndListBox, SW_HIDE); 00310 return 0; 00311 }; break; 00312 00313 case VK_LEFT: 00314 case VK_RIGHT: 00315 { 00316 return 0; 00317 }; break; 00318 00319 case VK_UP: 00320 case VK_DOWN: 00321 { 00322 /* Two cases here : 00323 - if the listbox is not visible, displays it 00324 with all the entries if the style ACO_UPDOWNKEYDROPSLIST 00325 is present but does not select anything. 00326 - if the listbox is visible, change the selection 00327 */ 00328 if ( (pThis->options & (ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST)) 00329 && (!IsWindowVisible(pThis->hwndListBox) && (! *hwndText)) ) 00330 { 00331 /* We must display all the entries */ 00332 displayall = TRUE; 00333 } 00334 else 00335 { 00336 if (IsWindowVisible(pThis->hwndListBox)) 00337 { 00338 int count; 00339 00340 count = SendMessageW(pThis->hwndListBox, LB_GETCOUNT, 0, 0); 00341 /* Change the selection */ 00342 sel = SendMessageW(pThis->hwndListBox, LB_GETCURSEL, 0, 0); 00343 if (wParam == VK_UP) 00344 sel = ((sel-1)<0)?count-1:sel-1; 00345 else 00346 sel = ((sel+1)>= count)?-1:sel+1; 00347 00348 SendMessageW(pThis->hwndListBox, LB_SETCURSEL, sel, 0); 00349 00350 if (sel != -1) 00351 { 00352 WCHAR *msg; 00353 int len; 00354 00355 len = SendMessageW(pThis->hwndListBox, LB_GETTEXTLEN, sel, (LPARAM)NULL); 00356 msg = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len + 1) * sizeof(WCHAR)); 00357 00358 if (msg) 00359 { 00360 SendMessageW(pThis->hwndListBox, LB_GETTEXT, sel, (LPARAM)msg); 00361 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)msg); 00362 SendMessageW(hwnd, EM_SETSEL, wcslen(msg), wcslen(msg)); 00363 00364 HeapFree(GetProcessHeap(), 0, msg); 00365 } 00366 else 00367 { 00368 TRACE("HeapAlloc failed to allocate %d bytes\n", (len + 1) * sizeof(WCHAR)); 00369 } 00370 } 00371 else 00372 { 00373 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)pThis->txtbackup); 00374 SendMessageW(hwnd, EM_SETSEL, wcslen(pThis->txtbackup), wcslen(pThis->txtbackup)); 00375 } 00376 } 00377 return 0; 00378 } 00379 }; break; 00380 00381 case VK_BACK: 00382 case VK_DELETE: 00383 { 00384 if ((! *hwndText) && (pThis->options & ACO_AUTOSUGGEST)) 00385 { 00386 ShowWindow(pThis->hwndListBox, SW_HIDE); 00387 return CallWindowProcW(pThis->wpOrigEditProc, hwnd, uMsg, wParam, lParam); 00388 } 00389 00390 if (pThis->options & ACO_AUTOAPPEND) 00391 { 00392 DWORD b; 00393 SendMessageW(hwnd, EM_GETSEL, (WPARAM)&b, (LPARAM)NULL); 00394 if (b>1) 00395 { 00396 hwndText[b-1] = '\0'; 00397 } 00398 else 00399 { 00400 hwndText[0] = '\0'; 00401 SetWindowTextW(hwnd, hwndText); 00402 } 00403 } 00404 }; break; 00405 00406 default: 00407 ; 00408 } 00409 00410 SendMessageW(pThis->hwndListBox, LB_RESETCONTENT, 0, 0); 00411 00412 HeapFree(GetProcessHeap(), 0, pThis->txtbackup); 00413 00414 pThis->txtbackup = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(hwndText)+1)*sizeof(WCHAR)); 00415 00416 if (pThis->txtbackup) 00417 { 00418 wcscpy(pThis->txtbackup, hwndText); 00419 } 00420 else 00421 { 00422 TRACE("HeapAlloc failed to allocate %d bytes\n", (wcslen(hwndText)+1)*sizeof(WCHAR)); 00423 } 00424 00425 /* Returns if there is no text to search and we doesn't want to display all the entries */ 00426 if ((!displayall) && (! *hwndText) ) 00427 break; 00428 00429 pThis->enumstr->Reset(); 00430 filled = FALSE; 00431 00432 for(cpt = 0;;) 00433 { 00434 hr = pThis->enumstr->Next(1, &strs, NULL); 00435 if (hr != S_OK) 00436 break; 00437 00438 if ((LPWSTR)strstrW(strs, hwndText) == strs) 00439 { 00440 00441 if (pThis->options & ACO_AUTOAPPEND) 00442 { 00443 SetWindowTextW(hwnd, strs); 00444 SendMessageW(hwnd, EM_SETSEL, wcslen(hwndText), wcslen(strs)); 00445 break; 00446 } 00447 00448 if (pThis->options & ACO_AUTOSUGGEST) 00449 { 00450 SendMessageW(pThis->hwndListBox, LB_ADDSTRING, 0, (LPARAM)strs); 00451 filled = TRUE; 00452 cpt++; 00453 } 00454 } 00455 } 00456 00457 if (pThis->options & ACO_AUTOSUGGEST) 00458 { 00459 if (filled) 00460 { 00461 height = SendMessageW(pThis->hwndListBox, LB_GETITEMHEIGHT, 0, 0); 00462 SendMessageW(pThis->hwndListBox, LB_CARETOFF, 0, 0); 00463 GetWindowRect(hwnd, &r); 00464 SetParent(pThis->hwndListBox, HWND_DESKTOP); 00465 /* It seems that Windows XP displays 7 lines at most 00466 and otherwise displays a vertical scroll bar */ 00467 SetWindowPos(pThis->hwndListBox, HWND_TOP, 00468 r.left, r.bottom + 1, r.right - r.left, min(height * 7, height * (cpt + 1)), 00469 SWP_SHOWWINDOW ); 00470 } 00471 else 00472 { 00473 ShowWindow(pThis->hwndListBox, SW_HIDE); 00474 } 00475 } 00476 00477 }; break; 00478 00479 default: 00480 { 00481 return CallWindowProcW(pThis->wpOrigEditProc, hwnd, uMsg, wParam, lParam); 00482 } 00483 00484 } 00485 00486 return 0; 00487 } 00488 00489 LRESULT APIENTRY CAutoComplete::ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 00490 { 00491 CAutoComplete *pThis = (CAutoComplete *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); 00492 WCHAR *msg; 00493 int sel, len; 00494 00495 switch (uMsg) 00496 { 00497 case WM_MOUSEMOVE: 00498 { 00499 sel = SendMessageW(hwnd, LB_ITEMFROMPOINT, 0, lParam); 00500 SendMessageW(hwnd, LB_SETCURSEL, (WPARAM)sel, (LPARAM)0); 00501 }; break; 00502 00503 case WM_LBUTTONDOWN: 00504 { 00505 sel = SendMessageW(hwnd, LB_GETCURSEL, 0, 0); 00506 00507 if (sel < 0) 00508 break; 00509 00510 len = SendMessageW(pThis->hwndListBox, LB_GETTEXTLEN, sel, 0); 00511 msg = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len + 1) * sizeof(WCHAR)); 00512 00513 if (msg) 00514 { 00515 SendMessageW(hwnd, LB_GETTEXT, sel, (LPARAM)msg); 00516 SendMessageW(pThis->hwndEdit, WM_SETTEXT, 0, (LPARAM)msg); 00517 SendMessageW(pThis->hwndEdit, EM_SETSEL, 0, wcslen(msg)); 00518 ShowWindow(hwnd, SW_HIDE); 00519 00520 HeapFree(GetProcessHeap(), 0, msg); 00521 } 00522 else 00523 { 00524 TRACE("HeapAlloc failed to allocate %d bytes\n", (len + 1) * sizeof(WCHAR)); 00525 } 00526 00527 }; break; 00528 00529 default: 00530 return CallWindowProcW(pThis->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam); 00531 } 00532 return 0; 00533 } Generated on Sun May 27 2012 04:26:15 for ReactOS by
1.7.6.1
|