update for HEAD-2003091401
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / IEShellListCtrl.cpp
1 //*******************************************************************************
2 // COPYRIGHT NOTES
3 // ---------------
4 // You may use this source code, compile or redistribute it as part of your application 
5 // for free. You cannot redistribute it as a part of a software development 
6 // library without the agreement of the author. If the sources are 
7 // distributed along with the application, you should leave the original 
8 // copyright notes in the source code without any changes.
9 // This code can be used WITHOUT ANY WARRANTIES at your own risk.
10 // 
11 // For the latest updates to this code, check this site:
12 // http://www.masmex.com 
13 // after Sept 2000
14 // 
15 // Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
16 //*******************************************************************************
17
18 // IEShellListCtrl.cpp : implementation file
19 #include "stdafx.h"
20 #include "IEShellListCtrl.h"
21 #include "UIMessages.h"
22 #include "dirwalk.h"
23 #include "cbformats.h"
24
25 #ifdef _DEBUG
26 #define new DEBUG_NEW
27 #undef THIS_FILE
28 static char THIS_FILE[] = __FILE__;
29 #endif
30
31 #define UMAKEINT64(low,high) ((unsigned __int64)(((DWORD)(low)) | ((unsigned __int64)((DWORD)(high))) << 32))
32 /////////////////////////////////////////////////////////////////////////////
33 // CIEShellListCtrl
34
35 CIEShellListCtrl::CIEShellListCtrl()
36 {
37         SetEditSubItems(false);
38         SetDropFiles(false);
39         ZeroMemory(&m_tvid,sizeof(m_tvid));
40         m_psfSubFolder = NULL;
41         m_pMalloc = NULL;
42         m_bCallBack = false;
43         m_bNoExt = false;
44         m_nThreadCount = 0;
45         m_bRefreshAllowed = true;
46         m_bPopulateInit = false;
47         m_bInitiliazed = false;
48         m_bNotifyParent = false;
49         m_pidlInternet = NULL;
50         SHGetMalloc(&m_pMalloc);
51         SHGetSpecialFolderLocation(NULL,CSIDL_INTERNET,&m_pidlInternet);
52         m_sColumns = _T("Name|Size|Type|Modified");
53 }
54
55 CIEShellListCtrl::~CIEShellListCtrl()
56 {
57         FreeTVID();
58         AllItemsDeleted();
59         if (m_pidlInternet)
60                 m_pMalloc->Release();
61         if (m_pMalloc)
62                 m_pMalloc->Release();
63 }
64
65 void CIEShellListCtrl::PopupTheMenu(int nRow,CPoint point)
66 {
67         if (!GetSelectedCount())
68                 return;
69         int nSel=-1;
70         LPLVITEMDATA lplvid=NULL;
71         LPITEMIDLIST *pidls=(LPITEMIDLIST*)GetShellPidl().GetMalloc()->Alloc(GetSelectedCount()*sizeof(LPITEMIDLIST));
72         int i=0;
73         while ((nSel = GetNextSel(nSel)) != -1)
74         {
75                 lplvid=(LPLVITEMDATA)GetItemData(nSel);
76                 pidls[i] = lplvid->lpi;
77                 i++;
78         }
79         // at least one
80         if (pidls && i)
81         {
82                 GetShellPidl().PopupTheMenu(m_hWnd, lplvid->lpsfParent, pidls, i, &point);
83         }
84         GetShellPidl().Free(pidls);
85 }
86
87 void CIEShellListCtrl::ShellExecute(int nRow,LPCTSTR pszVerb)
88 {
89         SHELLEXECUTEINFO si;
90         ZeroMemory(&si,sizeof(si));
91         si.cbSize = sizeof(si);
92         si.hwnd = GetSafeHwnd();
93         si.nShow = SW_SHOW;
94         si.lpIDList = (LPVOID)GetPathPidl(nRow);
95         si.fMask  = SEE_MASK_INVOKEIDLIST;
96         if (pszVerb)
97                 si.lpVerb = pszVerb;
98         ShellExecuteEx(&si);
99 }
100
101 void CIEShellListCtrl::SetNotificationObject(bool bNotify)
102 {
103         if (bNotify)
104                 CreateFileChangeThread(GetSafeHwnd());
105         else
106                 DestroyThreads();
107 }
108
109 void CIEShellListCtrl::FreeInterface(IUnknown *pInterface)
110 {
111         if (pInterface)
112                 pInterface->Release();
113 }
114
115 void CIEShellListCtrl::DestroyThreads()
116 {
117     if (m_nThreadCount == 0) 
118                 return;
119     for (UINT i=0; i<m_nThreadCount; i++)
120             m_event[i].SetEvent();
121     ::WaitForMultipleObjects (m_nThreadCount, m_hThreads, TRUE, INFINITE);
122     for (i=0; i<m_nThreadCount; i++)
123         delete m_pThreads[i];
124     m_nThreadCount = 0;
125 }
126
127 void CIEShellListCtrl::FreeTVID()
128 {
129         if (m_tvid.lpsfParent)
130                 m_tvid.lpsfParent->Release();
131         if (m_tvid.lpi)
132                 m_pMalloc->Free(m_tvid.lpi);
133         if (m_tvid.lpifq)
134                 m_pMalloc->Free(m_tvid.lpifq);
135         ZeroMemory(&m_tvid,sizeof(m_tvid));
136         if (m_psfSubFolder)
137                 m_psfSubFolder->Release();
138         m_psfSubFolder = NULL;
139 }
140
141 CString CIEShellListCtrl::GetCurrPathName()
142 {
143         return GetPathName(GetCurSel());
144 }
145
146 CString CIEShellListCtrl::GetPathName(int nRow)
147 {
148         if (nRow == -1)
149                 nRow = GetCurSel();
150         CString sPath;
151         if (nRow == -1)
152                 return sPath;
153         LPLVITEMDATA plvit = (LPLVITEMDATA)GetItemData(nRow);
154         ASSERT(plvit);
155         if (plvit == NULL)
156                 return sPath;
157         SHGetPathFromIDList(plvit->lpifq,sPath.GetBuffer(MAX_PATH));
158         sPath.ReleaseBuffer();
159         return sPath;
160 }
161
162 LPCITEMIDLIST CIEShellListCtrl::GetPathPidl(int nRow)
163 {
164         if (nRow == -1)
165                 return NULL;
166         LPLVITEMDATA plvit = (LPLVITEMDATA)GetItemData(nRow);
167         ASSERT(plvit);
168         if (plvit == NULL)
169                 return NULL;
170         return plvit->lpifq;
171 }
172
173 void CIEShellListCtrl::FillExcludedFileTypes(CComboBox &cb)
174 {
175         cb.ResetContent();
176         for(POSITION pos=m_ExcludedLookup.GetHeadPosition();pos != NULL;m_ExcludedLookup.GetNext(pos))
177         {
178                 cb.AddString(m_ExcludedLookup.GetAt(pos));
179         }
180 }
181
182 void CIEShellListCtrl::SetExcludedFileTypes(CComboBox &cb)
183 {
184         m_ExcludedLookup.RemoveAll();
185         CString sText;
186         for(int i=0;i < cb.GetCount();i++)
187         {
188                 cb.GetLBText(i,sText);
189                 m_ExcludedLookup.AddHead(sText);
190         }
191 }
192
193 void CIEShellListCtrl::LoadFilterFiles(const CString &sFileFilter)
194 {
195         m_FilterLookup.RemoveAll();
196         CFileFind ff;
197         CString sPath;
198         if (FAILED(GetShellPidl().SHPidlToPathEx(m_tvid.lpifq,sPath)))
199                 return;
200         if (sPath.Right(1) != _T('\\'))
201                 sPath += _T('\\');
202         CString sFindPath;
203         CString sMask;
204         LPCTSTR pszFilter=sFileFilter;
205         pszFilter = GetFilterMask(pszFilter,sMask);
206         while (pszFilter != NULL)
207         {
208                 sFindPath = sPath;
209                 sFindPath += sMask;
210                 BOOL bFind = ff.FindFile(sFindPath);  
211                 while (bFind)
212                 {
213                         bFind = ff.FindNextFile();
214                         m_FilterLookup.AddHead(ff.GetFilePath());
215                 }
216                 pszFilter = GetFilterMask(pszFilter,sMask);
217         }
218 }
219
220 LPCTSTR CIEShellListCtrl::GetFilterMask(LPCTSTR pszFilter,CString &sMask)
221 {
222         if (*pszFilter == '\0')
223                 return NULL;
224         TCHAR szMask[MAX_PATH];
225         szMask[0] = 0;
226         for(int i=0;*pszFilter != '\0';i++)
227         {
228                 if (*pszFilter == _T(';') || *pszFilter == _T(','))
229                 {
230                         pszFilter = _tcsinc(pszFilter);
231                         break;
232                 }
233                 szMask[i] = *pszFilter;
234                 pszFilter = _tcsinc(pszFilter);
235         }
236         szMask[i] = 0;
237         sMask = szMask;
238         return pszFilter;
239 }
240
241 void CIEShellListCtrl::AllItemsDeleted()
242 {
243         LPLVITEMDATA pItemData=NULL;
244         for(vecListItemData::iterator it=m_vecItemData.begin();it != m_vecItemData.end();it++)
245         {
246                 pItemData = *it;
247                 if (pItemData)
248                 {
249                         if (pItemData->lpsfParent)
250                                 pItemData->lpsfParent->Release();
251                         if (pItemData->lpi)
252                                 m_pMalloc->Free(pItemData->lpi);  
253                         if (pItemData->lpifq)
254                                 m_pMalloc->Free(pItemData->lpifq);  
255                         if (pItemData->lParam)
256                         {
257                                 PSLC_COLUMN_DATA pColData = (PSLC_COLUMN_DATA)pItemData->lParam;
258                                 if (pColData->pidl)
259                                         GetShellPidl().FreePidl(pColData->pidl);
260                                 delete pColData;
261                         }
262                         m_pMalloc->Free(pItemData);
263                 }
264         }
265         m_vecItemData.erase(m_vecItemData.begin(),m_vecItemData.end());
266 }
267
268 void CIEShellListCtrl::StartPopulate()
269 {
270         m_bPopulateInit = true;
271         DeleteAllItems();
272         for(UINT i=0;i < m_nThreadCount;i++)
273                 m_MonitorEvent[i].SetEvent();
274         if (m_sFileFilter.IsEmpty() || m_sFileFilter == _T("*.*") || m_sFileFilter == _T("*"))
275                 return;
276         LoadFilterFiles(m_sFileFilter);
277 }
278
279 void CIEShellListCtrl::EndPopulate()
280 {
281         m_bPopulateInit = false;
282         Sort();
283         SetColumnWidths();
284 }
285
286 BOOL CIEShellListCtrl::Populate(LPTVITEMDATA lptvid)
287 {
288         IShellFolder *pFolder=NULL;
289         BOOL bRet=FALSE;
290         HRESULT hr=E_FAIL;
291         if (lptvid->lpsfParent)
292         {
293                 hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,0,IID_IShellFolder,(LPVOID*)&pFolder);
294         }
295         else
296         {
297                 LPSHELLFOLDER psfDesktop;
298                 LPITEMIDLIST pidlDesktop=NULL;
299                 hr=SHGetDesktopFolder(&psfDesktop);
300                 SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&pidlDesktop);
301                 if (GetShellPidl().ComparePidls(NULL,lptvid->lpifq,pidlDesktop))
302                 {
303                         pFolder = psfDesktop;
304                 }
305                 else
306                 {
307                         hr=psfDesktop->BindToObject(lptvid->lpifq,0,IID_IShellFolder,(LPVOID*)&pFolder);
308                         psfDesktop->Release();
309                 }
310                 if (pidlDesktop)
311                         GetShellPidl().FreePidl(pidlDesktop);
312         }
313         if (SUCCEEDED(hr))
314         {
315                 bRet = Populate(lptvid,pFolder,true);
316                 pFolder->Release();
317         }
318         return bRet;
319 }
320
321 BOOL CIEShellListCtrl::Populate(LPCTSTR pszPath, bool bCallBack)
322 {
323         LPITEMIDLIST pidlfq=NULL;
324         LPITEMIDLIST pidl=NULL;
325         LPSHELLFOLDER pDesktop = NULL;
326     SHGetDesktopFolder(&pDesktop);
327         if (FAILED(GetShellPidl().SHPathToPidlEx(pszPath,&pidlfq,pDesktop)))
328                 return FALSE;
329         LPSHELLFOLDER pSubFolder = NULL;
330 #if 1 // bug fix by Dion Loy
331         if (FAILED(pDesktop->BindToObject(pidlfq, 0, IID_IShellFolder,(LPVOID*)&pSubFolder)))
332 #else
333         if (FAILED(pDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pSubFolder)))
334 #endif
335                 return FALSE;
336         pidl = GetShellPidl().CopyLastItemID(pidlfq);
337         TVITEMDATA tvid;
338         tvid.lpifq = pidlfq;
339         tvid.lpi = pidl;
340         tvid.lpsfParent = NULL;
341         BOOL bRet = Populate(&tvid,pSubFolder,bCallBack);
342         if (pDesktop)
343                 pDesktop->Release();
344         if (pSubFolder)
345                 pSubFolder->Release();
346         if (pidl)
347                 m_pMalloc->Free(pidl);
348         if (pidlfq)
349                 m_pMalloc->Free(pidlfq);
350                 
351         return bRet;
352 }
353
354 BOOL CIEShellListCtrl::Populate(LPTVITEMDATA lptvid,LPSHELLFOLDER psfFolder,bool bCallBack)
355 {
356         m_bCallBack = bCallBack;
357         FreeTVID();
358         m_tvid.lpi = GetShellPidl().CopyItemIDList(lptvid->lpi);
359         m_tvid.lpifq = GetShellPidl().CopyItemIDList(lptvid->lpifq);
360 #ifdef _DEBUG
361         CString sPath;
362         GetShellPidl().SHPidlToPathEx(m_tvid.lpifq,sPath,NULL);
363         TRACE1("Populating path %s in CIEShellListCtrl\n",sPath);
364 #endif  
365         if (lptvid->lpsfParent)
366         {
367                 m_tvid.lpsfParent = lptvid->lpsfParent;
368                 m_tvid.lpsfParent->AddRef();
369         }
370         m_psfSubFolder = psfFolder;
371         m_psfSubFolder->AddRef();
372         Load();
373     return TRUE;
374 }
375
376 CString CIEShellListCtrl::GetColumns()
377 {
378         SHELLDETAILS sd;
379         LPTSTR pszHeader=NULL;
380         CString sColumns;
381         for(int i=0;SUCCEEDED(m_ShellDetails.GetDetailsOf(NULL,i,&sd));i++)
382         {
383                 GetShellPidl().StrRetToStr(sd.str,&pszHeader,NULL);
384                 if (pszHeader)
385                 {
386                         TRACE1("Column found %s\n",pszHeader);  
387                         if (!sColumns.IsEmpty())
388                                 sColumns += _T("|");
389                         sColumns += pszHeader;
390                         GetShellPidl().Free(pszHeader);
391                         pszHeader= NULL;
392                 }
393         }
394         return sColumns;
395 }
396
397 void CIEShellListCtrl::InitColumns()
398 {
399         CString sColumns = GetColumns();
400         if (sColumns.IsEmpty())
401                 sColumns = m_sColumns;
402         InitListCtrl(sColumns);
403 }
404
405 void CIEShellListCtrl::SetColumnWidths()
406 {
407         if (!m_bCallBack)
408         {
409                 for(int i=0;i < GetColumnCount();i++)
410                         SetColumnWidth(i,LVSCW_AUTOSIZE);
411         }
412 }
413
414 void CIEShellListCtrl::Refresh()
415 {
416         if (m_psfSubFolder==NULL)
417                 return;
418         SetRefreshAllowed(false);
419         SetRedraw(FALSE);
420         int nCurSel = GetCurSel();
421         TRACE(_T("Refreshing shell list control\n"));
422         Load();
423         SetCurSel(nCurSel);
424         LONG Result;
425         OnSelChanged(nCurSel,&Result);
426         SetRedraw(TRUE);
427         SetRefreshAllowed(true);
428 }
429
430 void CIEShellListCtrl::Load()
431 {
432         CWaitCursor w;
433     if (!InitItems(&m_tvid,m_bCallBack))
434         return;
435 }
436
437 void CIEShellListCtrl::Init()
438 {
439         if (m_bInitiliazed)
440                 return;
441         CUIODListCtrl::Init();
442         InitShellSettings();
443         InitImageLists();
444         m_bInitiliazed = true;
445 }
446
447 BOOL CIEShellListCtrl::InitItems(LPTVITEMDATA lptvid, bool bCallBack)
448 {
449         CWaitCursor w;
450
451         Init();
452
453         ASSERT(m_psfSubFolder);
454         if (m_psfSubFolder == NULL)
455                 return FALSE;
456
457         // Try to initialize columns from shell
458         m_ShellDetails.SetShellDetails(NULL);
459         IShellFolder2 *pShellFolder2=NULL;
460         HRESULT hr=m_psfSubFolder->QueryInterface(IID_IShellFolder2,(LPVOID*)&pShellFolder2);
461         if (SUCCEEDED(hr))
462         {
463                 LPUNKNOWN pUnk=NULL;
464                 if (SUCCEEDED(pShellFolder2->QueryInterface(IID_IUnknown,(LPVOID*)&pUnk)))
465                 {
466                         m_ShellDetails.SetShellDetails(pUnk);
467                         pUnk->Release();
468                 }
469                 m_ShellDetails.SetShellDetails((LPUNKNOWN)pShellFolder2);
470                 pShellFolder2->Release();
471         }
472         else
473         {
474                 IShellDetails *pShellDetails=NULL;
475                 HRESULT hr = m_psfSubFolder->CreateViewObject(GetSafeHwnd(), IID_IShellDetails, (LPVOID*)&pShellDetails);
476                 if (SUCCEEDED(hr))
477                 {
478                         LPUNKNOWN pUnk=NULL;
479                         if (SUCCEEDED(pShellDetails->QueryInterface(IID_IUnknown,(LPVOID*)&pUnk)))
480                         {
481                                 m_ShellDetails.SetShellDetails(pUnk);
482                                 pUnk->Release();
483                         }
484                         pShellDetails->Release();
485                 }
486         }
487         InitColumns();
488                 
489         DWORD dwExStyle = GetExStyle(); 
490         if(!m_ShellSettings.DoubleClickInWebView()) 
491         {
492                 dwExStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT | LVS_EX_UNDERLINEHOT; 
493         }
494         else
495         {
496                 dwExStyle &= ~LVS_EX_ONECLICKACTIVATE;
497                 dwExStyle &= ~LVS_EX_TRACKSELECT;
498                 dwExStyle &= ~LVS_EX_UNDERLINEHOT; 
499         }
500         SetExStyle(dwExStyle);
501
502     LPITEMIDLIST lpi=NULL;
503     LPENUMIDLIST lpe=NULL;
504     LPLVITEMDATA lplvid=NULL;
505         LPSHELLFOLDER lpsf=m_psfSubFolder;
506     ULONG        ulFetched, ulAttrs;
507     HWND         hwnd=::GetParent(m_hWnd);
508         DWORD dwFlags = SHCONTF_NONFOLDERS;
509
510         if (GetShellSettings().ShowAllObjects() && !GetShellSettings().ShowSysFiles())
511                 dwFlags |= SHCONTF_INCLUDEHIDDEN;
512     hr=lpsf->EnumObjects(hwnd,dwFlags, &lpe);
513
514     if (FAILED(hr))
515                 return FALSE;
516
517         bool bEndPopulate=false;
518         if (m_bPopulateInit == false)
519         {
520                 StartPopulate();
521                 bEndPopulate = true;
522         }
523     while (NO_ERROR==lpe->Next(1, &lpi, &ulFetched))
524     {
525                 ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_DISPLAYATTRMASK | SFGAO_CONTENTSMASK | SFGAO_REMOVABLE; 
526         lpsf->GetAttributesOf(1, (LPCITEMIDLIST*)&lpi, &ulAttrs);
527                 if (!FilterItem(lpsf,lpi,ulAttrs))
528                 {
529                 m_pMalloc->Free(lpi);  // free PIDL the shell gave you
530                     lpi=NULL;
531                         continue;
532                 }
533         lplvid = (LPLVITEMDATA)m_pMalloc->Alloc(sizeof(LVITEMDATA));
534         if (!lplvid)
535            break;
536                 ZeroMemory(lplvid,sizeof(LVITEMDATA));
537                 m_vecItemData.push_back(lplvid);
538
539         lplvid->ulAttribs=ulAttrs;
540
541         lplvid->lpifq=m_ShellPidl.ConcatPidl(lptvid->lpifq, lpi);
542
543         lplvid->lpsfParent=lpsf;
544         lplvid->lpsfParent->AddRef();
545
546         // Now make a copy of the ITEMIDLIST.
547         lplvid->lpi=m_ShellPidl.CopyItemID(lpi);
548
549                 // Add the item to the list view control.   
550                 int nRow=-1;
551                 if (bCallBack)
552                 {
553                         nRow = AddCallBackItem((DWORD)lplvid,I_IMAGECALLBACK);                  
554                         if ((ulAttrs & SFGAO_COMPRESSED) && m_ShellSettings.ShowCompColor())
555                                 SetTextColor(nRow,0,RGB(0,0,255));
556                         else
557                                 SetDefaultTextColor(nRow,-1);
558                 }
559                 else
560                 {
561                         nRow = AddTextItem();
562                         if (nRow != -1)
563                         {
564                                 TCHAR szText[MAX_PATH+1];
565                                 SetItemData(nRow,(DWORD)lplvid);
566                                 LV_DISPINFO dsp;
567                                 ZeroMemory(&dsp,sizeof(LV_DISPINFO));
568                                 dsp.item.mask |= (LVIF_TEXT | LVIF_IMAGE);
569                                 for(int i=0; i < GetColumnCount();i++)
570                                 {
571                                         szText[0] = 0;
572                                         dsp.item.iItem = nRow;
573                                         dsp.item.iSubItem = i;
574                                         dsp.item.cchTextMax = MAX_PATH;
575                                         dsp.item.pszText = szText;
576                                         if (i > 0)
577                                                 dsp.item.mask &= ~LVIF_IMAGE;
578                                         m_bCallBack = true;
579                                         GetDispInfo(&dsp);
580                                         m_bCallBack = false;
581                                         SetIcon(nRow,dsp.item.iImage);
582                                         AddString(nRow,i,szText);
583                                 }
584                         }
585                 }
586         m_pMalloc->Free(lpi);  // free PIDL the shell gave you
587         lpi=NULL;
588     }
589
590     if (lpe)  
591         lpe->Release();
592
593     // The following two if statements will be TRUE only if you got here
594     // on an error condition from the goto statement.  Otherwise, free 
595     // this memory at the end of the while loop above.
596     if (lpi)           
597         m_pMalloc->Free(lpi);
598  
599         if (bEndPopulate)
600                 EndPopulate();
601     return TRUE;
602 }
603
604 bool CIEShellListCtrl::FilterItem(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl,UINT ulAttrs)
605 {
606         if ((m_sFileFilter.IsEmpty() || m_sFileFilter == _T("*.*") || m_sFileFilter == _T("*"))
607                 && m_ExcludedLookup.IsEmpty())
608                 return true;
609         bool bRet=false;
610         if (m_sFileFilter == _T("*.*") || m_sFileFilter == _T("*"))
611         {
612                 bRet=true;
613         }
614         else if (!m_sFileFilter.IsEmpty())
615         {
616                 CString sPath;
617                 GetShellPidl().SHPidlToPathEx(pidl,sPath,pFolder);
618                 if (m_FilterLookup.Find(sPath))
619                         bRet = true;
620         }
621         if (bRet == false)
622                 return bRet;
623         if (!m_ExcludedLookup.IsEmpty())
624         {
625                 SHFILEINFO fileInfo;
626                 ZeroMemory(&fileInfo,sizeof(fileInfo));
627                 SHGetFileInfo((LPCTSTR)pidl, NULL, &fileInfo, sizeof(fileInfo), SHGFI_PIDL|SHGFI_TYPENAME);
628                 if (m_ExcludedLookup.Find(fileInfo.szTypeName))
629                 {
630                         bRet = false;
631                 }
632         }
633         return bRet;
634 }
635
636 void CIEShellListCtrl::InitShellSettings()
637 {
638         m_ShellSettings.GetSettings();
639 }  
640
641 BOOL CIEShellListCtrl::InitImageLists()
642 {
643     HIMAGELIST himlSmall;
644     HIMAGELIST himlLarge;
645     SHFILEINFO sfi;
646     BOOL       bSuccess=TRUE;
647
648     himlSmall = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T("C:\\"), 
649                                            0,
650                                            &sfi, 
651                                            sizeof(SHFILEINFO), 
652                                            SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
653
654     himlLarge = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T("C:\\"), 
655                                            0,
656                                            &sfi, 
657                                            sizeof(SHFILEINFO), 
658                                            SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
659
660     if (himlSmall && himlLarge)
661     {
662         ::SendMessage(GetSafeHwnd(), LVM_SETIMAGELIST, (WPARAM)LVSIL_SMALL,
663             (LPARAM)himlSmall);
664         ::SendMessage(GetSafeHwnd(), LVM_SETIMAGELIST, (WPARAM)LVSIL_NORMAL,
665             (LPARAM)himlLarge);
666     }
667     else
668        bSuccess = FALSE;
669
670     return bSuccess;
671 }
672
673 BEGIN_MESSAGE_MAP(CIEShellListCtrl, CUIODListCtrl)
674         //{{AFX_MSG_MAP(CIEShellListCtrl)
675         ON_MESSAGE(WM_SETMESSAGESTRING,OnSetmessagestring)
676         ON_MESSAGE(WM_SETTINGCHANGE,OnSettingChange)
677         // NOTE - the ClassWizard will add and remove mapping macros here.
678         ON_WM_DESTROY()
679         ON_WM_MENUSELECT()
680         //}}AFX_MSG_MAP
681         ON_MESSAGE(WM_APP_ON_DELETE_KEY,OnAppDeleteKey)
682         ON_MESSAGE(WM_APP_ON_PROPERTIES_KEY,OnAppPropertiesKey)
683         ON_MESSAGE(WM_APP_UPDATE_ALL_VIEWS,OnAppUpdateAllViews)
684         ON_MESSAGE(WM_APP_FILE_CHANGE_NEW_PATH,OnAppFileChangeNewPath)
685         ON_MESSAGE(WM_APP_FILE_CHANGE_EVENT,OnAppFileChangeEvent)
686 END_MESSAGE_MAP()
687
688 /////////////////////////////////////////////////////////////////////////////
689 // CIEShellListCtrl message handlers
690 void CIEShellListCtrl::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
691 {
692         CUIODListCtrl::OnMenuSelect(nItemID,nFlags,hSysMenu);
693 }
694
695 void CIEShellListCtrl::ShowPopupMenu(int nRow,int nCol,CPoint point)    
696 {
697         if ((nCol > 0 || nRow == -1) || (m_PopupID || m_MultiPopupID))
698         {
699                 CUIODListCtrl::ShowPopupMenu(nRow,nCol,point);
700                 return;
701         }
702         PopupTheMenu(nRow,point);
703 }
704
705 void CIEShellListCtrl::OnDestroy()
706 {
707         SetImageList(NULL,LVSIL_SMALL);
708         SetImageList(NULL,LVSIL_NORMAL);
709         DestroyThreads();
710         CUIODListCtrl::OnDestroy();
711 }
712
713 bool CIEShellListCtrl::UseShellColumns()
714 {
715         return m_ShellDetails.IsValidDetails();
716 }
717
718 BOOL CIEShellListCtrl::GetDispInfo(LV_DISPINFO *pDispInfo)
719 {
720         // TODO: Add your specialized code here and/or call the base class
721         if (m_psfSubFolder == NULL || m_bCallBack == false)
722                 return CUIODListCtrl::GetDispInfo(pDispInfo);
723         LPLVITEMDATA lplvid = (LPLVITEMDATA)GetItemData(pDispInfo->item.iItem);
724         ASSERT(lplvid);
725         if (lplvid == NULL)
726                 return FALSE;
727         PSLC_COLUMN_DATA pColData=(PSLC_COLUMN_DATA)lplvid->lParam;
728         if (pColData == NULL)
729         {
730                 pColData = new SLC_COLUMN_DATA;
731                 pColData->sItems.SetSize(GetColumnCount());
732                 lplvid->lParam = (LPARAM)pColData;
733         }
734         if (pColData->pidl == NULL)
735                 pColData->pidl = m_ShellPidl.ConcatPidl(m_tvid.lpifq, lplvid->lpi);
736         if (pDispInfo->item.mask & LVIF_IMAGE)
737         {
738                 if (pColData->iImage == -1)
739                 {
740                         pColData->iImage = m_ShellPidl.GetIcon(pColData->pidl,SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
741                 }       
742                 pDispInfo->item.iImage = pColData->iImage;
743                 if (lplvid->ulAttribs & SFGAO_GHOSTED)
744                 {
745                         pDispInfo->item.mask |= LVIF_STATE;
746                         pDispInfo->item.stateMask = LVIS_CUT;
747                         pDispInfo->item.state = LVIS_CUT;
748                 }
749                 if (lplvid->ulAttribs & SFGAO_LINK)
750                 {
751                         pDispInfo->item.mask |= LVIF_STATE;
752                         pDispInfo->item.stateMask = LVIS_OVERLAYMASK;
753                         pDispInfo->item.state = INDEXTOOVERLAYMASK(2);
754                 }
755                 if (lplvid->ulAttribs & SFGAO_SHARE)
756                 {
757                         pDispInfo->item.mask |= LVIF_STATE;
758                         pDispInfo->item.stateMask = LVIS_OVERLAYMASK;
759                         pDispInfo->item.state = INDEXTOOVERLAYMASK(1);
760                 }
761         }
762         if (pDispInfo->item.mask & LVIF_TEXT)
763         {
764                 if (UseShellColumns())
765                 {
766                         if (pDispInfo->item.iSubItem == COL_NAME)
767                         {
768                                 if (pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
769                                         m_ShellPidl.GetName(lplvid->lpsfParent, lplvid->lpi, SHGDN_NORMAL, pColData->sItems[pDispInfo->item.iSubItem]);
770                                 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
771                                 if (m_bNoExt)
772                                         RemoveExt(pDispInfo->item.pszText);
773                         }
774                         else
775                         {
776                                 if (pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
777                                 {
778                                         SHELLDETAILS sd;
779                                         ZeroMemory(&sd,sizeof(sd));
780                                         HRESULT hr = m_ShellDetails.GetDetailsOf(lplvid->lpi,pDispInfo->item.iSubItem,&sd);
781                                         LPTSTR pszText=NULL;
782                                         GetShellPidl().StrRetToStr(sd.str,&pszText,lplvid->lpi);
783                                         if (pszText)
784                                         {
785                                                 _tcscpy(pDispInfo->item.pszText,pszText);
786                                                 GetShellPidl().Free(pszText);
787                                         }
788                                 }
789                                 else
790                                 {
791                                         _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
792                                 }
793                         }
794                 }
795                 else
796                 {
797                         GetText(pColData,pDispInfo,lplvid);
798                 }
799         }
800         return TRUE;
801 }
802
803 bool CIEShellListCtrl::GetColText(int nCol,LPCITEMIDLIST pidlAbs,LPLVITEMDATA lplvid,CString &sText)
804 {
805         return false;
806 }
807
808 void CIEShellListCtrl::GetText(PSLC_COLUMN_DATA pColData,LV_DISPINFO *pDispInfo,LPLVITEMDATA lplvid)
809 {
810         if (!pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
811         {
812                 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
813                 return;
814         }
815         LPITEMIDLIST pidlAbs = pColData->pidl;
816         CString sText;
817         if (GetColText(pDispInfo->item.iSubItem,pidlAbs,lplvid,sText))
818         {
819                 pColData->sItems[pDispInfo->item.iSubItem] = sText;
820                 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
821                 return;
822         }
823         if (pDispInfo->item.iSubItem == COL_NAME)
824         {
825                 if (pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
826                         m_ShellPidl.GetName(lplvid->lpsfParent, lplvid->lpi, SHGDN_NORMAL,pColData->sItems[pDispInfo->item.iSubItem]);
827                 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
828                 if (m_bNoExt)
829                         RemoveExt(pDispInfo->item.pszText);
830         }
831         else if (pDispInfo->item.iSubItem == COL_TYPE)
832         {
833                 if (pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
834                 {
835                         SHFILEINFO fileInfo;
836                         if (SHGetFileInfo((LPCTSTR)lplvid->lpi, NULL, &fileInfo, sizeof(fileInfo), SHGFI_PIDL|SHGFI_TYPENAME))
837                         {
838                                 pColData->sItems[pDispInfo->item.iSubItem] = fileInfo.szTypeName;
839                         }
840                 }
841                 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
842         }
843         else if (pDispInfo->item.iSubItem == COL_SIZE || pDispInfo->item.iSubItem == COL_MODIFIED)
844         {
845                 if (pColData->sItems[COL_SIZE].IsEmpty() || (pColData->sItems[COL_MODIFIED].IsEmpty()))
846                 {
847                         CString sSize;
848                         CString sDateTime;
849                         GetFileDetails(pidlAbs,sSize,sDateTime);
850                         if (pDispInfo->item.iSubItem == COL_SIZE)
851                                 pColData->sItems[pDispInfo->item.iSubItem] = sSize;
852                         else if (pDispInfo->item.iSubItem == COL_MODIFIED)
853                                 pColData->sItems[pDispInfo->item.iSubItem] = sDateTime;
854                 }
855                 if (pDispInfo->item.iSubItem == COL_SIZE)
856                         _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
857                 else if (pDispInfo->item.iSubItem == COL_MODIFIED)
858                         _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
859         }
860 }
861
862 void CIEShellListCtrl::GetFileDetails(LPCITEMIDLIST pidl, CString &sSize, CString &sDateTime)
863 {
864         CString sPath;
865         GetShellPidl().SHPidlToPathEx((LPITEMIDLIST)pidl,sPath,NULL);
866         if (sPath.GetLength() <= 3)
867                 return;
868         WIN32_FIND_DATA FindFileData;
869     HANDLE hFind = FindFirstFile(sPath,&FindFileData);
870     if (hFind != INVALID_HANDLE_VALUE)
871         {
872                 if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
873                 {
874                         unsigned __int64 fs = UMAKEINT64(FindFileData.nFileSizeLow, FindFileData.nFileSizeHigh);
875                         unsigned __int64 kb=1;
876                         TCHAR szText[1024];
877                         if (fs > 1024)
878                         {
879                                 kb = fs / 1024;
880                                 if (fs % 1024)
881                                         kb++;
882                         }
883                         _ui64tot(kb,szText,10);
884                         sSize = szText;
885                         AddThousandSeps(sSize);
886                         sSize += _T(" KB");
887                 }
888                 if ((FindFileData.ftLastWriteTime.dwLowDateTime != 0) || (FindFileData.ftLastWriteTime.dwHighDateTime != 0))
889                 {
890                         sDateTime = CLocaleInfo::Instance()->FormatDateTime(FindFileData.ftLastWriteTime);
891                 }
892                 else
893                 {
894                         sDateTime = CLocaleInfo::Instance()->FormatDateTime(FindFileData.ftCreationTime);
895                 }
896             FindClose(hFind);
897         }
898 }
899
900 void CIEShellListCtrl::RemoveExt(LPTSTR pszFileName)
901 {
902         if (pszFileName == NULL)
903                 return;
904         LPTSTR pExtPos=NULL;
905         LPTSTR pEndPos = pszFileName+lstrlen(pszFileName);
906         LPTSTR pStartPos = pszFileName;
907         while (pEndPos > pStartPos)
908         {
909                 if (*pEndPos == '.')
910                 {
911                         pExtPos = pEndPos;
912                         break;
913                 }
914                 pEndPos = _tcsdec(pStartPos,pEndPos);
915         }
916         if (pExtPos)
917                 *pExtPos = '\0';
918 }
919
920 int CALLBACK ShellCompareFunc(LPARAM lparam1, 
921                                  LPARAM lparam2,
922                                  LPARAM lparamSort);
923
924 PFNLVCOMPARE CIEShellListCtrl::GetCompareFunc()
925 {
926         if (m_bCallBack)
927                 return ShellCompareFunc;
928         return CUIODListCtrl::GetCompareFunc();
929 }
930
931 int CALLBACK ShellCompareFunc(LPARAM lParam1, 
932                          LPARAM lParam2,
933                          LPARAM lParamSort)
934 {
935         CUIListCtrlData *pData1 = (CUIListCtrlData*)lParam1;
936         CUIListCtrlData *pData2 = (CUIListCtrlData*)lParam2;
937     LPLVITEMDATA lplvid1=(LPLVITEMDATA)pData1->GetExtData();
938     LPLVITEMDATA lplvid2=(LPLVITEMDATA)pData2->GetExtData();
939         CUIODListCtrlSortInfo *pSortInfo = (CUIODListCtrlSortInfo*)lParamSort;
940         int nRet=0;
941         HRESULT hr = lplvid1->lpsfParent->CompareIDs(pSortInfo->GetColumn(),lplvid1->lpi,lplvid2->lpi);
942     if (SUCCEEDED(hr))
943                 nRet = (short)hr;
944         if (!pSortInfo->Ascending())
945                 nRet = -nRet;
946         return nRet;
947 }
948
949 /////////////////////////////////////////////////////////////////////////
950 // Thread function for detecting file system changes
951 UINT CIEShellListCtrl::ThreadFunc (LPVOID pParam)
952 {
953         ///////////////////////
954     PFC_THREADINFO pThreadInfo = (PFC_THREADINFO)pParam;
955     HANDLE hEvent = pThreadInfo->hEvent;
956     HANDLE hMonitorEvent = pThreadInfo->hMonitorEvent;
957         CIEShellListCtrl *pListCtrl = pThreadInfo->pListCtrl;
958     HWND hWnd = pListCtrl->GetSafeHwnd();
959     delete pThreadInfo;
960         ////////////////////////
961         TCHAR szPath[MAX_PATH];
962     int nHandles=2;
963         int nRet=0;
964         HANDLE hFileChange=NULL;
965     HANDLE aHandles[3];
966         aHandles[0] = hMonitorEvent;
967     aHandles[1] = hEvent;
968         aHandles[2] = NULL;
969     BOOL bContinue = TRUE;
970     // Sleep until a file change notification wakes this thread or
971     // m_event becomes set indicating it's time for the thread to end.
972     while (bContinue)
973         {
974                 TRACE(_T("ListControl waiting for %u multiple objects\n"),nHandles);
975         DWORD dw = ::WaitForMultipleObjects (nHandles, aHandles, FALSE, INFINITE);
976                 if (dw >= WAIT_ABANDONED && dw <= (WAIT_ABANDONED+(nHandles-1)))
977                 {
978                         TRACE(_T("ListControl waiting abandoned\n"),nHandles);
979                         break;
980                 }
981                 // Reset Event
982         if(dw - WAIT_OBJECT_0 == 0) 
983                 {
984                         if (hFileChange && hFileChange != INVALID_HANDLE_VALUE)
985                                 ::FindCloseChangeNotification(hFileChange);
986                         if (::SendMessage(hWnd, WM_APP_FILE_CHANGE_NEW_PATH, (WPARAM)szPath, 0))
987                         {
988                                 if (szPath[0] == 0)
989                                 {
990                                         TRACE(_T("File notify path was returned empty\n"));
991                                         hFileChange = NULL;
992                                         aHandles[2] = hFileChange;                              
993                                         continue;
994                                 }
995                                 TRACE(_T("File notify path returned %s\n"),szPath);
996                             hFileChange = ::FindFirstChangeNotification (szPath, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
997                             if (hFileChange == INVALID_HANDLE_VALUE)
998                                 {
999                                         TRACE(_T("File notify thread was unable to create notification object\n"));
1000                                         hFileChange = NULL;
1001                                         aHandles[2] = hFileChange;                              
1002                                         continue;
1003                                 }
1004                                 else
1005                                 {
1006                                         if (nHandles == 2)
1007                                         {
1008                                                 TRACE(_T("File notify thread has created the notification object for the first time\n"));
1009                                                 nHandles++;
1010                                         }
1011                                         TRACE(_T("File notify thread has created the notification object\n"));
1012                                         aHandles[2] = hFileChange;                              
1013                                 }
1014                         }
1015                 }
1016                 // End Event
1017         else if(dw - WAIT_OBJECT_0 == 1) 
1018                 {
1019             bContinue = FALSE;
1020                         TRACE(_T("File Notify Thread was signalled to stop\n"));
1021                 }
1022                 // File Change Event
1023         else if (dw - WAIT_OBJECT_0 == 2) 
1024                 { // Respond to a change notification.
1025             ::FindNextChangeNotification (hFileChange);
1026                         TRACE(_T("-- File notify event was fired in CIEShellListCtrl --\n"));
1027                         if (pListCtrl->RefreshAllowed())
1028                         {
1029                                 ::PostMessage (hWnd, WM_APP_FILE_CHANGE_EVENT,0,0);
1030                         }
1031                         else
1032                         {
1033                                 TRACE(_T("but not sending as refreshing\n"));
1034                                 pListCtrl->SetRefreshAllowed(true);
1035                                 TRACE(_T("Refresh is now allowed\n"));
1036                         }
1037         }
1038     }
1039         if (hFileChange && hFileChange != INVALID_HANDLE_VALUE)
1040                 ::FindCloseChangeNotification (hFileChange);
1041         TRACE(_T("File Notify Thread is ending\n"));
1042     return nRet;
1043 }
1044
1045 LRESULT CIEShellListCtrl::OnAppFileChangeNewPath(WPARAM wParam, LPARAM lParam)
1046 {
1047         ASSERT(wParam);
1048         SHGetPathFromIDList(m_tvid.lpifq,(LPTSTR)wParam);
1049         return 1;
1050 }
1051
1052 LRESULT CIEShellListCtrl::OnAppFileChangeEvent(WPARAM wParam, LPARAM lParam)
1053 {
1054         if (!RefreshAllowed())
1055                 return 1L;
1056         Refresh();
1057         if (m_bNotifyParent)
1058                 GetParent()->SendMessage(WM_APP_UPDATE_ALL_VIEWS,(WPARAM)HINT_SHELL_FILE_CHANGED,(LPARAM)(LPCTSTR)m_sMonitorPath);
1059         return 1L;
1060 }
1061
1062 void CIEShellListCtrl::PreSubclassWindow()
1063 {
1064         CUIODListCtrl::PreSubclassWindow();
1065         CreateFileChangeThread(GetSafeHwnd());
1066 }
1067
1068 void CIEShellListCtrl::CreateFileChangeThread(HWND hwnd)
1069 {
1070         if (m_nThreadCount >= MAX_THREADS)
1071                 return;
1072     PFC_THREADINFO pThreadInfo = new FC_THREADINFO; // Thread will delete
1073     pThreadInfo->hMonitorEvent = m_MonitorEvent[m_nThreadCount].m_hObject;
1074     pThreadInfo->hEvent = m_event[m_nThreadCount].m_hObject;
1075     pThreadInfo->pListCtrl = this;
1076
1077     CWinThread* pThread = AfxBeginThread (ThreadFunc, pThreadInfo,
1078         THREAD_PRIORITY_IDLE);
1079
1080     pThread->m_bAutoDelete = FALSE;
1081     m_hThreads[m_nThreadCount] = pThread->m_hThread;
1082     m_pThreads[m_nThreadCount++] = pThread;
1083 }
1084
1085 bool CIEShellListCtrl::DragDrop(CDD_OleDropTargetInfo *pInfo)
1086 {
1087         // TODO: Add your specialized code here and/or call the base class
1088         return m_ShellDragDrop.DragDrop(pInfo,m_tvid.lpsfParent,m_tvid.lpi);
1089 }
1090
1091 bool CIEShellListCtrl::DragEnter(CDD_OleDropTargetInfo *pInfo)
1092 {
1093         // TODO: Add your specialized code here and/or call the base class
1094         return m_ShellDragDrop.DragEnter(pInfo,m_tvid.lpsfParent,m_tvid.lpi);
1095 }
1096
1097 bool CIEShellListCtrl::DragLeave(CDD_OleDropTargetInfo *pInfo)
1098 {
1099         // TODO: Add your specialized code here and/or call the base class
1100         return m_ShellDragDrop.DragLeave(pInfo);
1101 }
1102
1103 bool CIEShellListCtrl::DragOver(CDD_OleDropTargetInfo *pInfo)
1104 {
1105         // TODO: Add your specialized code here and/or call the base class
1106         return m_ShellDragDrop.DragOver(pInfo,m_tvid.lpsfParent,m_tvid.lpi);
1107 }
1108
1109 // When the use starts a drag drop source
1110 DROPEFFECT CIEShellListCtrl::DoDragDrop(int *pnRows,COleDataSource *pOleDataSource)
1111 {
1112         CShellPidl pidl;
1113         CCF_ShellIDList sl;
1114         CCF_HDROP cf_hdrop;
1115         CCF_String cf_text;
1116         cf_hdrop.AddDropPoint(CPoint(),FALSE);
1117         CString sPath;
1118         CString sText;
1119         LPLVITEMDATA plvid=NULL;
1120         if (GetShellPidl().IsDesktopFolder(m_psfSubFolder))
1121                 sl.AddPidl(GetShellPidl().GetEmptyPidl());
1122         else
1123                 sl.AddPidl(m_tvid.lpifq);
1124         for(int i=0;*pnRows != -1;i++)
1125         {
1126                 plvid = (LPLVITEMDATA)GetItemData(*pnRows);
1127                 ASSERT(plvid);
1128                 sl.AddPidl(plvid->lpi);
1129                 pidl.SHPidlToPathEx(plvid->lpi,sPath,plvid->lpsfParent);
1130                 cf_hdrop.AddFileName(sPath);
1131                 sText += sPath;
1132                 sText += _T("\n");
1133                 pnRows++;
1134         }
1135         cf_text.SetString(sText);
1136         if (i > 0)
1137         {
1138                 CWDClipboardData::Instance()->SetData(pOleDataSource,&cf_text,CWDClipboardData::e_cfString);
1139                 CWDClipboardData::Instance()->SetData(pOleDataSource,&sl,CWDClipboardData::e_cfShellIDList);
1140                 CWDClipboardData::Instance()->SetData(pOleDataSource,&cf_hdrop,CWDClipboardData::e_cfHDROP);
1141         }
1142         return GetShellPidl().GetDragDropAttributes(plvid);
1143 }
1144
1145
1146 LRESULT CIEShellListCtrl::OnAppUpdateAllViews(WPARAM wParam, LPARAM lParam)
1147 {
1148         if (wParam == HINT_TREE_SEL_CHANGED)
1149         {
1150                 ASSERT(lParam);
1151                 const CRefreshShellFolder *pRefresh = reinterpret_cast<CRefreshShellFolder*>(lParam);
1152                 if (pRefresh)
1153                 {
1154                         LPTVITEMDATA lptvid = reinterpret_cast<LPTVITEMDATA>(pRefresh->GetItemData());
1155                         ASSERT(lptvid);
1156                         if (lptvid == NULL)
1157                                 return 1L;
1158                         bool bInternet=GetShellPidl().ComparePidls(NULL,lptvid->lpifq,m_pidlInternet);
1159                         if (GetParent())
1160                                 GetParent()->SendMessage(WM_APP_UPDATE_ALL_VIEWS,HINT_TREE_INTERNET_FOLDER_SELECTED,(LPARAM)(bInternet ? 1 : 0));
1161                         if (bInternet == false)
1162                                 Populate(lptvid);
1163                 }
1164         }       
1165         return 1L;
1166 }
1167
1168 LRESULT CIEShellListCtrl::OnSettingChange(WPARAM wParam,LPARAM lParam)
1169
1170         InitShellSettings();
1171         Refresh();
1172         LPCTSTR lpszSection=(LPCTSTR)lParam;
1173         TRACE1("OnSettingsChange in CIEShellListCtrl with %s\n",lpszSection ? lpszSection : _T("null"));
1174         return 1L; 
1175 }  
1176
1177 BOOL CIEShellListCtrl::DoubleClick(NM_LISTVIEW* pNMListView)
1178 {
1179         // TODO: Add your specialized code here and/or call the base class
1180         if (m_ShellSettings.DoubleClickInWebView())
1181         {
1182                 ShellExecute(pNMListView->iItem);
1183                 return TRUE;
1184         }
1185         return CUIODListCtrl::DoubleClick(pNMListView);
1186 }
1187
1188 BOOL CIEShellListCtrl::OnEnter(NM_LISTVIEW* pNMListView)
1189 {
1190         // TODO: Add your specialized code here and/or call the base class
1191         ShellExecute(pNMListView->iItem);
1192         return TRUE;
1193 }
1194
1195 LRESULT CIEShellListCtrl::OnAppDeleteKey(WPARAM wParam, LPARAM lParam)
1196 {
1197         // TODO: Add your specialized code here and/or call the base class
1198         UINT nSize = GetSelectedCount()*MAX_PATH;
1199         if (nSize == 0)
1200                 return 0L;
1201         SetRefreshAllowed(false);
1202         SHFILEOPSTRUCT shf;
1203         ZeroMemory(&shf,sizeof(shf));
1204         LPTSTR pszFrom=new TCHAR[nSize];
1205         LPTSTR pszStartFrom=pszFrom;
1206         ZeroMemory(pszFrom,nSize*sizeof(TCHAR));
1207         CString sPath;
1208         int item=-1;
1209         while ((item = GetNextSel(item)) != -1)
1210         {
1211                 sPath = GetPathName(item);
1212                 lstrcpy(pszFrom,(LPCTSTR)sPath);
1213                 pszFrom += sPath.GetLength()+1;
1214         }
1215         shf.hwnd = GetSafeHwnd();
1216         shf.wFunc = FO_DELETE;
1217         shf.pFrom = (LPCTSTR)pszStartFrom;
1218         shf.fFlags = GetKeyState(VK_SHIFT) < 0 ? 0 : FOF_ALLOWUNDO;
1219         if (SHFileOperation(&shf) != 0)
1220                 SetRefreshAllowed(true);
1221         delete []pszStartFrom;
1222         return 1L;
1223 }
1224
1225 LRESULT CIEShellListCtrl::OnAppPropertiesKey(WPARAM wParam, LPARAM lParam)
1226 {
1227         // TODO: Add your specialized code here and/or call the base class
1228         if (GetSelectedCount() == 0)
1229                 return 0L;
1230         SHELLEXECUTEINFO si;
1231         ZeroMemory(&si,sizeof(si));
1232         si.cbSize = sizeof(si);
1233         si.hwnd = GetSafeHwnd();
1234         si.nShow = SW_SHOW;
1235         si.fMask  = SEE_MASK_INVOKEIDLIST;
1236         si.lpVerb = _T("properties");
1237         int item=GetCurSel();
1238         while ((item = GetNextSel(item)) != -1)
1239         {
1240                 CString sPath(GetPathName(item));
1241                 si.lpFile = (LPCTSTR)sPath;
1242                 ShellExecuteEx(&si);
1243         }
1244         return 1L;
1245 }
1246
1247 bool CIEShellListCtrl::EndLabelEdit(int nRow,int nCol,LPCTSTR pszText)
1248 {
1249         // TODO: Add your specialized code here and/or call the base class
1250         if (nCol != 0)
1251                 return CUIODListCtrl::EndLabelEdit(nRow,nCol,pszText);
1252         CString sFromPath(GetPathName(nRow));
1253         CString sToPath;
1254         CSplitPath path(sFromPath);
1255         if (GetShellSettings().ShowExtensions())
1256         {
1257                 CSplitPath file(pszText);
1258                 path.SetFileName(file.GetFileName());
1259                 path.SetExt(file.GetExt());
1260         }
1261         else
1262         {
1263                 path.SetFileName(pszText);
1264         }
1265         path.Make();
1266         sToPath = path.GetPath();
1267         SHFILEOPSTRUCT shf;
1268         TCHAR szFrom[MAX_PATH+1];
1269         TCHAR szTo[MAX_PATH+1];
1270         ZeroMemory(szFrom,sizeof(szFrom));
1271         lstrcpy(szFrom,sFromPath);
1272         ZeroMemory(szTo,sizeof(szTo));
1273         lstrcpy(szTo,sToPath);
1274         ZeroMemory(&shf,sizeof(shf));
1275         shf.hwnd = GetSafeHwnd();
1276         shf.wFunc = FO_RENAME;
1277         shf.pFrom = szFrom;
1278         shf.pTo = szTo;
1279 #ifdef _DEBUG
1280         CString sMess;
1281         sMess = szFrom;
1282         sMess += _T("\n");
1283         sMess += szTo;
1284         AfxMessageBox(sMess);
1285 #endif
1286         int nRet = SHFileOperation(&shf);
1287         TRACE1("SHFileOperation returned %u\n",nRet);
1288         return false;
1289 }
1290
1291 void CIEShellListCtrl::GoBack(int nRow)
1292 {
1293         // TODO: Add your specialized code here and/or call the base class
1294         AfxMessageBox(_T("Needs to be implemented"));
1295 }
1296
1297 void CIEShellListCtrl::ChangeStyle(UINT &dwStyle)
1298 {
1299         // TODO: Add your specialized code here and/or call the base class
1300         CUIODListCtrl::ChangeStyle(dwStyle);
1301
1302         dwStyle |= (LVS_SHAREIMAGELISTS | LVS_EDITLABELS);  
1303 }
1304
1305 LRESULT CIEShellListCtrl::OnSetmessagestring(WPARAM wParam, LPARAM lParam)
1306 {
1307         if (GetParent())
1308                 return GetParent()->SendMessage(WM_SETMESSAGESTRING,wParam,lParam);
1309         return 0;
1310 }