ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

autocomplete.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.