[SHELL32][BOOTDATA] Unselect filename extension upon renaming (#2398)
[reactos.git] / dll / win32 / shell32 / CDefView.cpp
index 1485e16..f2cb361 100644 (file)
@@ -135,7 +135,7 @@ class CDefView :
         PCUITEMID_CHILD _PidlByItem(int i);
         PCUITEMID_CHILD _PidlByItem(LVITEM& lvItem);
         int LV_FindItemByPidl(PCUITEMID_CHILD pidl);
-        BOOLEAN LV_AddItem(PCUITEMID_CHILD pidl);
+        int LV_AddItem(PCUITEMID_CHILD pidl);
         BOOLEAN LV_DeleteItem(PCUITEMID_CHILD pidl);
         BOOLEAN LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew);
         BOOLEAN LV_ProdItem(PCUITEMID_CHILD pidl);
@@ -633,19 +633,16 @@ void CDefView::UpdateListColors()
     else
     {
         // text background color
-        COLORREF clrTextBack = GetSysColor(COLOR_WINDOW);
-        if (m_viewinfo_data.clrTextBack != CLR_INVALID)
-        {
-            clrTextBack = m_viewinfo_data.clrTextBack;
-        }
+        COLORREF clrTextBack = m_viewinfo_data.clrTextBack;
         m_ListView.SetTextBkColor(clrTextBack);
 
         // text color
-        COLORREF clrText = GetSysColor(COLOR_WINDOWTEXT);
+        COLORREF clrText;
         if (m_viewinfo_data.clrText != CLR_INVALID)
-        {
             clrText = m_viewinfo_data.clrText;
-        }
+        else
+            clrText = GetSysColor(COLOR_WINDOWTEXT);
+
         m_ListView.SetTextColor(clrText);
 
         // Background is painted by the parent via WM_PRINTCLIENT.
@@ -794,7 +791,7 @@ int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl)
 /**********************************************************
 * LV_AddItem()
 */
-BOOLEAN CDefView::LV_AddItem(PCUITEMID_CHILD pidl)
+int CDefView::LV_AddItem(PCUITEMID_CHILD pidl)
 {
     LVITEMW lvItem;
 
@@ -808,10 +805,7 @@ BOOLEAN CDefView::LV_AddItem(PCUITEMID_CHILD pidl)
     lvItem.iImage = I_IMAGECALLBACK;                      /*get the image on a callback basis*/
     lvItem.stateMask = LVIS_CUT;
 
-    if (m_ListView.InsertItem(&lvItem) == -1)
-        return FALSE;
-    else
-        return TRUE;
+    return m_ListView.InsertItem(&lvItem);
 }
 
 /**********************************************************
@@ -914,29 +908,32 @@ HRESULT CDefView::FillList()
     DWORD         dwFetched;
     HRESULT       hRes;
     HDPA          hdpa;
-    HKEY          hKey;
     DWORD         dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS;
+    DWORD dwValue, cbValue;
 
     TRACE("%p\n", this);
 
     /* determine if there is a setting to show all the hidden files/folders */
-    if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+    dwValue = 1;
+    cbValue = sizeof(dwValue);
+    SHGetValueW(HKEY_CURRENT_USER,
+                L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
+                L"Hidden", NULL, &dwValue, &cbValue);
+    if (dwValue == 1)
     {
-        DWORD dataLength, flagVal;
-
-        dataLength = sizeof(flagVal);
-        if (RegQueryValueExW(hKey, L"Hidden", NULL, NULL, (LPBYTE)&flagVal, &dataLength) == ERROR_SUCCESS)
-        {
-            /* if the value is 1, then show all hidden files/folders */
-            if (flagVal == 1)
-            {
-                dFlags |= SHCONTF_INCLUDEHIDDEN;
-                m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
-            }
-        }
+        dFlags |= SHCONTF_INCLUDEHIDDEN;
+        m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
+    }
 
-        /* close the key */
-        RegCloseKey(hKey);
+    dwValue = 0;
+    cbValue = sizeof(dwValue);
+    SHGetValueW(HKEY_CURRENT_USER,
+                L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
+                L"ShowSuperHidden", NULL, &dwValue, &cbValue);
+    if (dwValue)
+    {
+        dFlags |= SHCONTF_INCLUDESUPERHIDDEN;
+        m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
     }
 
     /* get the itemlist from the shfolder */
@@ -1210,8 +1207,11 @@ HRESULT CDefView::FillFileMenu()
             DeleteMenu(hFileMenu, i, MF_BYPOSITION);
     }
 
+    m_cidl = m_ListView.GetSelectedCount();
+
     /* Store the context menu in m_pCM and keep it in order to invoke the selected command later on */
-    HRESULT hr = GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pCM));
+    HRESULT hr = GetItemObject((m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND),
+                               IID_PPV_ARG(IContextMenu, &m_pCM));
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
@@ -1432,6 +1432,24 @@ LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
     if (!m_hContextMenu) 
         return E_FAIL;
 
+    if (lParam != ~0)   // unless app key (menu key) was pressed
+    {
+        x = GET_X_LPARAM(lParam);
+        y = GET_Y_LPARAM(lParam);
+
+        LV_HITTESTINFO hittest = { { x, y } };
+        ScreenToClient(&hittest.pt);
+        m_ListView.HitTest(&hittest);
+
+        // Right-Clicked item is selected? If selected, no selection change.
+        // If not selected, then reset the selection and select the item.
+        if ((hittest.flags & LVHT_ONITEM) &&
+            m_ListView.GetItemState(hittest.iItem, LVIS_SELECTED) != LVIS_SELECTED)
+        {
+            SelectItem(hittest.iItem, SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE);
+        }
+    }
+
     m_cidl = m_ListView.GetSelectedCount();
 
     hResult = GetItemObject( m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
@@ -1446,15 +1464,19 @@ LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
     /* There is no position requested, so try to find one */
     if (lParam == ~0)
     {
-        int lvIndex;
+        HWND hFocus = ::GetFocus();
+        int lvIndex = -1;
         POINT pt;
 
-        /* Do we have a focused item, */
-        if ((lvIndex = m_ListView.GetNextItem(-1, LVIS_FOCUSED)) < 0)
+        if (hFocus == m_ListView.m_hWnd || m_ListView.IsChild(hFocus))
         {
-            /* or a selected item? */
-            lvIndex = m_ListView.GetNextItem(-1, LVIS_SELECTED);
+            /* Is there an item focused and selected? */
+            lvIndex = m_ListView.GetNextItem(-1, LVIS_SELECTED|LVIS_FOCUSED);
+            /* If not, find the first selected item */
+            if (lvIndex < 0)
+                lvIndex = m_ListView.GetNextItem(-1, LVIS_SELECTED);
         }
+
         /* We got something */
         if (lvIndex > -1)
         {
@@ -1474,11 +1496,6 @@ LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
         x = pt.x;
         y = pt.y;
     }
-    else
-    {
-        x = GET_X_LPARAM(lParam);
-        y = GET_Y_LPARAM(lParam);
-    }
 
     uCommand = TrackPopupMenu(m_hContextMenu,
                               TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
@@ -1766,6 +1783,26 @@ LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHand
     return 0;
 }
 
+static BOOL
+SelectExtOnRename(void)
+{
+    HKEY hKey;
+    LONG error;
+    DWORD dwValue = FALSE, cbValue;
+
+    error = RegOpenKeyExW(HKEY_CURRENT_USER,
+                          L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer",
+                          0, KEY_READ, &hKey);
+    if (error)
+        return dwValue;
+
+    cbValue = sizeof(dwValue);
+    RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue);
+
+    RegCloseKey(hKey);
+    return !!dwValue;
+}
+
 /**********************************************************
 * ShellView_OnNotify()
 */
@@ -1975,9 +2012,21 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
             m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
             if (SFGAO_CANRENAME & dwAttr)
             {
+                HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
+                SHLimitInputEdit(hEdit, m_pSFParent);
+
+                if (!(dwAttr & SFGAO_LINK) && (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename())
+                {
+                    LPWSTR pszText = lpdi->item.pszText;
+                    LPWSTR pchDotExt = PathFindExtensionW(pszText);
+                    ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
+                    ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0);
+                }
+
                 m_isEditing = TRUE;
                 return FALSE;
             }
+
             return TRUE;
         }
 
@@ -2381,9 +2430,6 @@ HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags)
     if (i == -1)
         return S_OK;
 
-    if(uFlags & SVSI_ENSUREVISIBLE)
-        m_ListView.EnsureVisible(i, FALSE);
-
     LVITEMW lvItem = {0};
     lvItem.mask = LVIF_STATE;
     lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
@@ -2398,18 +2444,26 @@ HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags)
                 lvItem.state &= ~LVIS_SELECTED;
 
             if (uFlags & SVSI_FOCUSED)
+                lvItem.state |= LVIS_FOCUSED;
+            else
                 lvItem.state &= ~LVIS_FOCUSED;
         }
         else
         {
             if (uFlags & SVSI_DESELECTOTHERS)
+            {
                 lvItem.state &= ~LVIS_SELECTED;
+            }
+            lvItem.state &= ~LVIS_FOCUSED;
         }
 
         m_ListView.SetItem(&lvItem);
         lvItem.iItem++;
     }
 
+    if (uFlags & SVSI_ENSUREVISIBLE)
+        m_ListView.EnsureVisible(i, FALSE);
+
     if((uFlags & SVSI_EDIT) == SVSI_EDIT)
         m_ListView.EditLabel(i);
 
@@ -2422,6 +2476,9 @@ HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
 
     TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
 
+    if (!ppvOut)
+        return E_INVALIDARG;
+
     *ppvOut = NULL;
 
     switch (uItem)
@@ -2429,9 +2486,6 @@ HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
         case SVGIO_BACKGROUND:
             if (IsEqualIID(riid, IID_IContextMenu))
             {
-                if (!ppvOut)
-                    hr = E_OUTOFMEMORY;
-
                 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut);
                 if (FAILED_UNEXPECTEDLY(hr))
                     return hr;
@@ -2806,8 +2860,9 @@ HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
 
 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
 {
-    FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p %p)\n", this, pidl, item);
+    *item = LV_AddItem(pidl);
+    return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
 }
 
 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
@@ -3187,6 +3242,9 @@ HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEf
 
 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
 {
+    if (*pdwEffect == DROPEFFECT_NONE)
+        return S_OK;
+
     /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
     m_pCurDataObject = pDataObject;
 
@@ -3452,7 +3510,11 @@ HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
     CComPtr<IShellView> psv;
     HRESULT hRes;
 
+    if (!ppsv)
+        return E_INVALIDARG;
+
     *ppsv = NULL;
+
     if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
         return E_INVALIDARG;