|
|
//*******************************************************************************************
//
// Filename : SFVWnd.cpp
//
// Implementation file for CSFVDropSource and CSFViewDlg
//
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
//
//*******************************************************************************************
#include "Pch.H"
#include "SFVWnd.H"
#include "ThisDll.h"
#include "Resource.H"
class CSFVDropSource : public CUnknown, public IDropSource { public: CSFVDropSource() : m_grfInitialKeyState(0) {} virtual ~CSFVDropSource();
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release();
STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState); STDMETHODIMP GiveFeedback(DWORD dwEffect);
private: DWORD m_grfInitialKeyState; } ;
CSFVDropSource::~CSFVDropSource() { }
STDMETHODIMP CSFVDropSource::QueryInterface(REFIID riid, LPVOID * ppvObj) { static const IID *apiid[] = { &IID_IDropSource, NULL }; LPUNKNOWN aobj[] = { (IDropSource *)this };
return(QIHelper(riid, ppvObj, apiid, aobj)); }
STDMETHODIMP_(ULONG) CSFVDropSource::AddRef() { return(AddRefHelper()); }
STDMETHODIMP_(ULONG) CSFVDropSource::Release() { return(ReleaseHelper()); }
STDMETHODIMP CSFVDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { if (fEscapePressed) { return(DRAGDROP_S_CANCEL); }
// initialize ourself with the drag begin button
if (m_grfInitialKeyState == 0) { m_grfInitialKeyState = (grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)); }
if (!(grfKeyState & m_grfInitialKeyState)) { return(DRAGDROP_S_DROP); }
return(S_OK); }
STDMETHODIMP CSFVDropSource::GiveFeedback(DWORD dwEffect) { return(DRAGDROP_S_USEDEFAULTCURSORS); }
// Note that the OLESTR gets freed, so don't try to use it later
BOOL StrRetToStr(LPSTR szOut, UINT uszOut, LPSTRRET pStrRet, LPCITEMIDLIST pidl) { switch (pStrRet->uType) { case STRRET_OLESTR: { CSafeMalloc sm;
OleStrToStrN(szOut, uszOut, pStrRet->pOleStr, -1); sm.Free(pStrRet->pOleStr);
break; }
case STRRET_CSTR: lstrcpyn(szOut, pStrRet->cStr, uszOut); break;
case STRRET_OFFSET: if (pidl) { lstrcpyn(szOut, ((LPCSTR)&pidl->mkid)+pStrRet->uOffset, uszOut); break; }
// Fall through
default: if (uszOut) { *szOut = '\0'; } return(FALSE); }
return(TRUE); }
static void _PrettyMenu(HMENU hm) { BOOL bSeparated = TRUE; int i;
for (i=GetMenuItemCount(hm)-1; i>0; --i) { if (CSFViewDlg::IsMenuSeparator(hm, i)) { if (bSeparated) { DeleteMenu(hm, i, MF_BYPOSITION); }
bSeparated = TRUE; } else { bSeparated = FALSE; } }
// The above loop does not handle the case of many separators at
// the beginning of the menu
while (CSFViewDlg::IsMenuSeparator(hm, 0)) { DeleteMenu(hm, 0, MF_BYPOSITION); } }
static HMENU _LoadPopupMenu(UINT id, UINT uSubMenu) { HMENU hmParent = LoadMenu(g_ThisDll.GetInstance(), MAKEINTRESOURCE(id)); if (!hmParent) { return(NULL); }
HMENU hmPopup = GetSubMenu(hmParent, 0); RemoveMenu(hmParent, uSubMenu, MF_BYPOSITION); DestroyMenu(hmParent);
return(hmPopup); }
void CSFViewDlg::InitDialog() { m_cList.Init(GetDlgItem(m_hDlg, IDC_LISTVIEW), GetDlgItem(m_hDlg, IDC_LISTBOX), IDI_GENERIC);
SetWindowLong(m_cList, GWL_EXSTYLE, GetWindowLong(m_cList, GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
m_hrOLE = OleInitialize(NULL); }
LRESULT CSFViewDlg::BeginDrag() { if (!OleInited()) { return(0); }
// Get the dwEffect from the selection.
ULONG dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY; GetAttributesFromItem(&dwEffect, SVGIO_SELECTION);
// Just in case
dwEffect &= DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY; if (!dwEffect) { return(0); }
LPDATAOBJECT pdtobj; if (FAILED(GetUIObjectFromItem(IID_IDataObject, (LPVOID*)&pdtobj, SVGIO_SELECTION))) { return(0); } CEnsureRelease erData(pdtobj);
CSFVDropSource *pcsrc = new CSFVDropSource; if (!pcsrc) { return(0); } pcsrc->AddRef(); CEnsureRelease erCDSrc((IDropSource*)pcsrc);
IDropSource *pdsrc; HRESULT hres = pcsrc->QueryInterface(IID_IDropSource, (LPVOID*)&pdsrc); if (FAILED(hres)) { return(0); } CEnsureRelease erPDSrc(pdsrc);
DoDragDrop(pdtobj, pdsrc, dwEffect, &dwEffect);
return(0); }
BOOL CSFViewDlg::Notify(LPNMHDR pNotify) { LPNM_LISTVIEW pNotifyLV = (LPNM_LISTVIEW)pNotify; LV_DISPINFO *pNotifyDI = (LV_DISPINFO *)pNotify; LPTBNOTIFY pNotifyTB = (LPTBNOTIFY)pNotify; LPTOOLTIPTEXT pNotifyTT = (LPTOOLTIPTEXT)pNotify;
switch(pNotify->code) { case TTN_NEEDTEXT: m_psfv->GetCommandHelpText(pNotifyTT->hdr.idFrom, pNotifyTT->szText, sizeof(pNotifyTT->szText), TRUE); break;
case TBN_BEGINDRAG: m_psfv->OnMenuSelect(pNotifyTB->iItem, 0, 0); break;
case LVN_DELETEITEM: m_psfv->m_cMalloc.Free((LPITEMIDLIST)pNotifyLV->lParam); break;
case LVN_GETDISPINFO: if (pNotifyDI->item.iSubItem == 0) { LPCITEMIDLIST pidl = (LPCITEMIDLIST)pNotifyDI->item.lParam; if (pNotifyDI->item.mask & LVIF_TEXT) { STRRET strret;
if (FAILED(m_psfv->m_psf->GetDisplayNameOf(pidl, 0, &strret))) { lstrcpyn(pNotifyDI->item.pszText, "", pNotifyDI->item.cchTextMax); } else { StrRetToStr(pNotifyDI->item.pszText, pNotifyDI->item.cchTextMax, &strret, pidl); } }
if (pNotifyDI->item.mask & LVIF_IMAGE) { // Get the image
pNotifyDI->item.iImage = m_cList.GetIcon(m_psfv->m_psf, pidl); }
pNotifyDI->item.mask |= LVIF_DI_SETITEM; } else if (pNotifyDI->item.mask & LVIF_TEXT) { SFVCB_GETDETAILSOF_DATA gdo; gdo.pidl = (LPCITEMIDLIST)pNotifyDI->item.lParam;
if (m_psfv->CallCB(SFVCB_GETDETAILSOF, pNotifyDI->item.iSubItem, (LPARAM)&gdo) == S_OK) { StrRetToStr(pNotifyDI->item.pszText, pNotifyDI->item.cchTextMax, &gdo.str, gdo.pidl); } } break;
case LVN_COLUMNCLICK: m_psfv->ColumnClick(pNotifyLV->iSubItem); break;
case LVN_ITEMCHANGED: // We only care about STATECHANGE messages
if (!(pNotifyLV->uChanged & LVIF_STATE)) { // If the text is changed, we need to flush the cached
// context menu.
if (pNotifyLV->uChanged & LVIF_TEXT) { m_psfv->ReleaseSelContextMenu(); } break; }
// tell commdlg that selection may have changed
m_psfv->OnStateChange(CDBOSC_SELCHANGE);
// The rest only cares about SELCHANGE messages
if ((pNotifyLV->uNewState^pNotifyLV->uOldState) & LVIS_SELECTED) { m_psfv->ReleaseSelContextMenu(); }
break;
case LVN_BEGINDRAG: case LVN_BEGINRDRAG: return(BeginDrag());
case NM_RETURN: case NM_DBLCLK: ContextMenu((DWORD)-1, TRUE); break;
default: return(FALSE); }
return(TRUE); }
void CSFViewDlg::ContextMenu(DWORD dwPos, BOOL bDoDefault) { int idDefault = -1; int nInsert; UINT fFlags = 0; POINT pt;
// Find the selected item
int iItem = ListView_GetNextItem(m_cList, -1, LVNI_SELECTED);
if (dwPos == (DWORD) -1) { if (iItem != -1) { RECT rc; int iItemFocus = ListView_GetNextItem(m_cList, -1, LVNI_FOCUSED|LVNI_SELECTED); if (iItemFocus == -1) { iItemFocus = iItem; }
// Note that ListView_GetItemRect returns client coordinates
ListView_GetItemRect(m_cList, iItemFocus, &rc, LVIR_ICON); pt.x = (rc.left+rc.right)/2; pt.y = (rc.top+rc.bottom)/2; } else { pt.x = pt.y = 0; }
MapWindowPoints(m_cList, HWND_DESKTOP, &pt, 1); } else { pt.x = GET_X_LPARAM(dwPos); pt.y = GET_Y_LPARAM(dwPos); }
CMenuTemp cmContext(CreatePopupMenu()); if (!(HMENU)cmContext) { // There should be an error message here
return; }
LPCONTEXTMENU pcm = NULL;
if (iItem == -1) { // No selected item; use the background context menu
nInsert = -1;
CMenuTemp cmMerge(_LoadPopupMenu(MENU_SFV, 0)); if (!(HMENU)cmMerge) { // There should be an error message here
return; }
Cab_MergeMenus(cmContext, cmMerge, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0); m_psfv->MergeArrangeMenu(cmContext); m_psfv->InitViewMenu(cmContext);
if (FAILED(m_psfv->m_psf->CreateViewObject(m_psfv->m_hwndMain, IID_IContextMenu, (LPVOID *)&pcm))) { pcm = NULL; } } else { nInsert = 0;
pcm = m_psfv->GetSelContextMenu(); } CEnsureRelease erPCM(pcm);
if (pcm) { if (m_psfv->m_psb) { // Determine whether we are in Explorer mode
HWND hwnd = NULL; m_psfv->m_psb->GetControlWindow(FCW_TREE, &hwnd); if (hwnd) { fFlags |= CMF_EXPLORE; } }
pcm->QueryContextMenu(cmContext, nInsert, SFV_CONTEXT_FIRST, SFV_CONTEXT_LAST, fFlags);
// If this is the common dialog browser, we need to make the
// default command "Select" so that double-clicking (which is
// open in common dialog) makes sense.
if (m_psfv->IsInCommDlg() && iItem!=-1) { // make sure this is an item
CMenuTemp cmSelect(_LoadPopupMenu(MENU_SFV, 1));
Cab_MergeMenus(cmContext, cmSelect, 0, 0, (UINT)-1, MM_ADDSEPARATOR);
SetMenuDefaultItem(cmContext, 0, MF_BYPOSITION); }
idDefault = GetMenuDefaultItem(cmContext, MF_BYCOMMAND, 0); }
_PrettyMenu(cmContext);
int idCmd; if (bDoDefault) { if (idDefault < 0) { return; }
idCmd = idDefault; } else { idCmd = TrackPopupMenu(cmContext, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN, pt.x, pt.y, 0, m_psfv->m_cView, NULL); }
if ((idCmd==idDefault) && m_psfv->OnDefaultCommand()==S_OK) { // commdlg browser ate the default command
} else if (idCmd == 0) { // No item selected
} else { m_psfv->OnCommand(pcm, GET_WM_COMMAND_MPS(idCmd, 0, 0)); } }
BOOL CSFViewDlg::RealDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: InitDialog(); break;
case WM_DESTROY: m_cList.DeleteAllItems(); if (OleInited()) { OleUninitialize(); m_hrOLE = E_UNEXPECTED; } break;
case WM_NOTIFY: SetWindowLong(m_hDlg, DWL_MSGRESULT, Notify((LPNMHDR)lParam)); break;
case WM_INITMENUPOPUP: m_psfv->OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), HIWORD(lParam)); break;
case WM_COMMAND: m_psfv->OnCommand(NULL, wParam, lParam); break;
case WM_CONTEXTMENU: ContextMenu(lParam); break;
case WM_SIZE: SetWindowPos(m_cList, NULL, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), SWP_NOZORDER|SWP_SHOWWINDOW); break;
case WM_MENUSELECT: m_psfv->OnMenuSelect(GET_WM_MENUSELECT_CMD(wParam, lParam), GET_WM_MENUSELECT_FLAGS(wParam, lParam), GET_WM_MENUSELECT_HMENU(wParam, lParam)); break;
default: return(FALSE); }
return(TRUE); }
UINT CSFViewDlg::CharWidth() { HDC hdc = GetDC(m_cList); SelectFont(hdc, FORWARD_WM_GETFONT(m_cList, SendMessage));
SIZE siz; GetTextExtentPoint(hdc, "0", 1, &siz); ReleaseDC(m_cList, hdc);
return(siz.cx); }
int CSFViewDlg::AddObject(LPCITEMIDLIST pidl) { LV_ITEM item;
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; item.iItem = 0x7fff; // add at end
item.iSubItem = 0;
item.iImage = I_IMAGECALLBACK; item.pszText = LPSTR_TEXTCALLBACK; item.lParam = (LPARAM)pidl;
return(m_cList.InsertItem(&item)); }
LPCITEMIDLIST CSFViewDlg::GetPIDL(int iItem) { LV_ITEM item;
item.mask = LVIF_PARAM; item.iItem = iItem; item.iSubItem = 0; item.lParam = 0; if (iItem != -1) { ListView_GetItem(m_cList, &item); }
return((LPCITEMIDLIST)item.lParam); }
UINT CSFViewDlg::GetItemPIDLS(LPCITEMIDLIST apidl[], UINT cItemMax, UINT uItem) { // We should put the focused one at the top of the list.
int iItem = -1; int iItemFocus = -1; UINT cItem = 0; UINT uType;
switch (uItem) { case SVGIO_SELECTION: // special case for faster search
if (!cItemMax) { return ListView_GetSelectedCount(m_cList); } iItemFocus = ListView_GetNextItem(m_cList, -1, LVNI_FOCUSED); uType = LVNI_SELECTED; break;
case SVGIO_ALLVIEW: // special case for faster search
if (!cItemMax) { return ListView_GetItemCount(m_cList); } uType = LVNI_ALL; break;
default: return(0); }
while((iItem=ListView_GetNextItem(m_cList, iItem, uType)) != -1) { if (cItem < cItemMax) { // Check if the item is the focused one or not.
if (iItem == iItemFocus) { // Yes, put it at the top.
apidl[cItem] = apidl[0]; apidl[0] = GetPIDL(iItem); } else { // No, put it at the end of the list.
apidl[cItem] = GetPIDL(iItem); } }
cItem++; }
return cItem; }
HRESULT CSFViewDlg::GetItemObjects(LPCITEMIDLIST **ppidl, UINT uItem) { UINT cItems = GetItemPIDLS(NULL, 0, uItem); LPCITEMIDLIST * apidl;
if (ppidl != NULL) { *ppidl = NULL;
if (cItems == 0) { return(ResultFromShort(0)); // nothing allocated...
}
apidl = new LPCITEMIDLIST[cItems]; if (!apidl) { return(E_OUTOFMEMORY); }
*ppidl = apidl; cItems = GetItemPIDLS(apidl, cItems, uItem); }
return(ResultFromShort(cItems)); }
HRESULT CSFViewDlg::GetUIObjectFromItem(REFIID riid, LPVOID * ppv, UINT uItem) { LPCITEMIDLIST * apidl; HRESULT hres = GetItemObjects(&apidl, uItem); UINT cItems = ShortFromResult(hres);
if (FAILED(hres)) { return(hres); }
if (!cItems) { return(E_INVALIDARG); }
hres = m_psfv->m_psf->GetUIObjectOf(m_psfv->m_hwndMain, cItems, apidl, riid, 0, ppv);
delete apidl;
return hres; }
HRESULT CSFViewDlg::GetAttributesFromItem(ULONG *pdwAttr, UINT uItem) { LPCITEMIDLIST * apidl; HRESULT hres = GetItemObjects(&apidl, uItem); UINT cItems = ShortFromResult(hres);
if (FAILED(hres)) { return(hres); }
if (!cItems) { return(E_INVALIDARG); }
hres = m_psfv->m_psf->GetAttributesOf(cItems, apidl, pdwAttr);
delete apidl;
return hres; }
BOOL CSFViewDlg::IsMenuSeparator(HMENU hm, int i) { MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE; mii.cch = 0; // WARNING: We MUST initialize it to 0!!!
if (!GetMenuItemInfo(hm, i, TRUE, &mii)) { return(FALSE); }
if (mii.fType & MFT_SEPARATOR) { return(TRUE); }
return(FALSE); }
|