📄 mulelistctrl.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include "emule.h"
#include "MemDC.h"
#include "MuleListCtrl.h"
#include "Ini2.h"
#include "SharedFilesCtrl.h"
#include "SearchListCtrl.h"
#include "KadContactListCtrl.h"
#include "KadSearchListCtrl.h"
#include "DownloadListCtrl.h"
#include "UploadListCtrl.h"
#include "QueueListCtrl.h"
#include "ClientListCtrl.h"
#include "FriendListCtrl.h"
#include "ServerListCtrl.h"
#include "MenuCmds.h"
#include "OtherFunctions.h"
#include "ListViewSearchDlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define MLC_BLEND(A, B, X) ((A + B * (X-1) + ((X+1)/2)) / X)
#define MLC_RGBBLEND(A, B, X) ( \
RGB(MLC_BLEND(GetRValue(A), GetRValue(B), X), \
MLC_BLEND(GetGValue(A), GetGValue(B), X), \
MLC_BLEND(GetBValue(A), GetBValue(B), X)) \
)
#define MLC_DT_TEXT (DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_END_ELLIPSIS)
#define MLC_IDC_MENU 4875
#define MLC_IDC_UPDATE (MLC_IDC_MENU - 1)
//a value that's not a multiple of 4 and uncommon
#define MLC_MAGIC 0xFEEBDEEF
//used for very slow assertions
//#define MLC_ASSERT(f) ASSERT(f)
#define MLC_ASSERT(f) ((void)0)
#ifndef HDM_SETBITMAPMARGIN
#define HDM_SETBITMAPMARGIN (HDM_FIRST + 20)
#define HDM_GETBITMAPMARGIN (HDM_FIRST + 21)
#endif
//////////////////////////////////
// CMuleListCtrl
IMPLEMENT_DYNAMIC(CMuleListCtrl, CListCtrl)
CMuleListCtrl::CMuleListCtrl(PFNLVCOMPARE pfnCompare, DWORD dwParamSort) {
m_SortProc = pfnCompare;
m_dwParamSort = dwParamSort;
m_bCustomDraw = false;
m_iCurrentSortItem = -1;
m_iColumnsTracked = 0;
m_aColumns = NULL;
m_iRedrawCount = 0;
//just in case
m_crWindow = 0;
m_crWindowText = 0;
m_crWindowTextBk = m_crWindow;
m_crHighlight = 0;
m_crGlow=0;
m_crFocusLine = 0;
m_crNoHighlight = 0;
m_crNoFocusLine = 0;
m_bGeneralPurposeFind = false;
m_bFindMatchCase = false;
m_iFindDirection = 1;
m_iFindColumn = 0;
}
CMuleListCtrl::~CMuleListCtrl() {
if(m_aColumns != NULL)
delete[] m_aColumns;
}
int CMuleListCtrl::SortProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) {
return 0;
}
void CMuleListCtrl::SetName(LPCTSTR lpszName) {
m_Name = lpszName;
}
void CMuleListCtrl::PreSubclassWindow() {
SetColors();
CListCtrl::PreSubclassWindow();
ModifyStyle(LVS_SINGLESEL|LVS_LIST|LVS_ICON|LVS_SMALLICON,LVS_REPORT|LVS_SINGLESEL|LVS_REPORT);
SetExtendedStyle(LVS_EX_HEADERDRAGDROP);
}
int CMuleListCtrl::IndexToOrder(CHeaderCtrl* pHeader, int iIndex) {
int iCount = pHeader->GetItemCount();
int *piArray = new int[iCount];
Header_GetOrderArray( pHeader->m_hWnd, iCount, piArray);
for(int i=0; i < iCount; i++ ) {
if(piArray[i] == iIndex) {
delete[] piArray;
return i;
}
}
delete[] piArray;
return -1;
}
void CMuleListCtrl::HideColumn(int iColumn) {
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
int iCount = pHeaderCtrl->GetItemCount();
if(iColumn < 1 || iColumn >= iCount || m_aColumns[iColumn].bHidden)
return;
//stop it from redrawing
SetRedraw(FALSE);
//shrink width to 0
HDITEM item;
item.mask = HDI_WIDTH;
pHeaderCtrl->GetItem(iColumn, &item);
m_aColumns[iColumn].iWidth = item.cxy;
item.cxy = 0;
pHeaderCtrl->SetItem(iColumn, &item);
//move to front of list
INT *piArray = new INT[m_iColumnsTracked];
pHeaderCtrl->GetOrderArray(piArray, m_iColumnsTracked);
int iFrom = m_aColumns[iColumn].iLocation;
for(int i = 0; i < m_iColumnsTracked; i++)
if(m_aColumns[i].iLocation > m_aColumns[iColumn].iLocation && m_aColumns[i].bHidden)
iFrom++;
for(int i = iFrom; i > 0; i--)
piArray[i] = piArray[i - 1];
piArray[0] = iColumn;
pHeaderCtrl->SetOrderArray(m_iColumnsTracked, piArray);
delete[] piArray;
//update entry
m_aColumns[iColumn].bHidden = true;
//redraw
SetRedraw(TRUE);
Invalidate(FALSE);
}
void CMuleListCtrl::ShowColumn(int iColumn) {
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
int iCount = pHeaderCtrl->GetItemCount();
if(iColumn < 1 || iColumn >= iCount || !m_aColumns[iColumn].bHidden)
return;
//stop it from redrawing
SetRedraw(FALSE);
//restore position in list
INT *piArray = new INT[m_iColumnsTracked];
pHeaderCtrl->GetOrderArray(piArray, m_iColumnsTracked);
int iCurrent = IndexToOrder(pHeaderCtrl, iColumn);
for(; iCurrent < IndexToOrder(pHeaderCtrl, 0) && iCurrent < m_iColumnsTracked - 1; iCurrent++ )
piArray[iCurrent] = piArray[iCurrent + 1];
for(; m_aColumns[iColumn].iLocation > m_aColumns[pHeaderCtrl->OrderToIndex(iCurrent + 1)].iLocation &&
iCurrent < m_iColumnsTracked - 1; iCurrent++)
piArray[iCurrent] = piArray[iCurrent + 1];
piArray[iCurrent] = iColumn;
pHeaderCtrl->SetOrderArray(m_iColumnsTracked, piArray);
delete[] piArray;
//and THEN restore original width
HDITEM item;
item.mask = HDI_WIDTH;
item.cxy = m_aColumns[iColumn].iWidth;
pHeaderCtrl->SetItem(iColumn, &item);
//update entry
m_aColumns[iColumn].bHidden = false;
//redraw
SetRedraw(TRUE);
Invalidate(FALSE);
}
void CMuleListCtrl::SaveSettings(CPreferences::Table tID) {
INT *piArray = new INT[m_iColumnsTracked];
for(int i = 0; i < m_iColumnsTracked; i++) {
thePrefs.SetColumnWidth(tID, i, GetColumnWidth(i));
thePrefs.SetColumnHidden(tID, i, IsColumnHidden(i));
piArray[i] = m_aColumns[i].iLocation;
}
thePrefs.SetColumnOrder(tID, piArray);
delete[] piArray;
}
void CMuleListCtrl::SaveSettings(CIni* ini, LPCTSTR pszLVName)
{
int* piColWidths = new int[m_iColumnsTracked];
int* piColHidden = new int[m_iColumnsTracked];
INT *piColOrders = new INT[m_iColumnsTracked];
for(int i = 0; i < m_iColumnsTracked; i++)
{
piColWidths[i] = GetColumnWidth(i);
piColHidden[i] = IsColumnHidden(i);
piColOrders[i] = m_aColumns[i].iLocation;
}
ini->SerGet(false, piColWidths, m_iColumnsTracked, CString(pszLVName) + _T("ColumnWidths"));
ini->SerGet(false, piColHidden, m_iColumnsTracked, CString(pszLVName) + _T("ColumnHidden"));
ini->SerGet(false, piColOrders, m_iColumnsTracked, CString(pszLVName) + _T("ColumnOrders"));
delete[] piColOrders;
delete[] piColWidths;
delete[] piColHidden;
}
void CMuleListCtrl::LoadSettings(CPreferences::Table tID) {
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
INT *piArray = new INT[m_iColumnsTracked];
for(int i = 0; i < m_iColumnsTracked; i++)
piArray[i] = i;
for(int i = 0; i < m_iColumnsTracked; i++) {
int iWidth = thePrefs.GetColumnWidth(tID, i);
if(iWidth >= 2) // don't allow column widths of 0 and 1 -- just because it looks very confusing in GUI
SetColumnWidth(i, iWidth);
if(i == 0) {
piArray[0] = 0;
} else {
int iOrder = thePrefs.GetColumnOrder(tID, i);
if(iOrder > 0 && iOrder < m_iColumnsTracked && iOrder != i)
piArray[iOrder] = i;
}
}
pHeaderCtrl->SetOrderArray(m_iColumnsTracked, piArray);
pHeaderCtrl->GetOrderArray(piArray, m_iColumnsTracked);
for(int i = 0; i < m_iColumnsTracked; i++)
m_aColumns[piArray[i]].iLocation = i;
delete[] piArray;
for(int i = 1; i < m_iColumnsTracked; i++) {
if(thePrefs.GetColumnHidden(tID, i))
HideColumn(i);
}
}
void CMuleListCtrl::LoadSettings(CIni* ini, LPCTSTR pszLVName)
{
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
int* piColWidths = new int[m_iColumnsTracked];
int* piColHidden = new int[m_iColumnsTracked];
int* piColOrders = new int[m_iColumnsTracked];
ini->SerGet(true, piColWidths, m_iColumnsTracked, CString(pszLVName) + _T("ColumnWidths"));
ini->SerGet(true, piColHidden, m_iColumnsTracked, CString(pszLVName) + _T("ColumnHidden"));
ini->SerGet(true, piColOrders, m_iColumnsTracked, CString(pszLVName) + _T("ColumnOrders"));
INT *piArray = new INT[m_iColumnsTracked];
for (int i = 0; i < m_iColumnsTracked; i++)
piArray[i] = i;
for (int i = 0; i < m_iColumnsTracked; i++)
{
int iWidth = piColWidths[i];
if (iWidth >= 2) // don't allow column widths of 0 and 1 -- just because it looks very confusing in GUI
SetColumnWidth(i, iWidth);
if (i == 0) {
piArray[0] = 0;
}
else {
int iOrder = piColOrders[i];
if (iOrder > 0 && iOrder < m_iColumnsTracked && iOrder != i)
piArray[iOrder] = i;
}
}
pHeaderCtrl->SetOrderArray(m_iColumnsTracked, piArray);
pHeaderCtrl->GetOrderArray(piArray, m_iColumnsTracked);
for(int i = 0; i < m_iColumnsTracked; i++)
m_aColumns[piArray[i]].iLocation = i;
delete[] piArray;
for(int i = 1; i < m_iColumnsTracked; i++) {
if (piColHidden[i])
HideColumn(i);
}
delete[] piColOrders;
delete[] piColWidths;
delete[] piColHidden;
}
void CMuleListCtrl::SetColors(LPCTSTR pszLvKey) {
m_crWindow = ::GetSysColor(COLOR_WINDOW);
m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
m_crWindowTextBk = m_crWindow;
COLORREF crHighlight = ::GetSysColor(COLOR_HIGHLIGHT);
CString strBkImage;
LPCTSTR pszSkinProfile = thePrefs.GetSkinProfile();
if (pszSkinProfile != NULL && pszSkinProfile[0] != _T('\0'))
{
CString strKey;
if (pszLvKey != NULL && pszLvKey[0] != _T('\0'))
strKey = pszLvKey;
else if (IsKindOf(RUNTIME_CLASS(CServerListCtrl)))
strKey = _T("ServersLv");
else if (IsKindOf(RUNTIME_CLASS(CSearchListCtrl)))
strKey = _T("SearchResultsLv");
else if (IsKindOf(RUNTIME_CLASS(CDownloadListCtrl)))
strKey = _T("DownloadsLv");
else if (IsKindOf(RUNTIME_CLASS(CUploadListCtrl)))
strKey = _T("UploadsLv");
else if (IsKindOf(RUNTIME_CLASS(CQueueListCtrl)))
strKey = _T("QueuedLv");
else if (IsKindOf(RUNTIME_CLASS(CClientListCtrl)))
strKey = _T("ClientsLv");
else if (IsKindOf(RUNTIME_CLASS(CFriendListCtrl)))
strKey = _T("FriendsLv");
else if (IsKindOf(RUNTIME_CLASS(CSharedFilesCtrl)))
strKey = _T("SharedFilesLv");
else if (IsKindOf(RUNTIME_CLASS(CKadContactListCtrl)))
strKey = _T("KadContactsLv");
else if (IsKindOf(RUNTIME_CLASS(CKadSearchListCtrl)))
strKey = _T("KadActionsLv");
else
GetWindowText(strKey);
if (strKey.IsEmpty())
strKey = _T("DefLv");
TCHAR szColor[MAX_PATH];
GetPrivateProfileString(_T("Colors"), strKey + _T("Bk"), _T(""), szColor, ARRSIZE(szColor), pszSkinProfile);
if (szColor[0] == _T('\0'))
GetPrivateProfileString(_T("Colors"), _T("DefLvBk"), _T(""), szColor, ARRSIZE(szColor), pszSkinProfile);
if (szColor[0] != _T('\0'))
{
UINT red, grn, blu;
int iVals = _stscanf(szColor, _T("%i , %i , %i"), &red, &grn, &blu);
if (iVals == 3)
{
m_crWindow = RGB(red, grn, blu);
m_crWindowTextBk = m_crWindow;
}
}
GetPrivateProfileString(_T("Colors"), strKey + _T("Fg"), _T(""), szColor, ARRSIZE(szColor), pszSkinProfile);
if (szColor[0] == _T('\0'))
GetPrivateProfileString(_T("Colors"), _T("DefLvFg"), _T(""), szColor, ARRSIZE(szColor), pszSkinProfile);
if (szColor[0] != _T('\0'))
{
UINT red, grn, blu;
int iVals = _stscanf(szColor, _T("%i , %i , %i"), &red, &grn, &blu);
if (iVals == 3)
m_crWindowText = RGB(red, grn, blu);
}
GetPrivateProfileString(_T("Colors"), strKey + _T("Hl"), _T(""), szColor, ARRSIZE(szColor), pszSkinProfile);
if (szColor[0] == _T('\0'))
GetPrivateProfileString(_T("Colors"), _T("DefLvHl"), _T(""), szColor, ARRSIZE(szColor), pszSkinProfile);
if (szColor[0] != _T('\0'))
{
UINT red, grn, blu;
int iVals = _stscanf(szColor, _T("%i , %i , %i"), &red, &grn, &blu);
if (iVals == 3)
crHighlight = RGB(red, grn, blu);
}
GetPrivateProfileString(_T("Colors"), strKey + _T("BkImg"), _T(""), szColor, ARRSIZE(szColor), pszSkinProfile);
if (szColor[0] == _T('\0'))
GetPrivateProfileString(_T("Colors"), _T("DefLvBkImg"), _T(""), szColor, ARRSIZE(szColor), pszSkinProfile);
if (szColor[0] != _T('\0'))
strBkImage = szColor;
}
SetBkColor(m_crWindow);
SetTextBkColor(m_crWindowTextBk);
SetTextColor(m_crWindowText);
LVBKIMAGE lvimg = {0};
lvimg.ulFlags = LVBKIF_SOURCE_NONE;
SetBkImage(&lvimg);
if (!strBkImage.IsEmpty())
{
// expand any optional available environment strings
TCHAR szExpSkinRes[MAX_PATH];
if (ExpandEnvironmentStrings(strBkImage, szExpSkinRes, ARRSIZE(szExpSkinRes)) != 0)
strBkImage = szExpSkinRes;
// create absolute path to icon resource file
TCHAR szFullResPath[MAX_PATH];
if (PathIsRelative(strBkImage))
{
TCHAR szSkinResFolder[MAX_PATH];
_tcsncpy(szSkinResFolder, pszSkinProfile, ARRSIZE(szSkinResFolder));
szSkinResFolder[ARRSIZE(szSkinResFolder)-1] = _T('\0');
PathRemoveFileSpec(szSkinResFolder);
_tmakepath(szFullResPath, NULL, szSkinResFolder, strBkImage, NULL);
}
else
{
_tcsncpy(szFullResPath, strBkImage, ARRSIZE(szFullResPath));
szFullResPath[ARRSIZE(szFullResPath)-1] = _T('\0');
}
CString strUrl(_T("file://"));
strUrl += szFullResPath;
if (SetBkImage(const_cast<LPTSTR>((LPCTSTR)strUrl), FALSE, 0, 0))
{
m_crWindowTextBk = CLR_NONE;
SetTextBkColor(m_crWindowTextBk);
}
}
m_crFocusLine = crHighlight;
m_crNoHighlight = MLC_RGBBLEND(crHighlight, m_crWindow, 8);
m_crNoFocusLine = MLC_RGBBLEND(crHighlight, m_crWindow, 2);
m_crHighlight = MLC_RGBBLEND(crHighlight, m_crWindow, 4);
m_crGlow = MLC_RGBBLEND(crHighlight, m_crWindow, 3);
}
void CMuleListCtrl::SetSortArrow(int iColumn, ArrowType atType) {
HDITEM headerItem;
headerItem.mask = HDI_FORMAT;
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
if(iColumn != m_iCurrentSortItem) {
pHeaderCtrl->GetItem(m_iCurrentSortItem, &headerItem);
headerItem.fmt &= ~(HDF_IMAGE | HDF_BITMAP_ON_RIGHT);
pHeaderCtrl->SetItem(m_iCurrentSortItem, &headerItem);
m_iCurrentSortItem = iColumn;
m_imlHeaderCtrl.DeleteImageList();
}
//place new arrow unless we were given an invalid column
if(iColumn >= 0 && pHeaderCtrl->GetItem(iColumn, &headerItem)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -