📄 paneldrag.cpp
字号:
// PanelDrag.cpp
#include "StdAfx.h"
#include "Common/StringConvert.h"
#include "Windows/Memory.h"
#include "Windows/FileDir.h"
#include "Windows/Shell.h"
#include "../Common/ArchiveName.h"
#include "../Common/CompressCall.h"
#include "MessagesDialog.h"
#include "App.h"
#include "EnumFormatEtc.h"
using namespace NWindows;
#ifndef _UNICODE
extern bool g_IsNT;
#endif
static wchar_t *kTempDirPrefix = L"7zE";
static LPCTSTR kSvenZipSetFolderFormat = TEXT("7-Zip::SetTargetFolder");
////////////////////////////////////////////////////////
class CDataObject:
public IDataObject,
public CMyUnknownImp
{
private:
FORMATETC m_Etc;
UINT m_SetFolderFormat;
public:
MY_UNKNOWN_IMP1_MT(IDataObject)
STDMETHODIMP GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM medium);
STDMETHODIMP GetDataHere(LPFORMATETC pformatetc, LPSTGMEDIUM medium);
STDMETHODIMP QueryGetData(LPFORMATETC pformatetc );
STDMETHODIMP GetCanonicalFormatEtc ( LPFORMATETC /* pformatetc */, LPFORMATETC pformatetcOut)
{ pformatetcOut->ptd = NULL; return ResultFromScode(E_NOTIMPL); }
STDMETHODIMP SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release);
STDMETHODIMP EnumFormatEtc(DWORD drection, LPENUMFORMATETC *enumFormatEtc);
STDMETHODIMP DAdvise(FORMATETC * /* etc */, DWORD /* advf */, LPADVISESINK /* pAdvSink */, DWORD * /* pdwConnection */)
{ return OLE_E_ADVISENOTSUPPORTED; }
STDMETHODIMP DUnadvise(DWORD /* dwConnection */) { return OLE_E_ADVISENOTSUPPORTED; }
STDMETHODIMP EnumDAdvise( LPENUMSTATDATA * /* ppenumAdvise */) { return OLE_E_ADVISENOTSUPPORTED; }
CDataObject();
NMemory::CGlobal hGlobal;
UString Path;
};
CDataObject::CDataObject()
{
m_SetFolderFormat = RegisterClipboardFormat(kSvenZipSetFolderFormat);
m_Etc.cfFormat = CF_HDROP;
m_Etc.ptd = NULL;
m_Etc.dwAspect = DVASPECT_CONTENT;
m_Etc.lindex = -1;
m_Etc.tymed = TYMED_HGLOBAL;
}
STDMETHODIMP CDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL /* release */)
{
if (etc->cfFormat == m_SetFolderFormat && etc->tymed == TYMED_HGLOBAL &&
etc->dwAspect == DVASPECT_CONTENT && medium->tymed == TYMED_HGLOBAL)
{
Path.Empty();
if (medium->hGlobal == 0)
return S_OK;
size_t size = GlobalSize(medium->hGlobal) / sizeof(wchar_t);
const wchar_t *src = (const wchar_t *)GlobalLock(medium->hGlobal);
if (src != 0)
{
for (size_t i = 0; i < size; i++)
{
wchar_t c = src[i];
if (c == 0)
break;
Path += c;
}
GlobalUnlock(medium->hGlobal);
return S_OK;
}
}
return E_NOTIMPL;
}
static HGLOBAL DuplicateGlobalMem(HGLOBAL srcGlobal)
{
SIZE_T size = GlobalSize(srcGlobal);
const void *src = GlobalLock(srcGlobal);
if (src == 0)
return 0;
HGLOBAL destGlobal = GlobalAlloc(GHND | GMEM_SHARE, size);
if (destGlobal != 0)
{
void *dest = GlobalLock(destGlobal);
if (dest == 0)
{
GlobalFree(destGlobal);
destGlobal = 0;
}
else
{
memcpy(dest, src, size);
GlobalUnlock(destGlobal);
}
}
GlobalUnlock(srcGlobal);
return destGlobal;
}
STDMETHODIMP CDataObject::GetData(LPFORMATETC etc, LPSTGMEDIUM medium)
{
RINOK(QueryGetData(etc));
medium->tymed = m_Etc.tymed;
medium->pUnkForRelease = 0;
medium->hGlobal = DuplicateGlobalMem(hGlobal);
if (medium->hGlobal == 0)
return E_OUTOFMEMORY;
return S_OK;
}
STDMETHODIMP CDataObject::GetDataHere(LPFORMATETC /* etc */, LPSTGMEDIUM /* medium */)
{
// Seems Windows doesn't call it, so we will not implement it.
return E_UNEXPECTED;
}
STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC etc)
{
if ((m_Etc.tymed & etc->tymed) &&
m_Etc.cfFormat == etc->cfFormat &&
m_Etc.dwAspect == etc->dwAspect)
return S_OK;
return DV_E_FORMATETC;
}
STDMETHODIMP CDataObject::EnumFormatEtc(DWORD direction, LPENUMFORMATETC FAR* enumFormatEtc)
{
if (direction != DATADIR_GET)
return E_NOTIMPL;
return CreateEnumFormatEtc(1, &m_Etc, enumFormatEtc);
}
////////////////////////////////////////////////////////
class CDropSource:
public IDropSource,
public CMyUnknownImp
{
DWORD m_Effect;
public:
MY_UNKNOWN_IMP1_MT(IDropSource)
STDMETHOD(QueryContinueDrag)(BOOL escapePressed, DWORD keyState);
STDMETHOD(GiveFeedback)(DWORD effect);
bool NeedExtract;
CPanel *Panel;
CRecordVector<UInt32> Indices;
UString Folder;
CDataObject *DataObjectSpec;
CMyComPtr<IDataObject> DataObject;
bool NeedPostCopy;
HRESULT Result;
UStringVector Messages;
CDropSource(): NeedPostCopy(false), Panel(0), Result(S_OK), m_Effect(DROPEFFECT_NONE) {}
};
STDMETHODIMP CDropSource::QueryContinueDrag(BOOL escapePressed, DWORD keyState)
{
if (escapePressed == TRUE)
return DRAGDROP_S_CANCEL;
if ((keyState & MK_LBUTTON) == 0)
{
if (m_Effect == DROPEFFECT_NONE)
return DRAGDROP_S_CANCEL;
Result = S_OK;
bool needExtract = NeedExtract;
// MoveMode = (((keyState & MK_SHIFT) != 0) && MoveIsAllowed);
if (!DataObjectSpec->Path.IsEmpty())
{
needExtract = false;
NeedPostCopy = true;
}
if (needExtract)
{
Result = Panel->CopyTo(Indices, Folder,
false, // moveMode,
false, // showMessages
&Messages);
if (Result != S_OK || !Messages.IsEmpty())
return DRAGDROP_S_CANCEL;
}
return DRAGDROP_S_DROP;
}
return S_OK;
}
STDMETHODIMP CDropSource::GiveFeedback(DWORD effect)
{
m_Effect = effect;
return DRAGDROP_S_USEDEFAULTCURSORS;
}
static bool CopyNamesToHGlobal(NMemory::CGlobal &hgDrop, const UStringVector &names)
{
size_t totalLength = 1;
#ifndef _UNICODE
if (!g_IsNT)
{
AStringVector namesA;
int i;
for (i = 0; i < names.Size(); i++)
namesA.Add(GetSystemString(names[i]));
for (i = 0; i < names.Size(); i++)
totalLength += namesA[i].Length() + 1;
if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLength * sizeof(CHAR) + sizeof(DROPFILES)))
return false;
NMemory::CGlobalLock dropLock(hgDrop);
DROPFILES* dropFiles = (DROPFILES*)dropLock.GetPointer();
if (dropFiles == 0)
return false;
dropFiles->fNC = FALSE;
dropFiles->pt.x = 0;
dropFiles->pt.y = 0;
dropFiles->pFiles = sizeof(DROPFILES);
dropFiles->fWide = FALSE;
CHAR *p = (CHAR *)((BYTE *)dropFiles + sizeof(DROPFILES));
for (i = 0; i < names.Size(); i++)
{
const AString &s = namesA[i];
int fullLength = s.Length() + 1;
MyStringCopy(p, (const char *)s);
p += fullLength;
totalLength -= fullLength;
}
*p = 0;
}
else
#endif
{
int i;
for (i = 0; i < names.Size(); i++)
totalLength += names[i].Length() + 1;
if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLength * sizeof(WCHAR) + sizeof(DROPFILES)))
return false;
NMemory::CGlobalLock dropLock(hgDrop);
DROPFILES* dropFiles = (DROPFILES*)dropLock.GetPointer();
if (dropFiles == 0)
return false;
dropFiles->fNC = FALSE;
dropFiles->pt.x = 0;
dropFiles->pt.y = 0;
dropFiles->pFiles = sizeof(DROPFILES);
dropFiles->fWide = TRUE;
WCHAR *p = (WCHAR *)((BYTE *)dropFiles + sizeof(DROPFILES));
for (i = 0; i < names.Size(); i++)
{
const UString &s = names[i];
int fullLength = s.Length() + 1;
MyStringCopy(p, (const WCHAR *)s);
p += fullLength;
totalLength -= fullLength;
}
*p = 0;
}
return true;
}
void CPanel::OnDrag(LPNMLISTVIEW /* nmListView */)
{
CPanel::CDisableTimerProcessing disableTimerProcessing2(*this);
if (!DoesItSupportOperations())
return;
CRecordVector<UInt32> indices;
GetOperatedItemIndices(indices);
if (indices.Size() == 0)
return;
// CSelectedState selState;
// SaveSelectedState(selState);
UString dirPrefix;
NFile::NDirectory::CTempDirectoryW tempDirectory;
bool isFSFolder = IsFSFolder();
if (isFSFolder)
dirPrefix = _currentFolderPrefix;
else
{
tempDirectory.Create(kTempDirPrefix);
dirPrefix = tempDirectory.GetPath();
NFile::NName::NormalizeDirPathPrefix(dirPrefix);
}
CDataObject *dataObjectSpec = new CDataObject;
CMyComPtr<IDataObject> dataObject = dataObjectSpec;
{
UStringVector names;
for (int i = 0; i < indices.Size(); i++)
{
UInt32 index = indices[i];
UString s;
if (isFSFolder)
s = GetItemRelPath(index);
else
s = GetItemName(index);
names.Add(dirPrefix + s);
}
if (!CopyNamesToHGlobal(dataObjectSpec->hGlobal, names))
return;
}
CDropSource *dropSourceSpec = new CDropSource;
CMyComPtr<IDropSource> dropSource = dropSourceSpec;
dropSourceSpec->NeedExtract = !isFSFolder;
dropSourceSpec->Panel = this;
dropSourceSpec->Indices = indices;
dropSourceSpec->Folder = dirPrefix;
dropSourceSpec->DataObjectSpec = dataObjectSpec;
dropSourceSpec->DataObject = dataObjectSpec;
bool moveIsAllowed = isFSFolder;
DWORD effectsOK = DROPEFFECT_COPY;
if (moveIsAllowed)
effectsOK |= DROPEFFECT_MOVE;
DWORD effect;
_panelCallback->DragBegin();
HRESULT res = DoDragDrop(dataObject, dropSource, effectsOK, &effect);
_panelCallback->DragEnd();
bool canceled = (res == DRAGDROP_S_CANCEL);
if (res == DRAGDROP_S_DROP)
{
res = dropSourceSpec->Result;
if (dropSourceSpec->NeedPostCopy)
if (!dataObjectSpec->Path.IsEmpty())
{
NFile::NName::NormalizeDirPathPrefix(dataObjectSpec->Path);
res = CopyTo(indices, dataObjectSpec->Path,
(effect == DROPEFFECT_MOVE),// dropSourceSpec->MoveMode,
false, // showErrorMessages
&dropSourceSpec->Messages);
}
/*
if (effect == DROPEFFECT_MOVE)
RefreshListCtrl(selState);
*/
}
else
{
if (res != DRAGDROP_S_CANCEL && res != S_OK)
MessageBoxError(res);
res = dropSourceSpec->Result;
}
if (!dropSourceSpec->Messages.IsEmpty())
{
CMessagesDialog messagesDialog;
messagesDialog.Messages = &dropSourceSpec->Messages;
messagesDialog.Create((*this));
}
if (res != S_OK && res != E_ABORT)
MessageBoxError(res);
if (res == S_OK && dropSourceSpec->Messages.IsEmpty() && !canceled)
KillSelection();
}
void CDropTarget::QueryGetData(IDataObject *dataObject)
{
FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
m_DropIsAllowed = (dataObject->QueryGetData(&etc) == S_OK);
}
static void MySetDropHighlighted(HWND hWnd, int index, bool enable)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -