* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * FIXME: The order by part of the background context menu should be
- * built according to the columns shown.
- *
* FIXME: CheckToolbar: handle the "new folder" and "folder up" button
*/
/*
TODO:
- 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
*/
LONG m_iDragOverItem; /* Dragged over item's index, iff m_pCurDropTarget != NULL */
UINT m_cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */
POINT m_ptLastMousePos; /* Mouse position at last DragOver call */
+ POINT m_ptFirstMousePos; /* Mouse position when the drag operation started */
//
CComPtr<IContextMenu> m_pCM;
BOOL m_isEditing;
CLSID m_Category;
- BOOL m_Destroyed;
- private:
+ BOOL m_Destroyed;
+ private:
HRESULT _MergeToolbar();
+ BOOL _Sort();
public:
CDefView();
// Windows returns E_NOINTERFACE for IOleWindow
// COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
+ COM_INTERFACE_ENTRY_IID(IID_CDefView, IShellView)
COM_INTERFACE_ENTRY_IID(IID_IShellView2, IShellView2)
COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
COM_INTERFACE_ENTRY_IID(IID_IShellFolderView, IShellFolderView)
return nDiff;
}
+BOOL CDefView::_Sort()
+{
+ HWND hHeader;
+ HDITEM hColumn;
+
+ if ((m_ListView.GetWindowLongPtr(GWL_STYLE) & ~LVS_NOSORTHEADER) == 0)
+ return TRUE;
+
+ hHeader = (HWND)m_ListView.SendMessage(LVM_GETHEADER, 0, 0);
+ ZeroMemory(&hColumn, sizeof(hColumn));
+
+ /* If the sorting column changed, remove the sorting style from the old column */
+ if ( (m_sortInfo.nLastHeaderID != -1) &&
+ (m_sortInfo.nLastHeaderID != m_sortInfo.nHeaderID) )
+ {
+ hColumn.mask = HDI_FORMAT;
+ Header_GetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
+ hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
+ Header_SetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
+ }
+
+ /* Set the sorting style to the new column */
+ hColumn.mask = HDI_FORMAT;
+ Header_GetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
+
+ hColumn.fmt &= (m_sortInfo.bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP );
+ hColumn.fmt |= (m_sortInfo.bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
+ Header_SetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
+
+ /* Sort the list, using the current values of nHeaderID and bIsAscending */
+ m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
+ return m_ListView.SortItems(ListViewCompareItems, this);
+}
+
PCUITEMID_CHILD CDefView::_PidlByItem(int i)
{
return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i));
FIXME("no m_pSF2Parent\n");
}
m_sortInfo.bIsAscending = TRUE;
- m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
- m_ListView.SortItems(ListViewCompareItems, this);
+ _Sort();
/*turn the listview's redrawing back on and force it to draw*/
m_ListView.SetRedraw(TRUE);
CheckToolbar();
break;
- /* the menu-ID's for sorting are 0x30... see shrec.rc */
+ /* the menu-ID's for sorting are 0x30... see shrec.rc */
case 0x30:
case 0x31:
case 0x32:
case 0x33:
m_sortInfo.nHeaderID = dwCmdID - 0x30;
m_sortInfo.bIsAscending = TRUE;
- m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
- m_ListView.SortItems(ListViewCompareItems, this);
+ _Sort();
break;
case FCIDM_SHVIEW_SNAPTOGRID:
m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
else
m_sortInfo.bIsAscending = TRUE;
- m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
-
- m_ListView.SortItems(ListViewCompareItems, this);
+ _Sort();
break;
case LVN_GETDISPINFOA:
if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
{
+ LPNMLISTVIEW params = (LPNMLISTVIEW)lParam;
+
if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
{
if (dwAttributes & SFGAO_CANLINK)
DWORD dwEffect2;
m_pSourceDataObject = pda;
+ m_ptFirstMousePos = params->ptAction;
+ ClientToScreen(&m_ptFirstMousePos);
+
+ HIMAGELIST big_icons, small_icons;
+ Shell_GetImageLists(&big_icons, &small_icons);
+ PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
+ int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
+ POINT ptItem;
+ m_ListView.GetItemPosition(params->iItem, &ptItem);
+
+ ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
DoDragDrop(pda, this, dwEffect, &dwEffect2);
case SVGIO_BACKGROUND:
if (IsEqualIID(riid, IID_IContextMenu))
{
- //*ppvOut = ISvBgCm_Constructor(m_pSFParent, FALSE);
if (!ppvOut)
hr = E_OUTOFMEMORY;
- IContextMenu* pcm;
- hr = CDefFolderMenu_Create2(NULL, NULL, 0, NULL, m_pSFParent, NULL, 0, NULL, &pcm);
+ hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
- *ppvOut = pcm;
+
}
else if (IsEqualIID(riid, IID_IDispatch))
{
m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
- if (dwFlags & SVSI_EDIT)
+ if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
m_ListView.EditLabel(iItem);
return S_OK;
HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
- LVHITTESTINFO htinfo;
LONG lResult;
HRESULT hr;
RECT clientRect;
/* Map from global to client coordinates and query the index of the listview-item, which is
* currently under the mouse cursor. */
- htinfo.pt.x = pt.x;
- htinfo.pt.y = pt.y;
- htinfo.flags = LVHT_ONITEM;
- ::ScreenToClient(m_ListView, &htinfo.pt);
+ LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
+ ScreenToClient(&htinfo.pt);
lResult = m_ListView.HitTest(&htinfo);
/* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
m_ptLastMousePos = htinfo.pt;
+ /* We need to check if we drag the selection over itself */
+ if (lResult != -1 && m_pSourceDataObject.p != NULL)
+ {
+ PCUITEMID_CHILD pidl = _PidlByItem(lResult);
+
+ for (UINT i = 0; i < m_cidl; i++)
+ {
+ if (pidl == m_apidl[i])
+ {
+ /* The item that is being draged is hovering itself. */
+ lResult = -1;
+ break;
+ }
+ }
+ }
+
/* If we are still over the previous sub-item, notify it via DragOver and return. */
if (m_pCurDropTarget && lResult == m_iDragOverItem)
return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
/* We've left the previous sub-item, notify it via DragLeave and Release it. */
if (m_pCurDropTarget)
{
+ PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem);
+ if (pidl)
+ SelectItem(pidl, 0);
+
m_pCurDropTarget->DragLeave();
m_pCurDropTarget.Release();
}
m_iDragOverItem = lResult;
+
if (lResult == -1)
{
/* We are not above one of the listview's subitems. Bind to the parent folder's
/* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
if (FAILED(hr))
+ {
+ *pdwEffect = DROPEFFECT_NONE;
return hr;
+ }
+
+ if (m_iDragOverItem != -1)
+ {
+ SelectItem(m_iDragOverItem, SVSI_SELECT);
+ }
/* Notify the item just entered via DragEnter. */
return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
{
/* Get a hold on the data object for later calls to DragEnter on the sub-folders */
m_pCurDataObject = pDataObject;
- pDataObject->AddRef();
- return drag_notify_subitem(grfKeyState, pt, pdwEffect);
+ HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
+ if (SUCCEEDED(hr))
+ {
+ POINT ptClient = {pt.x, pt.y};
+ ScreenToClient(&ptClient);
+ ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
+ }
+
+ return hr;
}
HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
+ POINT ptClient = {pt.x, pt.y};
+ ScreenToClient(&ptClient);
+ ImageList_DragMove(ptClient.x, ptClient.y);
return drag_notify_subitem(grfKeyState, pt, pdwEffect);
}
HRESULT WINAPI CDefView::DragLeave()
{
+ ImageList_DragLeave(m_hWnd);
+
if (m_pCurDropTarget)
{
m_pCurDropTarget->DragLeave();
{
ERR("GetKeyState(VK_LBUTTON): %d\n", GetKeyState(VK_LBUTTON));
- if ((m_iDragOverItem == -1) &&
+ ImageList_DragLeave(m_hWnd);
+ ImageList_EndDrag();
+
+ if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
(*pdwEffect & DROPEFFECT_MOVE) &&
- (GetKeyState(VK_LBUTTON) != 0) &&
+ /*(GetKeyState(VK_LBUTTON) != 0) &&*/
(m_pSourceDataObject.p) &&
(SHIsSameObject(pDataObject, m_pSourceDataObject)))
{
- ERR("Should implement moving items here!\n");
-
if (m_pCurDropTarget)
{
m_pCurDropTarget->DragLeave();
m_pCurDropTarget.Release();
}
+
+ /* Restore the selection */
+ m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
+ for (UINT i = 0 ; i < m_cidl; i++)
+ SelectItem(m_apidl[i], SVSI_SELECT);
+
+ /* Reposition the items */
+ int lvIndex = -1;
+ while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
+ {
+ POINT ptItem;
+ if (m_ListView.GetItemPosition(lvIndex, &ptItem))
+ {
+ ptItem.x += pt.x - m_ptFirstMousePos.x;
+ ptItem.y += pt.y - m_ptFirstMousePos.y;
+ m_ListView.SetItemPosition(lvIndex, &ptItem);
+ }
+ }
}
else if (m_pCurDropTarget)
{
return S_OK;
}
-/**********************************************************
- * IShellView_Constructor
- */
-HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
+
+HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
{
- return ShellObjectCreatorInit<CDefView>(pFolder, IID_IShellView, newView);
+ return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
}
-HRESULT WINAPI CDefView_Constructor(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
+HRESULT WINAPI SHCreateShellFolderViewEx(
+ LPCSFV psvcbi, /* [in] shelltemplate struct */
+ IShellView **ppsv) /* [out] IShellView pointer */
{
- return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
+ CComPtr<IShellView> psv;
+ HRESULT hRes;
+
+ TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
+ psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
+ psvcbi->fvm, psvcbi->psvOuter);
+
+ *ppsv = NULL;
+ hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
+ if (FAILED_UNEXPECTEDLY(hRes))
+ return hRes;
+
+ *ppsv = psv.Detach();
+ return hRes;
+}
+
+HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
+ IShellView **ppsv)
+{
+ CComPtr<IShellView> psv;
+ HRESULT hRes;
+
+ *ppsv = NULL;
+ if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
+ return E_INVALIDARG;
+
+ TRACE("sf=%p outer=%p callback=%p\n",
+ pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
+
+ hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
+ if (FAILED(hRes))
+ return hRes;
+
+ *ppsv = psv.Detach();
+ return hRes;
}