/* TODO: Convert to using pidl's here, rather than file names. */ int CShellBrowser::SelectFiles(const TCHAR *FileNamePattern) { int iItem; iItem = LocateFileItemIndex(FileNamePattern); if(iItem != -1) { NListView::ListView_FocusItem(m_hListView,iItem,TRUE); NListView::ListView_SelectItem(m_hListView,iItem,TRUE); ListView_EnsureVisible(m_hListView,iItem,FALSE); return 1; } return 0; }
void CShellBrowser::DirectoryAltered(void) { BOOL bNewItemCreated; EnterCriticalSection(&m_csDirectoryAltered); bNewItemCreated = m_bNewItemCreated; SendMessage(m_hListView,WM_SETREDRAW,(WPARAM)FALSE,(LPARAM)NULL); pantheios::log(pantheios::debug,_T("ShellBrowser - Starting directory change update for \""),m_CurDir,_T("\"")); /* Potential problem: After a file is created, it may be renamed shortly afterwards. If the rename occurs before the file is added here, the addition won't be registered (since technically, the file does not exist), and the rename operation will not take place. Adding an item that does not exist will corrupt the programs state. Solution: If a file does not exist when adding it, temporarily remember its filename. On the next rename operation, if the renamed file matches the name of the added file, add the file in-place with its new name. The operation should NOT be queued, as it is possible that other actions for the file will take place before the addition, which will again result in an incorrect state. */ for each(auto af in m_AlteredList) { /* Only undertake the modification if the unique folder index on the modified item and current folder match up (i.e. ensure the directory has not changed since these files were modified). */ if(af.iFolderIndex == m_iUniqueFolderIndex) { switch(af.dwAction) { case FILE_ACTION_ADDED: pantheios::log(pantheios::debug,_T("ShellBrowser - Adding \""),af.szFileName,_T("\"")); OnFileActionAdded(af.szFileName); break; case FILE_ACTION_MODIFIED: pantheios::log(pantheios::debug,_T("ShellBrowser - Modifying \""),af.szFileName,_T("\"")); ModifyItemInternal(af.szFileName); break; case FILE_ACTION_REMOVED: pantheios::log(pantheios::debug,_T("ShellBrowser - Removing \""),af.szFileName,_T("\"")); RemoveItemInternal(af.szFileName); break; case FILE_ACTION_RENAMED_OLD_NAME: pantheios::log(pantheios::debug,_T("ShellBrowser - Old name received \""),af.szFileName,_T("\"")); OnFileActionRenamedOldName(af.szFileName); break; case FILE_ACTION_RENAMED_NEW_NAME: pantheios::log(pantheios::debug,_T("ShellBrowser - New name received \""),af.szFileName,_T("\"")); OnFileActionRenamedNewName(af.szFileName); break; } } } pantheios::log(pantheios::debug,_T("ShellBrowser - Finished directory change update for \""),m_CurDir,_T("\"")); SendMessage(m_hListView,WM_SETREDRAW,(WPARAM)TRUE,(LPARAM)NULL); /* Ensure the first dropped item is visible. */ if(m_iDropped != -1) { if(!ListView_IsItemVisible(m_hListView,m_iDropped)) ListView_EnsureVisible(m_hListView,m_iDropped,TRUE); m_iDropped = -1; } SendMessage(m_hOwner,WM_USER_DIRECTORYMODIFIED,m_ID,0); if(bNewItemCreated && !m_bNewItemCreated) SendMessage(m_hOwner,WM_USER_NEWITEMINSERTED,0,m_iIndexNewItem); m_AlteredList.clear(); BOOL bFocusSet = FALSE; int iIndex; /* Select the specified items, and place the focus on the first item. */ auto itr = m_FileSelectionList.begin(); while(itr != m_FileSelectionList.end()) { iIndex = LocateFileItemIndex(itr->c_str()); if(iIndex != -1) { NListView::ListView_SelectItem(m_hListView,iIndex,TRUE); if(!bFocusSet) { NListView::ListView_FocusItem(m_hListView,iIndex,TRUE); ListView_EnsureVisible(m_hListView,iIndex,TRUE); bFocusSet = TRUE; } itr = m_FileSelectionList.erase(itr); } else { ++itr; } } LeaveCriticalSection(&m_csDirectoryAltered); return; }
/* * Modifies the attributes of an item currently in the listview. */ void CShellBrowser::ModifyItemInternal(const TCHAR *FileName) { HANDLE hFirstFile; ULARGE_INTEGER ulFileSize; LVITEM lvItem; TCHAR FullFileName[MAX_PATH]; BOOL bFolder; BOOL res; int iItem; int iItemInternal = -1; iItem = LocateFileItemIndex(FileName); /* Although an item may not have been added to the listview yet, it is critical that its' size still be updated if necessary. It is possible (and quite likely) that the file add and modified messages will be sent in the same group, meaning that when the modification message is processed, the item is not in the listview, but it still needs to be updated. Therefore, instead of searching for items solely in the listview, also look through the list of pending file additions. */ if(iItem == -1) { /* The item doesn't exist in the listview. This can happen when a file has been created with a non-zero size, but an item has not yet been inserted into the listview. Search through the list of items waiting to be inserted, so that files the have just been created can be updated without them residing within the listview. */ std::list<AwaitingAdd_t>::iterator itr; for(itr = m_AwaitingAddList.begin();itr!= m_AwaitingAddList.end();itr++) { if(lstrcmp(m_pwfdFiles[itr->iItemInternal].cFileName,FileName) == 0) { iItemInternal = itr->iItemInternal; break; } } } else { /* The item exists in the listview. Determine its internal index from its listview information. */ lvItem.mask = LVIF_PARAM; lvItem.iItem = iItem; lvItem.iSubItem = 0; res = ListView_GetItem(m_hListView,&lvItem); if(res != FALSE) iItemInternal = (int)lvItem.lParam; TCHAR szFullFileName[MAX_PATH]; StringCchCopy(szFullFileName,SIZEOF_ARRAY(szFullFileName),m_CurDir); PathAppend(szFullFileName,FileName); /* When a file is modified, its icon overlay may change. This is the case when modifying a file managed by TortoiseSVN, for example. */ SHFILEINFO shfi; DWORD_PTR dwRes = SHGetFileInfo(szFullFileName,0,&shfi,sizeof(SHFILEINFO),SHGFI_ICON|SHGFI_OVERLAYINDEX); if(dwRes != 0) { lvItem.mask = LVIF_STATE; lvItem.iItem = iItem; lvItem.iSubItem = 0; lvItem.stateMask = LVIS_OVERLAYMASK; lvItem.state = INDEXTOOVERLAYMASK(shfi.iIcon >> 24); ListView_SetItem(m_hListView,&lvItem); DestroyIcon(shfi.hIcon); } }
/* * Modifies the attributes of an item currently in the listview. */ void CFolderView::ModifyItemInternal(TCHAR *FileName) { HANDLE hFirstFile; ULARGE_INTEGER ulFileSize; LVITEM lvItem; TCHAR FullFileName[MAX_PATH]; BOOL bFolder; BOOL res; int iItem; int iItemInternal = -1; iItem = LocateFileItemIndex(FileName); /* Although an item may not have been added to the listview yet, it is critical that its' size still be updated if neccesary. It is possible (and quite likely) that the file add and modified messages will be sent in the same group, meaning that when the modification message is processed, the item is not in the listview, but it still needs to be updated. Therefore, instead of searching for items soley in the listview, also look through the list of pending file additions. */ if(iItem == -1) { /* The item doesn't exist in the listview. This can happen when a file has been created with a non-zero size, but an item has not yet been inserted into the listview. Search through the list of items waiting to be inserted, so that files the have just been created can be updated without them residing within the listview. */ list<AwaitingAdd_t>::iterator itr; for(itr = m_AwaitingAddList.begin();itr!= m_AwaitingAddList.end();itr++) { if(lstrcmp(m_pwfdFiles[itr->iItemInternal].cFileName,FileName) == 0) { iItemInternal = itr->iItemInternal; break; } } } else { /* The item exists in the listview. Determine its internal index from its listview information. */ lvItem.mask = LVIF_PARAM; lvItem.iItem = iItem; lvItem.iSubItem = 0; res = ListView_GetItem(m_hListView,&lvItem); if(res != FALSE) iItemInternal = (int)lvItem.lParam; } if(iItemInternal != -1) { /* Is this item a folder? */ bFolder = (m_pwfdFiles[iItemInternal].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; ulFileSize.LowPart = m_pwfdFiles[iItemInternal].nFileSizeLow; ulFileSize.HighPart = m_pwfdFiles[iItemInternal].nFileSizeHigh; m_ulTotalDirSize.QuadPart -= ulFileSize.QuadPart; if(ListView_GetItemState(m_hListView,iItem,LVIS_SELECTED) == LVIS_SELECTED) { ulFileSize.LowPart = m_pwfdFiles[iItemInternal].nFileSizeLow; ulFileSize.HighPart = m_pwfdFiles[iItemInternal].nFileSizeHigh; m_ulFileSelectionSize.QuadPart -= ulFileSize.QuadPart; } StringCchCopy(FullFileName,SIZEOF_ARRAY(FullFileName),m_CurDir); PathAppend(FullFileName,FileName); hFirstFile = FindFirstFile(FullFileName,&m_pwfdFiles[iItemInternal]); if(hFirstFile != INVALID_HANDLE_VALUE) { ulFileSize.LowPart = m_pwfdFiles[iItemInternal].nFileSizeLow; ulFileSize.HighPart = m_pwfdFiles[iItemInternal].nFileSizeHigh; m_ulTotalDirSize.QuadPart += ulFileSize.QuadPart; if(ListView_GetItemState(m_hListView,iItem,LVIS_SELECTED) == LVIS_SELECTED) { ulFileSize.LowPart = m_pwfdFiles[iItemInternal].nFileSizeLow; ulFileSize.HighPart = m_pwfdFiles[iItemInternal].nFileSizeHigh; m_ulFileSelectionSize.QuadPart += ulFileSize.QuadPart; } if((m_pwfdFiles[iItemInternal].dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN) { ListView_SetItemState(m_hListView,iItem,LVIS_CUT,LVIS_CUT); } else ListView_SetItemState(m_hListView,iItem,0,LVIS_CUT); if(m_ViewMode == VM_DETAILS) { list<Column_t>::iterator itrColumn; int iColumnIndex = 0; if(m_pActiveColumnList != NULL) { for(itrColumn = m_pActiveColumnList->begin();itrColumn != m_pActiveColumnList->end();itrColumn++) { if(itrColumn->bChecked) { SetColumnData(itrColumn->id,iItem,iColumnIndex++); } } } } FindClose(hFirstFile); } else { /* The file may not exist if, for example, it was renamed just after a file with the same name was deleted. If this does happen, a modification message will likely be sent out after the file has been renamed, indicating the new items properties. However, the files' size will be subtracted on modification. If the internal structures still hold the old size, the total directory size will become corrupted. */ m_pwfdFiles[iItemInternal].nFileSizeLow = 0; m_pwfdFiles[iItemInternal].nFileSizeHigh = 0; } } }