📄 paneldrag.cpp
字号:
{
LVITEM item;
item.mask = LVIF_STATE;
item.iItem = index;
item.iSubItem = 0;
item.state = enable ? LVIS_DROPHILITED : 0;
item.stateMask = LVIS_DROPHILITED;
item.pszText = 0;
ListView_SetItem(hWnd, &item);
}
void CDropTarget::RemoveSelection()
{
if (m_SelectionIndex >= 0 && m_Panel != 0)
MySetDropHighlighted(m_Panel->_listView, m_SelectionIndex, false);
m_SelectionIndex = -1;
}
void CDropTarget::PositionCursor(POINTL ptl)
{
m_SubFolderIndex = -1;
POINT pt;
pt.x = ptl.x;
pt.y = ptl.y;
RemoveSelection();
m_IsAppTarget = true;
m_Panel = NULL;
m_PanelDropIsAllowed = true;
if (!m_DropIsAllowed)
return;
{
POINT pt2 = pt;
App->_window.ScreenToClient(&pt2);
for (int i = 0; i < kNumPanelsMax; i++)
if (App->IsPanelVisible(i))
if (App->Panels[i].IsEnabled())
if (ChildWindowFromPointEx(App->_window, pt2,
CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) == (HWND)App->Panels[i])
{
m_Panel = &App->Panels[i];
m_IsAppTarget = false;
if (i == SrcPanelIndex)
{
m_PanelDropIsAllowed = false;
return;
}
break;
}
if (m_IsAppTarget)
{
if (TargetPanelIndex >= 0)
m_Panel = &App->Panels[TargetPanelIndex];
return;
}
}
/*
m_PanelDropIsAllowed = m_Panel->DoesItSupportOperations();
if (!m_PanelDropIsAllowed)
return;
*/
if (!m_Panel->IsFSFolder() && !m_Panel->IsFSDrivesFolder())
return;
if (WindowFromPoint(pt) != (HWND)m_Panel->_listView)
return;
LVHITTESTINFO info;
m_Panel->_listView.ScreenToClient(&pt);
info.pt = pt;
int index = ListView_HitTest(m_Panel->_listView, &info);
if (index < 0)
return;
int realIndex = m_Panel->GetRealItemIndex(index);
if (realIndex == kParentIndex)
return;
if (!m_Panel->IsItemFolder(realIndex))
return;
m_SubFolderIndex = realIndex;
m_SubFolderName = m_Panel->GetItemName(m_SubFolderIndex);
MySetDropHighlighted(m_Panel->_listView, index, true);
m_SelectionIndex = index;
}
bool CDropTarget::IsFsFolderPath() const
{
if (!m_IsAppTarget && m_Panel != 0)
return (m_Panel->IsFSFolder() || (m_Panel->IsFSDrivesFolder() && m_SelectionIndex >= 0));
return false;
}
static void ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names)
{
names.Clear();
UString name;
for (;size > 0; size--)
{
wchar_t c = *p++;
if (c == 0)
{
if (name.IsEmpty())
break;
names.Add(name);
name.Empty();
}
else
name += c;
}
}
static void ReadAnsiStrings(const char *p, size_t size, UStringVector &names)
{
names.Clear();
AString name;
for (;size > 0; size--)
{
char c = *p++;
if (c == 0)
{
if (name.IsEmpty())
break;
names.Add(GetUnicodeString(name));
name.Empty();
}
else
name += c;
}
}
static void GetNamesFromDataObject(IDataObject *dataObject, UStringVector &names)
{
names.Clear();
FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM medium;
HRESULT res = dataObject->GetData(&etc, &medium);
if (res != S_OK)
return;
if (medium.tymed != TYMED_HGLOBAL)
return;
{
NMemory::CGlobal global;
global.Attach(medium.hGlobal);
size_t blockSize = GlobalSize(medium.hGlobal);
NMemory::CGlobalLock dropLock(medium.hGlobal);
const DROPFILES* dropFiles = (DROPFILES*)dropLock.GetPointer();
if (dropFiles == 0)
return;
if (blockSize < dropFiles->pFiles)
return;
size_t size = blockSize - dropFiles->pFiles;
const void *namesData = (const Byte *)dropFiles + dropFiles->pFiles;
if (dropFiles->fWide)
ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names);
else
ReadAnsiStrings((const char *)namesData, size, names);
}
}
bool CDropTarget::IsItSameDrive() const
{
if (m_Panel == 0)
return false;
if (!IsFsFolderPath())
return false;
UString drive;
if (m_Panel->IsFSFolder())
{
drive = m_Panel->GetDriveOrNetworkPrefix();
if (drive.IsEmpty())
return false;
}
else if (m_Panel->IsFSDrivesFolder() && m_SelectionIndex >= 0)
drive = m_SubFolderName + WCHAR_PATH_SEPARATOR;
else
return false;
if (m_SourcePaths.Size() == 0)
return false;
for (int i = 0; i < m_SourcePaths.Size(); i++)
{
const UString &path = m_SourcePaths[i];
if (drive.CompareNoCase(path.Left(drive.Length())) != 0)
return false;
}
return true;
}
DWORD CDropTarget::GetEffect(DWORD keyState, POINTL /* pt */, DWORD allowedEffect)
{
if (!m_DropIsAllowed || !m_PanelDropIsAllowed)
return DROPEFFECT_NONE;
if (!IsFsFolderPath() || !m_SetPathIsOK)
allowedEffect &= ~DROPEFFECT_MOVE;
DWORD effect = 0;
if (keyState & MK_CONTROL)
effect = allowedEffect & DROPEFFECT_COPY;
else if (keyState & MK_SHIFT)
effect = allowedEffect & DROPEFFECT_MOVE;
if (effect == 0)
{
if (allowedEffect & DROPEFFECT_COPY)
effect = DROPEFFECT_COPY;
if (allowedEffect & DROPEFFECT_MOVE)
{
if (IsItSameDrive())
effect = DROPEFFECT_MOVE;
}
}
if (effect == 0)
return DROPEFFECT_NONE;
return effect;
}
UString CDropTarget::GetTargetPath() const
{
if (!IsFsFolderPath())
return UString();
UString path = m_Panel->_currentFolderPrefix;
if (m_Panel->IsFSDrivesFolder())
path.Empty();
if (m_SubFolderIndex >= 0 && !m_SubFolderName.IsEmpty())
{
path += m_SubFolderName;
path += WCHAR_PATH_SEPARATOR;
}
return path;
}
bool CDropTarget::SetPath(bool enablePath) const
{
UINT setFolderFormat = RegisterClipboardFormat(kSvenZipSetFolderFormat);
FORMATETC etc = { (CLIPFORMAT)setFolderFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM medium;
medium.tymed = etc.tymed;
medium.pUnkForRelease = 0;
UString path;
if (enablePath)
path = GetTargetPath();
size_t size = path.Length() + 1;
medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size * sizeof(wchar_t));
if (medium.hGlobal == 0)
return false;
wchar_t *dest = (wchar_t *)GlobalLock(medium.hGlobal);
if (dest == 0)
{
GlobalUnlock(medium.hGlobal);
return false;
}
MyStringCopy(dest, (const wchar_t *)path);
GlobalUnlock(medium.hGlobal);
bool res = m_DataObject->SetData(&etc, &medium, FALSE) == S_OK;
GlobalFree(medium.hGlobal);
return res;
}
bool CDropTarget::SetPath()
{
m_SetPathIsOK = SetPath(m_DropIsAllowed && m_PanelDropIsAllowed && IsFsFolderPath());
return m_SetPathIsOK;
}
STDMETHODIMP CDropTarget::DragEnter(IDataObject * dataObject, DWORD keyState,
POINTL pt, DWORD *effect)
{
GetNamesFromDataObject(dataObject, m_SourcePaths);
QueryGetData(dataObject);
m_DataObject = dataObject;
return DragOver(keyState, pt, effect);
}
STDMETHODIMP CDropTarget::DragOver(DWORD keyState, POINTL pt, DWORD *effect)
{
PositionCursor(pt);
SetPath();
*effect = GetEffect(keyState, pt, *effect);
return S_OK;
}
STDMETHODIMP CDropTarget::DragLeave()
{
RemoveSelection();
SetPath(false);
m_DataObject.Release();
return S_OK;
}
// We suppose that there was ::DragOver for same POINTL_pt before ::Drop
// So SetPath() is same as in Drop.
STDMETHODIMP CDropTarget::Drop(IDataObject *dataObject, DWORD keyState,
POINTL pt, DWORD * effect)
{
QueryGetData(dataObject);
PositionCursor(pt);
m_DataObject = dataObject;
bool needDrop = true;
if (m_DropIsAllowed && m_PanelDropIsAllowed)
if (IsFsFolderPath())
needDrop = !SetPath();
*effect = GetEffect(keyState, pt, *effect);
if (m_DropIsAllowed && m_PanelDropIsAllowed)
{
if (needDrop)
{
UString path = GetTargetPath();
if (m_IsAppTarget && m_Panel)
if (m_Panel->IsFSFolder())
path = m_Panel->_currentFolderPrefix;
m_Panel->DropObject(dataObject, path);
}
}
RemoveSelection();
m_DataObject.Release();
return S_OK;
}
void CPanel::DropObject(IDataObject *dataObject, const UString &folderPath)
{
UStringVector names;
GetNamesFromDataObject(dataObject, names);
CompressDropFiles(names, folderPath);
}
/*
void CPanel::CompressDropFiles(HDROP dr)
{
UStringVector fileNames;
{
NShell::CDrop drop(true);
drop.Attach(dr);
drop.QueryFileNames(fileNames);
}
CompressDropFiles(fileNamesUnicode);
}
*/
static bool IsFolderInTemp(const UString &path)
{
UString tempPath;
if (!NFile::NDirectory::MyGetTempPath(tempPath))
return false;
if (tempPath.IsEmpty())
return false;
return (tempPath.CompareNoCase(path.Left(tempPath.Length())) == 0);
}
static bool AreThereNamesFromTemp(const UStringVector &fileNames)
{
UString tempPath;
if (!NFile::NDirectory::MyGetTempPath(tempPath))
return false;
if (tempPath.IsEmpty())
return false;
for (int i = 0; i < fileNames.Size(); i++)
if (tempPath.CompareNoCase(fileNames[i].Left(tempPath.Length())) == 0)
return true;
return false;
}
void CPanel::CompressDropFiles(const UStringVector &fileNames, const UString &folderPath)
{
if (fileNames.Size() == 0)
return;
const UString archiveName = CreateArchiveName(fileNames.Front(),
(fileNames.Size() > 1), false);
bool createNewArchive = true;
if (!IsFSFolder())
createNewArchive = !DoesItSupportOperations();
if (createNewArchive)
{
UString folderPath2 = folderPath;
if (folderPath2.IsEmpty())
{
NFile::NDirectory::GetOnlyDirPrefix(fileNames.Front(), folderPath2);
if (IsFolderInTemp(folderPath2))
folderPath2 = L"C:\\"; // fix it
}
CompressFiles(folderPath2, archiveName, L"", fileNames,
false, // email
true, // showDialog
AreThereNamesFromTemp(fileNames) // waitFinish
);
}
else
CopyFromAsk(fileNames);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -