[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / CDefView.cpp
index f7f420c..035d73e 100644 (file)
  * built according to the columns shown.
  *
  * FIXME: CheckToolbar: handle the "new folder" and "folder up" button
- *
- * FIXME: ShellView_FillList: consider sort orders
  */
 
 /*
 TODO:
-1. Load/Save the view state from/into the stream provided by the ShellBrowser.
-2. Let the shell folder sort items.
-3. Code to merge menus in the shellbrowser is incorrect.
-4. Move the background context menu creation into shell view. It should store the
-    shell view HWND to send commands.
-5. Send init, measure, and draw messages to context menu during tracking.
-6. Shell view should do SetCommandTarget on internet toolbar.
-7. When editing starts on item, set edit text to for editing value.
-8. When shell view is called back for item info, let listview save the value.
-9. Shell view should update status bar.
-10. Fix shell view to handle view mode popup exec.
-11. The background context menu should have a pidl just like foreground menus. This
-    causes crashes when dynamic handlers try to use the NULL pidl.
-12. The SHELLDLL_DefView should not be filled with blue unconditionally. This causes
-    annoying flashing of blue even on XP, and is not correct.
-13. Reorder of columns doesn't work - might be bug in comctl32
+- Load/Save the view state from/into the stream provided by the ShellBrowser.
+- Code to merge menus in the shellbrowser is incorrect.
+- Move the background context menu creation into shell view. It should store the
+   shell view HWND to send commands.
+- Shell view should do SetCommandTarget on internet toolbar.
+- When editing starts on item, set edit text to for editing value.
+- When shell view is called back for item info, let listview save the value.
+- Fix shell view to handle view mode popup exec.
+- The background context menu should have a pidl just like foreground menus. This
+   causes crashes when dynamic handlers try to use the NULL pidl.
+- The SHELLDLL_DefView should not be filled with blue unconditionally. This causes
+   annoying flashing of blue even on XP, and is not correct.
+- Reorder of columns doesn't work - might be bug in comctl32
 */
 
 #include "precomp.h"
@@ -92,7 +87,7 @@ class CDefView :
         BOOL                      m_menusLoaded;
         UINT                      m_uState;
         UINT                      m_cidl;
-        PCUITEMID_CHILD_ARRAY     m_apidl;
+        PCUITEMID_CHILD          *m_apidl;
         PIDLIST_ABSOLUTE          m_pidlParent;
         LISTVIEW_SORT_INFO        m_sortInfo;
         ULONG                     m_hNotify;            /* change notification handle */
@@ -125,12 +120,12 @@ class CDefView :
         HRESULT IncludeObject(PCUITEMID_CHILD pidl);
         HRESULT OnDefaultCommand();
         HRESULT OnStateChange(UINT uFlags);
+        void UpdateStatusbar();
         void CheckToolbar();
         void SetStyle(DWORD dwAdd, DWORD dwRemove);
         BOOL CreateList();
         void UpdateListColors();
         BOOL InitList();
-        static INT CALLBACK CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
         static INT CALLBACK ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData);
 
         PCUITEMID_CHILD _PidlByItem(int i);
@@ -150,6 +145,7 @@ class CDefView :
         void OnDeactivate();
         void DoActivate(UINT uState);
         HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
+        HRESULT InvokeContextMenuCommand(UINT uCommand);
         LRESULT OnExplorerCommand(UINT uCommand, BOOL bUseSelection);
 
         // *** IOleWindow methods ***
@@ -270,7 +266,7 @@ class CDefView :
             {
                 {   sizeof(WNDCLASSEX), 0, StartWindowProc,
                     0, 0, NULL, NULL,
-                    LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_BACKGROUND + 1), NULL, SV_CLASS_NAME, NULL
+                    LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, SV_CLASS_NAME, NULL
                 },
                 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
             };
@@ -333,13 +329,6 @@ class CDefView :
         END_COM_MAP()
 };
 
-/* 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)
@@ -469,6 +458,26 @@ void CDefView::CheckToolbar()
     }
 }
 
+void CDefView::UpdateStatusbar()
+{
+    WCHAR szFormat[MAX_PATH] = {0};
+    WCHAR szObjects[MAX_PATH] = {0};
+    UINT cSelectedItems;
+
+    cSelectedItems = m_ListView.GetSelectedCount();
+    if (cSelectedItems)
+    {
+        LoadStringW(shell32_hInstance, IDS_OBJECTS_SELECTED, szFormat, _countof(szFormat));
+        StringCchPrintfW(szObjects, MAX_PATH, szFormat, cSelectedItems);
+    }
+    else
+    {
+        LoadStringW(shell32_hInstance, IDS_OBJECTS, szFormat, _countof(szFormat));
+        StringCchPrintfW(szObjects, MAX_PATH, szFormat, m_ListView.GetItemCount());
+    }
+    m_pShellBrowser->SetStatusTextSB(szObjects);
+}
+
 /**********************************************************
  *
  * ##### helperfunctions for initializing the view #####
@@ -626,30 +635,6 @@ BOOL CDefView::InitList()
     return TRUE;
 }
 
-/**********************************************************
-* ShellView_CompareItems()
-*
-* NOTES
-*  internal, CALLBACK for DSA_Sort
-*/
-INT CALLBACK CDefView::CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
-{
-    int ret;
-    TRACE("pidl1=%p pidl2=%p lpsf=%p\n", lParam1, lParam2, (LPVOID) lpData);
-
-    if (!lpData)
-        return 0;
-
-    IShellFolder* psf = reinterpret_cast<IShellFolder*>(lpData);
-    PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1);
-    PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2);
-
-    ret = (SHORT)SCODE_CODE(psf->CompareIDs(0, pidl1, pidl2));
-    TRACE("ret=%i\n", ret);
-
-    return ret;
-}
-
 /*************************************************************************
  * ShellView_ListViewCompareItems
  *
@@ -664,89 +649,20 @@ INT CALLBACK CDefView::CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpDat
  *     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
- *    FIXME: function does what ShellView_CompareItems is supposed to do.
- *    unify it and figure out how to use the undocumented first parameter
- *    of IShellFolder_CompareIDs to do the job this function does and
- *    move this code to IShellFolder.
- *    make LISTVIEW_SORT_INFO obsolete
- *    the way this function works is only usable if we had only
- *    filesystemfolders  (25/10/99 jsch)
  */
 INT CALLBACK CDefView::ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
 {
-    INT nDiff = 0;
-    FILETIME fd1, fd2;
-    char strName1[MAX_PATH], strName2[MAX_PATH];
-    BOOL bIsFolder1, bIsFolder2, bIsBothFolder;
     PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1);
     PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2);
-    LISTVIEW_SORT_INFO *pSortInfo = reinterpret_cast<LPLISTVIEW_SORT_INFO>(lpData);
-
-
-    bIsFolder1 = _ILIsFolder(pidl1);
-    bIsFolder2 = _ILIsFolder(pidl2);
-    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(pSortInfo->nHeaderID == LISTVIEW_COLUMN_TIME)
-        {
-            _ILGetFileDateTime(pidl1, &fd1);
-            _ILGetFileDateTime(pidl2, &fd2);
-            nDiff = CompareFileTime(&fd2, &fd1);
-        }
-        /* Sort by Attribute: Folder or Files can be sorted */
-        else if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_ATTRIB)
-        {
-            _ILGetFileAttributes(pidl1, strName1, MAX_PATH);
-            _ILGetFileAttributes(pidl2, strName2, MAX_PATH);
-            nDiff = lstrcmpiA(strName1, strName2);
-        }
-        /* Sort by FileName: Folder or Files can be sorted */
-        else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_NAME || bIsBothFolder)
-        {
-            /* Sort by Text */
-            _ILSimpleGetText(pidl1, strName1, MAX_PATH);
-            _ILSimpleGetText(pidl2, strName2, MAX_PATH);
-            nDiff = lstrcmpiA(strName1, strName2);
-        }
-        /* Sort by File Size, Only valid for Files */
-        else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_SIZE)
-        {
-            nDiff = (INT)(_ILGetFileSize(pidl1, NULL, 0) - _ILGetFileSize(pidl2, NULL, 0));
-        }
-        /* Sort by File Type, Only valid for Files */
-        else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_TYPE)
-        {
-            /* Sort by Type */
-            _ILGetFileType(pidl1, strName1, MAX_PATH);
-            _ILGetFileType(pidl2, strName2, MAX_PATH);
-            nDiff = lstrcmpiA(strName1, strName2);
-        }
-    }
-    /*  If the Date, FileSize, FileType, Attrib was the same, sort by FileName */
+    CDefView *pThis = reinterpret_cast<CDefView*>(lpData);
 
-    if (nDiff == 0)
-    {
-        _ILSimpleGetText(pidl1, strName1, MAX_PATH);
-        _ILSimpleGetText(pidl2, strName2, MAX_PATH);
-        nDiff = lstrcmpiA(strName1, strName2);
-    }
+    HRESULT hres = pThis->m_pSFParent->CompareIDs(pThis->m_sortInfo.nHeaderID, pidl1, pidl2);
+    if (FAILED_UNEXPECTEDLY(hres))
+        return 0;
 
-    if (!pSortInfo->bIsAscending)
-    {
+    SHORT nDiff = HRESULT_CODE(hres);
+    if (!pThis->m_sortInfo.bIsAscending)
         nDiff = -nDiff;
-    }
-
     return nDiff;
 }
 
@@ -833,11 +749,13 @@ BOOLEAN CDefView::LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew
     {
         lvItem.mask = LVIF_PARAM;        /* only the pidl */
         lvItem.iItem = nItem;
+        lvItem.iSubItem = 0;
         m_ListView.GetItem(&lvItem);
 
         SHFree(reinterpret_cast<LPVOID>(lvItem.lParam));
         lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
         lvItem.iItem = nItem;
+        lvItem.iSubItem = 0;
         lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew));    /* set the item's data */
         lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
         m_ListView.SetItem(&lvItem);
@@ -864,6 +782,7 @@ BOOLEAN CDefView::LV_ProdItem(PCUITEMID_CHILD pidl)
     {
         lvItem.mask = LVIF_IMAGE;
         lvItem.iItem = nItem;
+        lvItem.iSubItem = 0;
         lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
         m_ListView.SetItem(&lvItem);
         m_ListView.Update(nItem);
@@ -950,14 +869,17 @@ HRESULT CDefView::FillList()
         }
     }
 
-    /* sort the array */
-    DPA_Sort(hdpa, CompareItems, reinterpret_cast<LPARAM>(m_pSFParent.p));
-
     /*turn the listview's redrawing off*/
     m_ListView.SetRedraw(FALSE);
 
     DPA_DestroyCallback( hdpa, fill_list, this);
 
+    /* sort the array */
+    m_pSF2Parent->GetDefaultColumn(NULL, (ULONG*)&m_sortInfo.nHeaderID, NULL);
+    m_sortInfo.bIsAscending = TRUE;
+    m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
+    m_ListView.SortItems(ListViewCompareItems, this);
+
     /*turn the listview's redrawing back on and force it to draw*/
     m_ListView.SetRedraw(TRUE);
 
@@ -1071,6 +993,8 @@ LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
 
     m_hAccel = LoadAcceleratorsW(shell32_hInstance, MAKEINTRESOURCEW(IDA_SHELLVIEW));
 
+    UpdateStatusbar();
+
     return S_OK;
 }
 
@@ -1204,7 +1128,7 @@ UINT CDefView::GetSelections()
     SHFree(m_apidl);
 
     m_cidl = m_ListView.GetSelectedCount();
-    m_apidl = reinterpret_cast<PCUITEMID_CHILD_ARRAY>(SHAlloc(m_cidl * sizeof(PCUITEMID_CHILD)));
+    m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(m_cidl * sizeof(PCUITEMID_CHILD)));
     if (!m_apidl)
     {
         m_cidl = 0;
@@ -1227,13 +1151,30 @@ UINT CDefView::GetSelections()
     return m_cidl;
 }
 
+HRESULT CDefView::InvokeContextMenuCommand(UINT uCommand)
+{
+    CMINVOKECOMMANDINFO cmi;
+
+    ZeroMemory(&cmi, sizeof(cmi));
+    cmi.cbSize = sizeof(cmi);
+    cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
+    cmi.hwnd = m_hWnd;
+
+    if (GetKeyState(VK_SHIFT) & 0x8000)
+        cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
+
+    if (GetKeyState(VK_CONTROL) & 0x8000)
+        cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
+
+    return m_pCM->InvokeCommand(&cmi);
+}
+
 /**********************************************************
  *    ShellView_OpenSelectedItems()
  */
 HRESULT CDefView::OpenSelectedItems()
 {
     HMENU hMenu;
-    CMINVOKECOMMANDINFO cmi;
     UINT uCommand;
     HRESULT hResult;
 
@@ -1264,12 +1205,7 @@ HRESULT CDefView::OpenSelectedItems()
         goto cleanup;
     }
 
-    ZeroMemory(&cmi, sizeof(cmi));
-    cmi.cbSize = sizeof(cmi);
-    cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
-    cmi.hwnd = m_hWnd;
-
-    hResult = m_pCM->InvokeCommand(&cmi);
+    InvokeContextMenuCommand(uCommand);
 
 cleanup:
     
@@ -1291,7 +1227,6 @@ LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
     WORD                 y;
     UINT                 uCommand;
     HMENU                hMenu;
-    CMINVOKECOMMANDINFO  cmi;
     HRESULT              hResult;
 
     // for some reason I haven't figured out, we sometimes recurse into this method
@@ -1317,9 +1252,6 @@ LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
     if (FAILED( hResult))
         goto cleanup;
 
-    if (m_FolderSettings.fFlags & FWF_DESKTOP)
-        SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
-
     uCommand = TrackPopupMenu(hMenu,
                               TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
                               x, y, 0, m_hWnd, NULL);
@@ -1329,14 +1261,9 @@ LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
     if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
         goto cleanup;
 
-    ZeroMemory(&cmi, sizeof(cmi));
-    cmi.cbSize = sizeof(cmi);
-    cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
-    cmi.hwnd = m_hWnd;
-    m_pCM->InvokeCommand(&cmi);
+    InvokeContextMenuCommand(uCommand);
 
 cleanup:
-    
     if (m_pCM)
         m_pCM.Release();
 
@@ -1349,7 +1276,6 @@ cleanup:
 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
 {
     HRESULT hResult;
-    CMINVOKECOMMANDINFO cmi;
     HMENU hMenu;
 
     hMenu = CreatePopupMenu();
@@ -1364,14 +1290,9 @@ LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
     if (FAILED( hResult))
         goto cleanup;
 
-    ZeroMemory(&cmi, sizeof(cmi));
-    cmi.cbSize = sizeof(cmi);
-    cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
-    cmi.hwnd = m_hWnd;
-    m_pCM->InvokeCommand(&cmi);
+    InvokeContextMenuCommand(uCommand);
 
 cleanup:
-
     if (m_pCM)
         m_pCM.Release();
 
@@ -1634,7 +1555,7 @@ LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHand
             m_sortInfo.nHeaderID = dwCmdID - 0x30;
             m_sortInfo.bIsAscending = TRUE;
             m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
-            m_ListView.SortItems(ListViewCompareItems, &m_sortInfo);
+            m_ListView.SortItems(ListViewCompareItems, this);
             break;
 
         case FCIDM_SHVIEW_SELECTALL:
@@ -1764,7 +1685,7 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
                 m_sortInfo.bIsAscending = TRUE;
             m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
 
-            m_ListView.SortItems(ListViewCompareItems, &m_sortInfo);
+            m_ListView.SortItems(ListViewCompareItems, this);
             break;
 
         case LVN_GETDISPINFOA:
@@ -1822,6 +1743,7 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
         case LVN_ITEMCHANGED:
             TRACE("-- LVN_ITEMCHANGED %p\n", this);
             OnStateChange(CDBOSC_SELCHANGE);  /* the browser will get the IDataObject now */
+            UpdateStatusbar();
             break;
 
         case LVN_BEGINDRAG:
@@ -1891,6 +1813,7 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
                 {
                     lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
                     lvItem.iItem = lpdi->item.iItem;
+                    lvItem.iSubItem = 0;
                     lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
                     lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
                     m_ListView.SetItem(&lvItem);
@@ -1955,7 +1878,7 @@ LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &
 
     TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
 
-    switch (lParam)
+    switch (lParam &~ SHCNE_INTERRUPT)
     {
         case SHCNE_MKDIR:
         case SHCNE_CREATE:
@@ -3110,3 +3033,8 @@ HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newVie
 {
     return ShellObjectCreatorInit<CDefView>(pFolder, IID_IShellView, newView);
 }
+
+HRESULT WINAPI CDefView_Constructor(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
+{
+    return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
+}