update for HEAD-2003091401
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / IEShellTreeCtrl.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 // IEShellTreeCtrl.cpp : implementation file
19 #include "stdafx.h"
20 #include "IEShellTreeCtrl.h"
21 #include "cbformats.h"
22 #include "UIMessages.h"
23 #include "dirwalk.h"
24
25 #ifdef _DEBUG
26 #define new DEBUG_NEW
27 #undef THIS_FILE
28 static char THIS_FILE[] = __FILE__;
29 #endif
30
31 /////////////////////////////////////////////////////////////////////////////
32 // CIEShellTreeCtrl
33
34 CIEShellTreeCtrl::CIEShellTreeCtrl()
35 {
36         m_lptvid = NULL;
37         m_hListWnd = NULL;
38         m_hComboWnd = NULL;
39         m_nThreadCount = 0;
40         m_bRefreshAllowed = true;
41         m_bNotifyParent = false;
42         // Turn off WM_DROPFILES
43         SetDropFiles(false);
44 }
45
46 CIEShellTreeCtrl::~CIEShellTreeCtrl()
47 {
48 }
49
50 void CIEShellTreeCtrl::ShellExecute(HTREEITEM hItem,LPCTSTR pszVerb)
51 {
52         SHELLEXECUTEINFO si;
53         ZeroMemory(&si,sizeof(si));
54         si.cbSize = sizeof(si);
55         si.hwnd = GetSafeHwnd();
56         si.nShow = SW_SHOW;
57         si.lpIDList = (LPVOID)GetPathPidl(hItem);
58         si.fMask  = SEE_MASK_INVOKEIDLIST;
59         if (pszVerb)
60                 si.lpVerb = pszVerb;
61         ShellExecuteEx(&si);
62 }
63
64 void CIEShellTreeCtrl::RefreshComboBox(LPTVITEMDATA lptvid)
65 {
66         if (m_hComboWnd)
67         {
68                 ::PostMessage(m_hComboWnd,WM_APP_CB_IE_POPULATE,(WPARAM)lptvid->lpifq,0);
69         }
70 }
71
72 void CIEShellTreeCtrl::SetNotificationObject(bool bNotify)
73 {
74         if (bNotify)
75                 CreateFileChangeThreads(GetSafeHwnd());
76         else
77                 DestroyThreads();
78 }
79
80 void CIEShellTreeCtrl::UpOneLevel(HTREEITEM hItem)
81 {
82         if (hItem == NULL)
83         {
84                 hItem = GetSelectedItem();
85         }
86         if (hItem == NULL)
87                 return;
88         HTREEITEM hParentItem = GetParentItem(hItem);
89         if (hParentItem)
90                 Select(hParentItem,TVGN_CARET);
91 }
92
93 void CIEShellTreeCtrl::DestroyThreads()
94 {
95     if (m_nThreadCount == 0) 
96                 return;
97     for (UINT i=0;i < m_nThreadCount; i++)
98             m_event[i].SetEvent();
99     ::WaitForMultipleObjects (m_nThreadCount, m_hThreads, TRUE, INFINITE);
100     for (i=0; i < m_nThreadCount; i++)
101         delete m_pThreads[i];
102     m_nThreadCount = 0;
103 }
104
105 void CIEShellTreeCtrl::CreateFileChangeThreads(HWND hwnd)
106 {
107         if (m_nThreadCount)
108                 return;
109         TCHAR szDrives[MAX_PATH];
110         DWORD dwSize = sizeof(szDrives)/sizeof(TCHAR);
111         DWORD dwChars = GetLogicalDriveStrings(dwSize,szDrives);
112         if (dwChars == 0 || dwChars > dwSize) 
113         {
114                 TRACE(_T("Warning: CreateFileChangeThreads failed in GetLogicalDriveStrings\n"));
115                 return;
116         }
117         UINT nType;
118         CString sDrive;
119         LPCTSTR pszDrives=szDrives;
120         while (*pszDrives != '\0')
121         {
122                 sDrive = pszDrives;
123                 nType = ::GetDriveType(sDrive);
124                 if (nType == DRIVE_FIXED || nType == DRIVE_REMOTE || nType == DRIVE_RAMDISK)
125                 {
126                         CreateFileChangeThread(sDrive,hwnd);
127                 }
128 #if 1 // bugfix by mad79
129                 pszDrives=pszDrives+sDrive.GetLength()+1;
130 #else
131                 pszDrives = _tcsninc(pszDrives,sDrive.GetLength()+1);
132 #endif
133         }
134 }
135
136 void CIEShellTreeCtrl::CreateFileChangeThread(const CString& sPath,HWND hwnd)
137 {
138         if (m_nThreadCount >= MAX_THREADS)
139                 return;
140     PDC_THREADINFO pThreadInfo = new DC_THREADINFO; // Thread will delete
141     pThreadInfo->sPath = sPath;
142     pThreadInfo->hEvent = m_event[m_nThreadCount].m_hObject;
143     pThreadInfo->pTreeCtrl = this;
144
145     CWinThread* pThread = AfxBeginThread (ThreadFunc, pThreadInfo,
146         THREAD_PRIORITY_IDLE);
147
148     pThread->m_bAutoDelete = FALSE;
149     m_hThreads[m_nThreadCount] = pThread->m_hThread;
150     m_pThreads[m_nThreadCount++] = pThread;
151 }
152
153 HTREEITEM CIEShellTreeCtrl::SearchSiblings(HTREEITEM hItem,LPITEMIDLIST pidlAbs)
154 {
155         LPTVITEMDATA pItem = NULL;
156         HTREEITEM hChildItem = GetChildItem(hItem);
157         HTREEITEM hFoundItem;
158         while (hChildItem) 
159         {
160                         pItem = (LPTVITEMDATA)GetItemData(hChildItem);
161                         if (GetShellPidl().ComparePidls(NULL,pItem->lpifq,pidlAbs))
162                            break;
163                         hFoundItem = SearchSiblings(hChildItem,pidlAbs);
164                         if (hFoundItem)
165                                 return hFoundItem;
166                         hChildItem = GetNextSiblingItem(hChildItem);
167         }
168         return hChildItem;
169 }
170
171 HTREEITEM CIEShellTreeCtrl::ExpandMyComputer(LPITEMIDLIST pidlAbs)
172 {
173         HTREEITEM hItem=NULL;
174         if (pidlAbs == NULL)
175                 return hItem;
176         LPITEMIDLIST pidlMyComputer=NULL;
177         LPITEMIDLIST pidlFirst=GetShellPidl().CopyItemID(pidlAbs);
178     SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer); 
179         if (GetShellPidl().ComparePidls(NULL,pidlMyComputer,pidlFirst))
180         {
181                 hItem = ExpandPidl(pidlMyComputer);
182         }
183         if (pidlMyComputer)
184                 GetShellPidl().FreePidl(pidlMyComputer);
185         if (pidlFirst)
186                 GetShellPidl().FreePidl(pidlFirst);
187         return hItem;
188 }
189
190 HTREEITEM CIEShellTreeCtrl::ExpandPidl(LPITEMIDLIST pidlAbs)
191 {
192         HTREEITEM hItem = SearchSiblings(GetRootItem(),pidlAbs);
193         if (hItem)
194         {
195                 Expand(hItem,TVE_EXPAND);
196         }
197         return hItem;
198 }
199
200 HTREEITEM CIEShellTreeCtrl::FindPidl(LPITEMIDLIST pidlAbs,BOOL bSelect)
201 {
202         HTREEITEM hItem = NULL;
203         if (pidlAbs == NULL)
204                 hItem = GetRootItem();
205         else
206                 hItem = SearchSiblings(GetRootItem(),pidlAbs);
207         if (bSelect && hItem != GetSelectedItem())
208         {
209                 SelectItem(hItem);
210                 SelectionChanged(hItem,GetItemData(hItem));
211         }
212         return hItem;
213 }
214
215 HTREEITEM CIEShellTreeCtrl::FindItem (HTREEITEM hItem, const CString& strTarget)
216 {
217     while (hItem != NULL) 
218         {
219         if (GetItemText (hItem) == strTarget)
220             break;
221         hItem = GetNextSiblingItem (hItem);
222     }
223     return hItem;
224 }
225
226 UINT CIEShellTreeCtrl::DeleteChildren (HTREEITEM hItem)
227 {
228     UINT nCount = 0;
229     HTREEITEM hChild = GetChildItem (hItem);
230
231     while (hChild != NULL)
232         {
233         HTREEITEM hNextItem = GetNextSiblingItem (hChild);
234         DeleteItem (hChild);
235         hChild = hNextItem;
236         nCount++;
237     }
238     return nCount;
239 }
240
241 void CIEShellTreeCtrl::Init()
242 {
243         ModifyStyle(0,TVS_EDITLABELS);
244         CIEFolderTreeCtrl::Init();
245 }
246
247 void CIEShellTreeCtrl::Refresh()
248 {
249         SetRefreshAllowed(false);
250         CIEFolderTreeCtrl::Refresh();
251         SetRefreshAllowed(true);
252 }
253
254 bool CIEShellTreeCtrl::DragEnter(CDD_OleDropTargetInfo *pInfo)
255 {
256         HTREEITEM hItem = pInfo->GetTreeItem(); 
257         if (hItem == NULL)
258                 return false;
259         LPTVITEMDATA ptvid = (LPTVITEMDATA)GetItemData(hItem);
260         ASSERT(ptvid);
261         if (ptvid == NULL)
262                 return false;
263         return m_ShellDragDrop.DragEnter(pInfo,ptvid->lpsfParent,ptvid->lpi);
264 }
265
266 bool CIEShellTreeCtrl::DragLeave(CDD_OleDropTargetInfo *pInfo)
267 {
268         return m_ShellDragDrop.DragLeave(pInfo);
269 }
270
271 bool CIEShellTreeCtrl::DragOver(CDD_OleDropTargetInfo *pInfo)
272 {
273         pInfo->SetDropEffect(DROPEFFECT_NONE);
274
275         HTREEITEM hItem = pInfo->GetTreeItem(); 
276         if (hItem == NULL)
277                 return false;
278         LPTVITEMDATA ptvid = (LPTVITEMDATA)GetItemData(hItem);
279         ASSERT(ptvid);
280         if (ptvid == NULL)
281                 return false;
282         return m_ShellDragDrop.DragOver(pInfo,ptvid->lpsfParent,ptvid->lpi);
283 }
284
285 bool CIEShellTreeCtrl::DragDrop(CDD_OleDropTargetInfo *pInfo)
286 {
287         HTREEITEM hItem = pInfo->GetTreeItem(); 
288         if (hItem == NULL)
289                 return false;
290         LPTVITEMDATA ptvid = (LPTVITEMDATA)GetItemData(hItem);
291         ASSERT(ptvid);
292         if (ptvid == NULL)
293                 return false;
294         return m_ShellDragDrop.DragDrop(pInfo,ptvid->lpsfParent,ptvid->lpi);
295 }
296
297 DROPEFFECT CIEShellTreeCtrl::DoDragDrop(NM_TREEVIEW* pNMTreeView,COleDataSource *pOleDataSource)
298 {
299         if (pNMTreeView->itemNew.hItem == GetRootItem())
300                 return DROPEFFECT_NONE;
301         CCF_ShellIDList sl;
302         CShellPidl pidl;
303         HTREEITEM hParentItem = GetParentItem(pNMTreeView->itemNew.hItem);
304         LPTVITEMDATA ptvid = (LPTVITEMDATA)GetItemData(pNMTreeView->itemNew.hItem);
305         LPTVITEMDATA ptvid_parent = (LPTVITEMDATA)GetItemData(hParentItem);
306         ASSERT(ptvid);
307         ASSERT(ptvid_parent);
308         if (GetShellPidl().IsDesktopFolder(ptvid->lpsfParent))
309                 sl.AddPidl(GetShellPidl().GetEmptyPidl());
310         else
311                 sl.AddPidl(ptvid_parent->lpifq);
312         sl.AddPidl(ptvid->lpi);
313         CCF_HDROP cf_hdrop;
314         CCF_String cf_text;
315         CString sPath;
316         pidl.SHPidlToPathEx(ptvid->lpifq,sPath);
317         cf_hdrop.AddDropPoint(CPoint(pNMTreeView->ptDrag),FALSE);
318         cf_hdrop.AddFileName(sPath);
319         sPath += _T("\r\n");
320         cf_text.SetString(sPath);
321         CWDClipboardData::Instance()->SetData(pOleDataSource,&cf_text,CWDClipboardData::e_cfString);
322         CWDClipboardData::Instance()->SetData(pOleDataSource,&cf_hdrop,CWDClipboardData::e_cfHDROP);
323         CWDClipboardData::Instance()->SetData(pOleDataSource,&sl,CWDClipboardData::e_cfShellIDList);
324         return GetShellPidl().GetDragDropAttributes(ptvid);
325 }
326
327 bool CIEShellTreeCtrl::EndLabelEdit(HTREEITEM hItem,LPCTSTR pszText)
328 {
329         LPTVITEMDATA plvit = (LPTVITEMDATA)GetItemData(hItem);
330         CString sFromPath;
331         CString sToPath;
332         GetShellPidl().SHPidlToPathEx(plvit->lpifq,sFromPath);
333         sToPath = sFromPath;
334         sToPath.Replace(GetItemText(hItem),pszText);
335         SHFILEOPSTRUCT shf;
336         TCHAR szFrom[MAX_PATH+1];
337         TCHAR szTo[MAX_PATH+1];
338         ZeroMemory(szFrom,sizeof(szFrom));
339         lstrcpy(szFrom,sFromPath);
340         ZeroMemory(szTo,sizeof(szTo));
341         lstrcpy(szTo,sToPath);
342         ZeroMemory(&shf,sizeof(shf));
343         shf.hwnd = GetSafeHwnd();
344         shf.wFunc = FO_RENAME;
345         shf.pFrom = szFrom;
346         shf.pTo = szTo;
347 #ifdef _DEBUG
348         CString sMess;
349         sMess = szFrom;
350         sMess += _T("\n");
351         sMess += szTo;
352         AfxMessageBox(sMess);
353 #endif
354         if (SHFileOperation(&shf) == 0)
355                 return true;
356         SetRefreshAllowed(false);
357         return false;
358 }
359
360 bool CIEShellTreeCtrl::SHMoveFile(HTREEITEM hSrcItem,HTREEITEM hDestItem)
361 {
362         LPTVITEMDATA plvit_src = (LPTVITEMDATA)GetItemData(hSrcItem);
363         LPTVITEMDATA plvit_dest = (LPTVITEMDATA)GetItemData(hDestItem);
364         CString sFromPath;
365         CString sToPath;
366         GetShellPidl().SHPidlToPathEx(plvit_src->lpifq,sFromPath);
367         GetShellPidl().SHPidlToPathEx(plvit_dest->lpifq,sToPath);
368         SHFILEOPSTRUCT shf;
369         TCHAR szFrom[MAX_PATH+1];
370         TCHAR szTo[MAX_PATH+1];
371         ZeroMemory(szFrom,sizeof(szFrom));
372         lstrcpy(szFrom,sFromPath);
373         ZeroMemory(szTo,sizeof(szTo));
374         lstrcpy(szTo,sToPath);
375         ZeroMemory(&shf,sizeof(shf));
376         shf.hwnd = GetSafeHwnd();
377         shf.wFunc = FO_MOVE;
378         shf.pFrom = szFrom;
379         shf.pTo = szTo;
380         return SHFileOperation(&shf) == 0 ? true : false;
381 }
382
383 BOOL CIEShellTreeCtrl::TransferItem(HTREEITEM hitemDrag, HTREEITEM hitemDrop)
384 {
385         return SHMoveFile(hitemDrag,hitemDrop) ? TRUE : FALSE;
386 }
387
388 bool CIEShellTreeCtrl::GetFolderInfo(HTREEITEM hItem,CString &sPath,CString &sName)
389 {
390         LPTVITEMDATA lptvid = (LPTVITEMDATA)GetItemData(hItem);
391         if (lptvid == NULL)
392                 return false;
393         GetShellPidl().SHPidlToPathEx(lptvid->lpifq,sPath,NULL,SHGDN_NORMAL);
394         GetShellPidl().GetDisplayName(lptvid->lpi,sName);
395         return true;
396 }
397
398 bool CIEShellTreeCtrl::LoadFolderItems(LPCTSTR pszPath)
399 {
400         return LoadItems(pszPath);
401 }
402
403 CRefresh *CIEShellTreeCtrl::CreateRefreshObject(HTREEITEM hItem,LPARAM lParam)
404 {
405         CRefreshShellFolder *pRefresh=NULL;
406         if (lParam)
407         {
408                 pRefresh = new CRefreshShellFolder(hItem,lParam);
409         }
410         return pRefresh;
411 }
412
413 bool CIEShellTreeCtrl::Expanding(NM_TREEVIEW *nmtvw)
414 {
415         if ((nmtvw->itemNew.state & TVIS_EXPANDEDONCE) || nmtvw->itemNew.hItem == GetRootItem())
416                 return false;
417
418         LPSHELLFOLDER  pFolder=NULL;
419         CUIListCtrlData *pData = (CUIListCtrlData*)nmtvw->itemNew.lParam;
420         ASSERT(pData);
421         ASSERT_KINDOF(CUIListCtrlData,pData);
422         LPTVITEMDATA lptvid=(LPTVITEMDATA)pData->GetExtData();
423         if (lptvid)
424         {
425                 HRESULT hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
426                         0, IID_IShellFolder,(LPVOID*)&pFolder);
427
428                 if (SUCCEEDED(hr))
429                 {
430                         if (!AddItems(nmtvw->itemNew.hItem,pFolder))
431                                 SetButtonState(nmtvw->itemNew.hItem);
432                 }
433                 return false;
434         }
435         // prevent from expanding
436         return true;
437 }
438
439 BEGIN_MESSAGE_MAP(CIEShellTreeCtrl, CIEFolderTreeCtrl)
440         //{{AFX_MSG_MAP(CIEShellTreeCtrl)
441         ON_MESSAGE(WM_SETMESSAGESTRING,OnSetmessagestring)
442         ON_MESSAGE(WM_APP_CB_IE_HIT_ENTER,OnAppCbIeHitEnter)
443                 // NOTE - the ClassWizard will add and remove mapping macros here.
444         ON_WM_DESTROY()
445         //}}AFX_MSG_MAP
446         ON_MESSAGE(WM_APP_POPULATE_TREE,OnAppPopulateTree)
447         ON_MESSAGE(WM_APP_CB_IE_SEL_CHANGE,OnCBIESelChange)
448         ON_MESSAGE(WM_APP_DIR_CHANGE_EVENT,OnAppDirChangeEvent)
449
450 END_MESSAGE_MAP()
451
452 /////////////////////////////////////////////////////////////////////////////
453 // CIEShellTreeCtrl message handlers
454 BOOL CIEShellTreeCtrl::OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult )
455 {
456         if ((message == WM_MEASUREITEM || message == WM_DRAWITEM && wParam == 0) || message == WM_INITMENUPOPUP)
457         {
458                 if (m_lptvid)
459                 {
460                         return GetShellPidl().HandleMenuMsg(m_hWnd,m_lptvid->lpsfParent, m_lptvid->lpi,
461                                                                         message,wParam,lParam);
462                 }
463         }
464         return CIEFolderTreeCtrl::OnWndMsg(message, wParam, lParam, pResult );
465 }
466
467 void CIEShellTreeCtrl::PreSubclassWindow()
468 {
469         CIEFolderTreeCtrl::PreSubclassWindow();
470         CreateFileChangeThreads(GetSafeHwnd());
471 }
472
473 /////////////////////////////////////////////////////////////////////////
474 // Thread function for detecting file system changes
475 UINT CIEShellTreeCtrl::ThreadFunc (LPVOID pParam)
476 {
477         ///////////////////////////////
478     PDC_THREADINFO pThreadInfo = (PDC_THREADINFO) pParam;
479     HANDLE hEvent = pThreadInfo->hEvent;
480         CIEShellTreeCtrl *pTreeCtrl = pThreadInfo->pTreeCtrl;
481     HWND hWnd = pTreeCtrl->GetSafeHwnd();
482         TCHAR szPath[MAX_PATH];
483         lstrcpy(szPath,pThreadInfo->sPath);
484     delete pThreadInfo;
485     ////////////////////////////////////
486
487     // Get a handle to a file change notification object.
488         TRACE(_T("Creating directory thread handler for %s\n"),szPath);
489     HANDLE hDirChange = ::FindFirstChangeNotification (szPath,TRUE,FILE_NOTIFY_CHANGE_DIR_NAME);
490
491     // Return now if ::FindFirstChangeNotification failed.
492     if (hDirChange == INVALID_HANDLE_VALUE)
493         return 1;
494         const int nHandles=2;
495     HANDLE aHandles[nHandles];
496     aHandles[0] = hDirChange;
497     aHandles[1] = hEvent;
498     BOOL bContinue = TRUE;
499
500     // Sleep until a file change notification wakes this thread or
501     // m_event becomes set indicating it's time for the thread to end.
502     while (bContinue)
503         {
504                 TRACE(_T("TreeControl waiting for %u multiple objects\n"),nHandles);
505         DWORD dw = ::WaitForMultipleObjects (nHandles, aHandles, FALSE, INFINITE);
506         if (dw - WAIT_OBJECT_0 == 0) 
507                 { // Respond to a change notification.
508             ::FindNextChangeNotification (hDirChange);
509                         TRACE(_T("-- Directory notify event was fired in CIEShellTreeCtrl --\n"));
510                         if (pTreeCtrl->RefreshAllowed())
511                         {
512                                 ::PostMessage (hWnd, WM_APP_DIR_CHANGE_EVENT,0,0);
513                         }
514                         else
515                         {
516                                 TRACE(_T("but not sending as refresh disallowed\n"));
517                                 pTreeCtrl->SetRefreshAllowed(true);
518                                 TRACE(_T("Refresh is now allowed\n"));
519                         }
520         }
521         else if(dw - WAIT_OBJECT_0 == 1) 
522                 {
523             bContinue = FALSE;
524                         TRACE(_T("Directory Notify Thread was signalled to stop\n"));
525                 }
526     }
527
528     // Close the file change notification handle and return.
529     ::FindCloseChangeNotification (hDirChange);
530         TRACE(_T("Directory Notify Thread is ending\n"));
531     return 0;
532 }
533
534 void CIEShellTreeCtrl::OnDestroy()
535 {
536         DestroyThreads();
537         CIEFolderTreeCtrl::OnDestroy();
538 }
539
540 LRESULT CIEShellTreeCtrl::OnAppDirChangeEvent(WPARAM wParam, LPARAM lParam)
541 {
542         if (!RefreshAllowed())
543                 return 1L;
544         Refresh();
545         if (m_bNotifyParent)
546                 GetParent()->SendMessage(WM_APP_UPDATE_ALL_VIEWS,(WPARAM)HINT_SHELL_DIR_CHANGED,(LPARAM)(LPCTSTR)GetRootPath());
547         return 1L;
548 }
549
550 LRESULT CIEShellTreeCtrl::OnCBIESelChange(WPARAM wParam,LPARAM lParam)
551 {
552         LPITEMIDLIST pidl = (LPITEMIDLIST)wParam;
553         ExpandMyComputer(pidl);
554         FindPidl(pidl);                         
555         GetShellPidl().FreePidl(pidl);
556         SetFocus();
557         return 1L;
558 }
559
560 // Selection has changed
561 void CIEShellTreeCtrl::UpdateEvent(LPARAM lHint,CObject *pHint)
562 {
563         // TODO: Add your specialized code here and/or call the base class
564         // Notify the combo box
565         const CRefreshShellFolder *pRefresh = static_cast<CRefreshShellFolder*>(pHint);
566         LPTVITEMDATA lptvid = reinterpret_cast<LPTVITEMDATA>(pRefresh->GetItemData());
567         ASSERT(lptvid);
568         // Notify combo box
569         RefreshComboBox(lptvid);
570         // Notify list control
571         if (m_hListWnd)
572         {
573                 ::SendMessage(m_hListWnd,WM_APP_UPDATE_ALL_VIEWS,(WPARAM)lHint,(LPARAM)pHint);
574                 return;
575         }
576         // or let base class handle it
577         CUITreeCtrl::UpdateEvent(lHint,pHint);
578 }
579
580 LRESULT CIEShellTreeCtrl::OnAppPopulateTree(WPARAM wParam, LPARAM lParam)
581 {
582         TRACE0("Selecting root item\n");
583         HTREEITEM hRoot = GetRootItem();
584         if (hRoot == NULL)
585                 return 1L;      
586         SelectItem(hRoot);
587 #ifndef _DEBUG
588         SelectionChanged(hRoot,GetItemData(hRoot));
589 #else
590         LPTVITEMDATA lptvid = reinterpret_cast<LPTVITEMDATA>(GetItemData(hRoot));
591         RefreshComboBox(lptvid);
592 #endif
593         return 1;
594 }
595
596 void CIEShellTreeCtrl::DeleteKey(HTREEITEM hItem)
597 {
598         // TODO: Add your specialized code here and/or call the base class
599         SHFILEOPSTRUCT shf;
600         ZeroMemory(&shf,sizeof(shf));
601         TCHAR szFrom[MAX_PATH+1];
602         ZeroMemory(szFrom,sizeof(szFrom)*sizeof(TCHAR));
603         lstrcpy(szFrom,GetPathName(hItem));
604         shf.hwnd = GetSafeHwnd();
605         shf.wFunc = FO_DELETE;
606         shf.pFrom = szFrom;
607         shf.fFlags = GetKeyState(VK_SHIFT) < 0 ? 0 : FOF_ALLOWUNDO;
608         SHFileOperation(&shf);
609 }
610
611 void CIEShellTreeCtrl::DoubleClick(HTREEITEM hItem)
612 {
613         // TODO: Add your specialized code here and/or call the base class
614         ShellExecute(hItem);
615 }
616
617 void CIEShellTreeCtrl::GoBack(HTREEITEM hItem)
618 {
619         // TODO: Add your specialized code here and/or call the base class
620         UpOneLevel(hItem);
621 }
622
623 void CIEShellTreeCtrl::ShowPopupMenu(HTREEITEM hItem,CPoint point)
624 {
625         // TODO: Add your specialized code here and/or call the base class
626         if (m_PopupID)
627         {
628                 CUITreeCtrl::ShowPopupMenu(hItem,point);
629         }
630         // TODO: Add your control notification handler code here
631         m_lptvid = (LPTVITEMDATA)GetItemData(hItem);
632         if (m_lptvid)
633                 GetShellPidl().PopupTheMenu(m_hWnd,m_lptvid->lpsfParent, &m_lptvid->lpi, 1, &point);
634 }
635
636 void CIEShellTreeCtrl::ShowProperties(HTREEITEM hItem)
637 {
638         // TODO: Add your specialized code here and/or call the base class
639         ShellExecute(hItem,_T("properties"));
640 }
641
642 LRESULT CIEShellTreeCtrl::OnAppCbIeHitEnter(WPARAM wParam, LPARAM lParam)
643 {
644         if (lParam == NULL)
645                 return 0L;
646         LPCTSTR pszPath = (LPCTSTR)lParam;
647         LPITEMIDLIST pidl=NULL;
648         GetShellPidl().SHPathToPidlEx(pszPath,&pidl,NULL);
649         if (pidl == NULL)
650                 return 0L;
651         int nCount = GetShellPidl().GetCount(pidl);
652         LPITEMIDLIST pidlPart=NULL;
653         LPITEMIDLIST pidlFull=NULL;
654         HTREEITEM hItem=NULL;
655         SetRedraw(FALSE);
656         for(int i=0;i < nCount;i++)
657         {
658                 pidlPart=GetShellPidl().CopyItemID(pidl,i+1);
659                 if (pidlPart)
660                 {
661                         pidlFull = GetShellPidl().ConcatPidl(pidlFull,pidlPart);
662                         hItem = ExpandPidl(pidlFull);
663                         if (hItem == NULL)
664                                 break;
665                         GetShellPidl().FreePidl(pidlPart);
666                 }
667         }
668         if (hItem && GetShellPidl().ComparePidls(NULL,pidl,pidlFull))
669         {
670                 Select(hItem,TVGN_CARET);
671         }
672         else
673         {
674                 CString sMess;
675                 sMess.Format(_T("%s was not found"),pszPath);
676                 AfxMessageBox(sMess,MB_ICONSTOP);
677         }
678         if (pidl)
679                 GetShellPidl().FreePidl(pidl);
680         if (pidlFull)
681                 GetShellPidl().FreePidl(pidlFull);
682         SetRedraw(TRUE);
683         return 1;
684 }
685
686 LRESULT CIEShellTreeCtrl::OnSetmessagestring(WPARAM wParam, LPARAM lParam)
687 {
688         if (GetParent())
689                 return GetParent()->SendMessage(WM_SETMESSAGESTRING,wParam,lParam);
690         return 0;
691 }