⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 paneldrag.cpp

📁 7z一个高压缩比的压缩程序源代码,重要的是里面的算法值得学习
💻 CPP
📖 第 1 页 / 共 2 页
字号:
{
  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 + -