📄 mulelistctrl.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.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
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#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();
SendMessage(CCM_SETUNICODEFORMAT, TRUE);
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");
if (theApp.LoadSkinColorAlt(strKey + _T("Bk" ), _T("DefLvBk"), m_crWindow))
m_crWindowTextBk = m_crWindow;
theApp.LoadSkinColorAlt(strKey + _T("Fg"), _T("DefLvFg"), m_crWindowText);
theApp.LoadSkinColorAlt(strKey + _T("Hl"), _T("DefLvHl"), crHighlight);
TCHAR szColor[MAX_PATH];
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))
if (SetBkImage(const_cast<LPTSTR>((LPCTSTR)strUrl), FALSE, 100, 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)) {
m_atSortArrow = atType;
HINSTANCE hInstRes = AfxFindResourceHandle(MAKEINTRESOURCE(m_atSortArrow), RT_BITMAP);
if (hInstRes != NULL){
HBITMAP hbmSortStates = (HBITMAP)::LoadImage(hInstRes, MAKEINTRESOURCE(m_atSortArrow), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS);
if (hbmSortStates != NULL){
CBitmap bmSortStates;
bmSortStates.Attach(hbmSortStates);
CImageList imlSortStates;
if (imlSortStates.Create(14, 14, theApp.m_iDfltImageListColorFlags | ILC_MASK, 1, 0)){
VERIFY( imlSortStates.Add(&bmSortStates, RGB(255, 0, 255)) != -1 );
// To avoid drawing problems (which occure only with an image list *with* a mask) while
// resizing list view columns which have the header control bitmap right aligned, set
// the background color of the image list.
if (theApp.m_ullComCtrlVer < MAKEDLLVERULL(6,0,0,0))
imlSortStates.SetBkColor(GetSysColor(COLOR_BTNFACE));
// When setting the image list for the header control for the first time we'll get
// the image list of the listview control!! So, better store the header control imagelist separate.
(void)pHeaderCtrl->SetImageList(&imlSortStates);
m_imlHeaderCtrl.DeleteImageList();
m_imlHeaderCtrl.Attach(imlSortStates.Detach());
// Use smaller bitmap margins -- this saves some pixels which may be required for
// rather small column titles.
if (theApp.m_ullComCtrlVer >= MAKEDLLVERULL(5,8,0,0)){
int iBmpMargin = pHeaderCtrl->SendMessage(HDM_GETBITMAPMARGIN);
int iNewBmpMargin = GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXEDGE)/2;
if (iNewBmpMargin < iBmpMargin)
pHeaderCtrl->SendMessage(HDM_SETBITMAPMARGIN, iNewBmpMargin);
}
}
}
}
headerItem.mask |= HDI_IMAGE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -