From e340c707bab2d66ee479c069054ea8d191058f45 Mon Sep 17 00:00:00 2001 From: Juergen Schmied Date: Wed, 13 Oct 1999 15:53:05 +0000 Subject: [PATCH] - implemented sorting the listview by clicking on the column header - implemented the context menu entrys for sorting - some more functions to gather data form pidls --- dlls/comctl32/listview.c | 19 ++++ dlls/shell32/pidl.c | 180 ++++++++++++++++++++++++++++++++---- dlls/shell32/pidl.h | 10 +- dlls/shell32/shell32_main.c | 18 +--- dlls/shell32/shlview.c | 116 ++++++++++++++++++++++- dlls/shell32/shv_bg_cmenu.c | 4 + 6 files changed, 310 insertions(+), 37 deletions(-) diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index f4b9af83e65..ec3a6fd247d 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -6203,6 +6203,25 @@ static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh) infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd); InvalidateRect(hwnd, NULL, TRUE); } + if(lpnmh->code == HDN_ITEMCLICKA) + { + /* Handle sorting by Header Column */ + NMLISTVIEW nmlv; + LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh; + LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); + + ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); + nmlv.hdr.hwndFrom = hwnd; + nmlv.hdr.idFrom = lCtrlId; + nmlv.hdr.code = LVN_COLUMNCLICK; + nmlv.iItem = -1; + nmlv.iSubItem = pnmHeader->iItem; + + ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv); + InvalidateRect(hwnd, NULL, TRUE); + + } + } return 0; diff --git a/dlls/shell32/pidl.c b/dlls/shell32/pidl.c index 140671464a4..1246a1ba0fa 100644 --- a/dlls/shell32/pidl.c +++ b/dlls/shell32/pidl.c @@ -19,6 +19,7 @@ #include "winnls.h" #include "winversion.h" #include "shell32_main.h" +#include "shellapi.h" #include "pidl.h" #include "wine/undocshell.h" @@ -1512,36 +1513,79 @@ REFIID WINAPI _ILGetGUIDPointer(LPCITEMIDLIST pidl) return NULL; } +/************************************************************************* + * _ILGetFileDateTime + * + * Given the ItemIdList, get the FileTime + * + * PARAMS + * pidl [I] The ItemIDList + * pFt [I] the resulted FILETIME of the file + * + * RETURNS + * True if Successful + * + * NOTES + * + */ +BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt) +{ + LPPIDLDATA pdata =_ILGetDataPointer(pidl); + + switch (pdata->type) + { + case PT_FOLDER: + DosDateTimeToFileTime(pdata->u.folder.uFileDate, pdata->u.folder.uFileTime, pFt); + break; + case PT_VALUE: + DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt); + break; + default: + return FALSE; + } + return TRUE; +} + BOOL WINAPI _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) -{ LPPIDLDATA pdata =_ILGetDataPointer(pidl); +{ FILETIME ft; SYSTEMTIME time; - switch (pdata->type) - { case PT_FOLDER: - DosDateTimeToFileTime(pdata->u.folder.uFileDate, pdata->u.folder.uFileTime, &ft); - break; - case PT_VALUE: - DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, &ft); - break; - default: - return FALSE; - } + if (! _ILGetFileDateTime( pidl, &ft )) return FALSE; + FileTimeToSystemTime (&ft, &time); return GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL, pOut, uOutSize); } -BOOL WINAPI _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) -{ LPPIDLDATA pdata =_ILGetDataPointer(pidl); +/************************************************************************* + * _ILGetFileSize + * + * Given the ItemIdList, get the FileSize + * + * PARAMS + * pidl [I] The ItemIDList + * pOut [I] The buffer to save the result + * uOutsize [I] The size of the buffer + * + * RETURNS + * The FileSize + * + * NOTES + * pOut can be null when no string is needed + * + */ +DWORD WINAPI _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) +{ + LPPIDLDATA pdata =_ILGetDataPointer(pidl); + DWORD dwSize; switch (pdata->type) { case PT_VALUE: - break; - default: - return FALSE; + dwSize = pdata->u.file.dwFileSize; + if (pOut) StrFormatByteSizeA(dwSize, pOut, uOutSize); + return dwSize; } - StrFormatByteSizeA(pdata->u.file.dwFileSize, pOut, uOutSize); - return TRUE; + return 0; } BOOL WINAPI _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) @@ -1570,3 +1614,103 @@ BOOL WINAPI _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) return TRUE; } +/************************************************************************* + * _ILGetFileType + * + * Given the ItemIdList, get the file type description + * + * PARAMS + * pidl [I] The ItemIDList (simple) + * pOut [I] The buffer to save the result + * uOutsize [I] The size of the buffer + * + * RETURNS + * nothing + * + * NOTES + * This function copies as much as possible into the buffer. + */ +void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) +{ + if(_ILIsValue(pidl)) + { + char sTemp[64]; + if (_ILGetExtension (pidl, sTemp, 64)) + { + if (!( HCR_MapTypeToValue(sTemp, sTemp, 64, TRUE) + && HCR_MapTypeToValue(sTemp, pOut, uOutSize, FALSE ))) + { + lstrcpynA (pOut, sTemp, uOutSize - 6); + strcat (pOut, "-file"); + } + } + } + else + { + lstrcpynA(pOut, "Folder", uOutSize); + } +} + +/************************************************************************* + * _ILGetAttributeStr + * + * Given the ItemIdList, get the Attrib string format + * + * PARAMS + * pidl [I] The ItemIDList + * pOut [I] The buffer to save the result + * uOutsize [I] The size of the Buffer + * + * RETURNS + * True if successful + * + * NOTES + * + */ +BOOL _ILGetAttributeStr(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) +{ + LPPIDLDATA pData =_ILGetDataPointer(pidl); + WORD wAttrib; + int i; + + /* Need At Least 6 characters to represent the Attrib String */ + if(uOutSize < 6) + { + return FALSE; + } + switch(pData->type) + { + case PT_FOLDER: + wAttrib = pData->u.folder.uFileAttribs; + break; + case PT_VALUE: + wAttrib = pData->u.file.uFileAttribs; + break; + default: + return FALSE; + } + i=0; + if(wAttrib & FILE_ATTRIBUTE_READONLY) + { + pOut[i++] = 'R'; + } + if(wAttrib & FILE_ATTRIBUTE_HIDDEN) + { + pOut[i++] = 'H'; + } + if(wAttrib & FILE_ATTRIBUTE_SYSTEM) + { + pOut[i++] = 'S'; + } + if(wAttrib & FILE_ATTRIBUTE_ARCHIVE) + { + pOut[i++] = 'A'; + } + if(wAttrib & FILE_ATTRIBUTE_COMPRESSED) + { + pOut[i++] = 'C'; + } + pOut[i] = 0x00; + return TRUE; +} + diff --git a/dlls/shell32/pidl.h b/dlls/shell32/pidl.h index 0f8a27b3ddb..3111414cb69 100644 --- a/dlls/shell32/pidl.h +++ b/dlls/shell32/pidl.h @@ -124,7 +124,7 @@ DWORD WINAPI _ILGetDrive(LPCITEMIDLIST,LPSTR,UINT16); * getting special values from simple pidls */ BOOL WINAPI _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); -BOOL WINAPI _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); +DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); BOOL WINAPI _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); @@ -168,4 +168,12 @@ REFIID WINAPI _ILGetGUIDPointer(LPCITEMIDLIST pidl); void pdump (LPCITEMIDLIST pidl); BOOL pcheck (LPCITEMIDLIST pidl); + +/* + * ItemIDList File helper functions + */ +void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); +BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *ft); +BOOL _ILGetAttributeStr(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); + #endif diff --git a/dlls/shell32/shell32_main.c b/dlls/shell32/shell32_main.c index 25d9e788b29..39fd751bf23 100644 --- a/dlls/shell32/shell32_main.c +++ b/dlls/shell32/shell32_main.c @@ -170,23 +170,7 @@ DWORD WINAPI SHGetFileInfoA(LPCSTR path,DWORD dwFileAttributes, /* get the type name */ if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME)) { - if(_ILIsValue(pidlLast)) - { - char sTemp[64]; - if (_ILGetExtension (pidlLast, sTemp, 64)) - { - if (!( HCR_MapTypeToValue(sTemp, sTemp, 64, TRUE) - && HCR_MapTypeToValue(sTemp, psfi->szTypeName, 80, FALSE ))) - { - lstrcpynA (psfi->szTypeName, sTemp, 74); - strcat (psfi->szTypeName, "-file"); - } - } - } - else - { - strcpy(psfi->szTypeName, "Folder"); - } + _ILGetFileType(pidlLast, psfi->szTypeName, 80); } /* ### icons ###*/ diff --git a/dlls/shell32/shlview.c b/dlls/shell32/shlview.c index d8379f4d500..e8802dcbf95 100644 --- a/dlls/shell32/shlview.c +++ b/dlls/shell32/shlview.c @@ -71,6 +71,13 @@ static struct ICOM_VTABLE(IViewObject) vovt; #define _IViewObject_Offset ((int)(&(((IShellViewImpl*)0)->lpvtblViewObject))) #define _ICOM_THIS_From_IViewObject(class, name) class* This = (class*)(((char*)name)-_IViewObject_Offset); +/* ListView Header ID's */ +#define LISTVIEW_COLUMN_NAME 0 +#define LISTVIEW_COLUMN_SIZE 1 +#define LISTVIEW_COLUMN_TYPE 2 +#define LISTVIEW_COLUMN_TIME 3 +#define LISTVIEW_COLUMN_ATTRIB 4 + /*menu items */ #define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500) #define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501) @@ -314,6 +321,96 @@ static INT CALLBACK ShellView_CompareItems(LPVOID lParam1, LPVOID lParam2, LPARA return ret; } + +/************************************************************************* + * ShellView_ListViewCompareItems + * + * Compare Function for the Listview (FileOpen Dialog) + * + * PARAMS + * lParam1 [I] the first ItemIdList to compare with + * lParam2 [I] the second ItemIdList to compare with + * lpData [I] The column ID for the header Ctrl to process + * + * RETURNS + * A negative value if the first item should precede the second, + * a positive value if the first item should follow the second, + * or zero if the two items are equivalent + * + * NOTES + * + */ +static INT CALLBACK ShellView_ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData) +{ + INT nDiff=0; + FILETIME fd1, fd2; + char strName1[MAX_PATH], strName2[MAX_PATH]; + BOOL bIsFolder1, bIsFolder2,bIsBothFolder; + LPITEMIDLIST pItemIdList1 = (LPITEMIDLIST) lParam1; + LPITEMIDLIST pItemIdList2 = (LPITEMIDLIST) lParam2; + + + bIsFolder1 = _ILIsFolder(pItemIdList1); + bIsFolder2 = _ILIsFolder(pItemIdList2); + bIsBothFolder = bIsFolder1 && bIsFolder2; + + /* When sorting between a File and a Folder, the Folder gets sorted first */ + if( (bIsFolder1 || bIsFolder2) && !bIsBothFolder) + { + nDiff = bIsFolder1 ? -1 : 1; + } + else + { + /* Sort by Time: Folders or Files can be sorted */ + + if(lpData == LISTVIEW_COLUMN_TIME) + { + _ILGetFileDateTime(pItemIdList1, &fd1); + _ILGetFileDateTime(pItemIdList2, &fd2); + nDiff = CompareFileTime(&fd2, &fd1); + } + /* Sort by Attribute: Folder or Files can be sorted */ + else if(lpData == LISTVIEW_COLUMN_ATTRIB) + { + _ILGetAttributeStr(pItemIdList1, strName1, MAX_PATH); + _ILGetAttributeStr(pItemIdList2, strName2, MAX_PATH); + nDiff = strcasecmp(strName1, strName2); + } + /* Sort by FileName: Folder or Files can be sorted */ + else if(lpData == LISTVIEW_COLUMN_NAME || bIsBothFolder) + { + /* Sort by Text */ + _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH); + _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH); + nDiff = strcasecmp(strName1, strName2); + } + /* Sort by File Size, Only valid for Files */ + else if(lpData == LISTVIEW_COLUMN_SIZE) + { + nDiff = _ILGetFileSize(pItemIdList1, NULL, 0) - _ILGetFileSize(pItemIdList2, NULL, 0); + } + /* Sort by File Type, Only valid for Files */ + else if(lpData == LISTVIEW_COLUMN_TYPE) + { + /* Sort by Type */ + _ILGetFileType(pItemIdList1, strName1, MAX_PATH); + _ILGetFileType(pItemIdList2, strName2, MAX_PATH); + nDiff = strcasecmp(strName1, strName2); + } + } + /* If the Date, FileSize, FileType, Attrib was the same, sort by FileName */ + + if(nDiff == 0) + { + _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH); + _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH); + nDiff = strcasecmp(strName1, strName2); + } + + return nDiff; + +} + /********************************************************** * ShellView_FillList() * @@ -812,6 +909,9 @@ static LRESULT ShellView_OnKillFocus(IShellViewImpl * This) /********************************************************** * ShellView_OnCommand() +* +* NOTES +* the CmdID's are the ones from the context menu */ static LRESULT ShellView_OnCommand(IShellViewImpl * This,DWORD dwCmdID, DWORD dwCmd, HWND hwndCmd) { @@ -839,6 +939,14 @@ static LRESULT ShellView_OnCommand(IShellViewImpl * This,DWORD dwCmdID, DWORD dw SetStyle (This, LVS_REPORT, LVS_TYPEMASK); break; + /* the menu-ID's for sorting are 0x30... see shrec.rc */ + case 0x30: + case 0x31: + case 0x32: + case 0x33: + ListView_SortItems(This->hWndList, ShellView_ListViewCompareItems, (LPARAM) (dwCmdID - 0x30)); + break; + default: TRACE("-- COMMAND 0x%04lx unhandled\n", dwCmdID); } @@ -850,7 +958,7 @@ static LRESULT ShellView_OnCommand(IShellViewImpl * This,DWORD dwCmdID, DWORD dw */ static LRESULT ShellView_OnNotify(IShellViewImpl * This, UINT CtlID, LPNMHDR lpnmh) -{ NM_LISTVIEW *lpnmlv = (NM_LISTVIEW*)lpnmh; +{ LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lpnmh; NMLVDISPINFOA *lpdi = (NMLVDISPINFOA *)lpnmh; LPITEMIDLIST pidl; STRRET str; @@ -888,6 +996,12 @@ static LRESULT ShellView_OnNotify(IShellViewImpl * This, UINT CtlID, LPNMHDR lpn ShellView_DoContextMenu(This, 0, 0, TRUE); break; + case LVN_COLUMNCLICK: + { + ListView_SortItems(lpnmlv->hdr.hwndFrom, ShellView_ListViewCompareItems, (LPARAM) (lpnmlv->iSubItem)); + break; + } + case LVN_GETDISPINFOA: TRACE("-- LVN_GETDISPINFOA %p\n",This); pidl = (LPITEMIDLIST)lpdi->item.lParam; diff --git a/dlls/shell32/shv_bg_cmenu.c b/dlls/shell32/shv_bg_cmenu.c index be0141c0754..735758dae93 100644 --- a/dlls/shell32/shv_bg_cmenu.c +++ b/dlls/shell32/shv_bg_cmenu.c @@ -203,6 +203,10 @@ static HRESULT WINAPI ISVBgCm_fnInvokeCommand( case FCIDM_SHVIEW_REPORTVIEW: SendMessageA(hWndSV, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW,0),0 ); break; + + default: + SendMessageA(hWndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0),0 ); + break; } }