📄 searchlistctrl.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 "ResizableLib/ResizableSheet.h"
#include "SearchList.h"
#include "emuledlg.h"
#include "MetaDataDlg.h"
#include "SearchDlg.h"
#include "SearchListCtrl.h"
#include "SearchParams.h"
#include "ClosableTabCtrl.h"
#include "PreviewDlg.h"
#include "UpDownClient.h"
#include "ClientList.h"
#include "MemDC.h"
#include "SharedFileList.h"
#include "DownloadQueue.h"
#include "PartFile.h"
#include "KnownFileList.h"
#include "MenuCmds.h"
#include "OtherFunctions.h"
#include "Opcodes.h"
#include "Packets.h"
#include "WebServices.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////////////
// CSearchResultFileDetailSheet
class CSearchResultFileDetailSheet : public CResizableSheet
{
DECLARE_DYNAMIC(CSearchResultFileDetailSheet)
public:
CSearchResultFileDetailSheet(const CSearchFile* file);
virtual ~CSearchResultFileDetailSheet();
protected:
const CSearchFile* m_file;
CMetaDataDlg m_wndMetaData;
static int sm_iLastActivePage;
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
afx_msg void OnDestroy();
};
int CSearchResultFileDetailSheet::sm_iLastActivePage;
IMPLEMENT_DYNAMIC(CSearchResultFileDetailSheet, CResizableSheet)
BEGIN_MESSAGE_MAP(CSearchResultFileDetailSheet, CResizableSheet)
ON_WM_DESTROY()
END_MESSAGE_MAP()
CSearchResultFileDetailSheet::CSearchResultFileDetailSheet(const CSearchFile* file)
{
m_file = file;
m_psh.dwFlags &= ~PSH_HASHELP;
m_psh.dwFlags |= PSH_NOAPPLYNOW;
m_wndMetaData.m_psp.dwFlags &= ~PSP_HASHELP;
if (thePrefs.IsExtControlsEnabled())
m_wndMetaData.SetFile(file);
if (thePrefs.IsExtControlsEnabled())
AddPage(&m_wndMetaData);
}
CSearchResultFileDetailSheet::~CSearchResultFileDetailSheet()
{
}
void CSearchResultFileDetailSheet::OnDestroy()
{
sm_iLastActivePage = GetActiveIndex();
CResizableSheet::OnDestroy();
}
BOOL CSearchResultFileDetailSheet::OnInitDialog()
{
EnableStackedTabs(FALSE);
BOOL bResult = CResizableSheet::OnInitDialog();
InitWindowStyles(this);
EnableSaveRestore(_T("SearchResultFileDetailsSheet")); // call this after(!) OnInitDialog
SetWindowText(GetResString(IDS_DETAILS) + _T(": ") + m_file->GetFileName());
if (sm_iLastActivePage < GetPageCount())
SetActivePage(sm_iLastActivePage);
return bResult;
}
//////////////////////////////////////////////////////////////////////////////
// CSearchListCtrl
#define DLC_DT_TEXT (DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS)
IMPLEMENT_DYNAMIC(CSearchListCtrl, CMuleListCtrl)
CSearchListCtrl::CSearchListCtrl()
{
searchlist = NULL;
m_nResultsID = 0;
SetGeneralPurposeFind(true);
}
void CSearchListCtrl::SetStyle()
{
if (thePrefs.IsDoubleClickEnabled())
SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
else
SetExtendedStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
}
void CSearchListCtrl::Init(CSearchList* in_searchlist)
{
CImageList ilDummyImageList; //dummy list for getting the proper height of listview entries
ilDummyImageList.Create(1, theApp.GetSmallSytemIconSize().cy,theApp.m_iDfltImageListColorFlags|ILC_MASK, 1, 1);
SetImageList(&ilDummyImageList, LVSIL_SMALL);
ASSERT( (GetStyle() & LVS_SHAREIMAGELISTS) == 0 );
ilDummyImageList.Detach();
ModifyStyle(LVS_SINGLESEL,0);
SetStyle();
CToolTipCtrl* tooltip = GetToolTips();
if (tooltip){
tooltip->ModifyStyle(0, TTS_NOPREFIX);
tooltip->SetDelayTime(TTDT_AUTOPOP, 20000);
tooltip->SetDelayTime(TTDT_INITIAL, thePrefs.GetToolTipDelay()*1000);
}
searchlist = in_searchlist;
InsertColumn(0,GetResString(IDS_DL_FILENAME),LVCFMT_LEFT,250);
InsertColumn(1,GetResString(IDS_DL_SIZE),LVCFMT_LEFT,70);
InsertColumn(2,GetResString(IDS_SEARCHAVAIL) + (thePrefs.IsExtControlsEnabled() ? _T(" (") + GetResString(IDS_DL_SOURCES) + _T(')') : _T("")),LVCFMT_LEFT,50);
InsertColumn(3,GetResString(IDS_COMPLSOURCES),LVCFMT_LEFT,50);
InsertColumn(4,GetResString(IDS_TYPE),LVCFMT_LEFT,65);
InsertColumn(5,GetResString(IDS_FILEID),LVCFMT_LEFT,220);
InsertColumn(6,GetResString(IDS_ARTIST),LVCFMT_LEFT,100);
InsertColumn(7,GetResString(IDS_ALBUM),LVCFMT_LEFT,100);
InsertColumn(8,GetResString(IDS_TITLE),LVCFMT_LEFT,100);
InsertColumn(9,GetResString(IDS_LENGTH),LVCFMT_LEFT,50);
InsertColumn(10,GetResString(IDS_BITRATE),LVCFMT_LEFT,50);
InsertColumn(11,GetResString(IDS_CODEC),LVCFMT_LEFT,50);
InsertColumn(12,GetResString(IDS_FOLDER),LVCFMT_LEFT,220);
InsertColumn(13,GetResString(IDS_KNOWN),LVCFMT_LEFT,50);
CreateMenues();
LoadSettings(CPreferences::tableSearch);
// Barry - Use preferred sort order from preferences
int sortItem = thePrefs.GetColumnSortItem(CPreferences::tableSearch);
if (sortItem != -1){// don't force a sorting if '-1' is specified, so we can better see how the search results are arriving
bool sortAscending = thePrefs.GetColumnSortAscending(CPreferences::tableSearch);
SetSortArrow(sortItem, sortAscending);
SortItems(SortProc, sortItem + (sortAscending ? 0:100));
}
}
CSearchListCtrl::~CSearchListCtrl(){
}
void CSearchListCtrl::Localize()
{
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
HDITEM hdi;
hdi.mask = HDI_TEXT;
CString strRes;
for (int icol=0;icol<pHeaderCtrl->GetItemCount();icol++) {
switch (icol) {
case 0: strRes = GetResString(IDS_DL_FILENAME); break;
case 1: strRes = GetResString(IDS_DL_SIZE); break;
case 2: strRes = GetResString(IDS_SEARCHAVAIL) + (thePrefs.IsExtControlsEnabled() ? _T(" (") + GetResString(IDS_DL_SOURCES) + _T(')') : _T("")); break;
case 3: strRes = GetResString(IDS_COMPLSOURCES); break;
case 4: strRes = GetResString(IDS_TYPE); break;
case 5: strRes = GetResString(IDS_FILEID); break;
case 6: strRes = GetResString(IDS_ARTIST); break;
case 7: strRes = GetResString(IDS_ALBUM); break;
case 8: strRes = GetResString(IDS_TITLE); break;
case 9: strRes = GetResString(IDS_LENGTH); break;
case 10: strRes = GetResString(IDS_BITRATE); break;
case 11: strRes = GetResString(IDS_CODEC); break;
case 12: strRes = GetResString(IDS_FOLDER); break;
case 13: strRes = GetResString(IDS_KNOWN); break;
}
hdi.pszText = strRes.GetBuffer();
pHeaderCtrl->SetItem(icol, &hdi);
strRes.ReleaseBuffer();
}
CreateMenues();
}
BEGIN_MESSAGE_MAP(CSearchListCtrl, CMuleListCtrl)
ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
ON_WM_CONTEXTMENU()
ON_NOTIFY_REFLECT(LVN_GETINFOTIP, OnLvnGetInfoTip)
ON_NOTIFY_REFLECT(LVN_DELETEALLITEMS, OnLvnDeleteallitems)
ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
ON_NOTIFY_REFLECT(NM_DBLCLK,OnDblClick)
ON_WM_KEYDOWN()
END_MESSAGE_MAP()
// CSearchListCtrl message handlers
void CSearchListCtrl::AddResult(const CSearchFile* toshow)
{
// update tab-counter for the given searchfile
CClosableTabCtrl& searchselect = theApp.emuledlg->searchwnd->GetSearchSelector();
int iTabItems = searchselect.GetItemCount();
if (iTabItems > 0)
{
TCITEM tabitem;
tabitem.mask = TCIF_PARAM;
tabitem.lParam = -1;
for (int tabCounter = 0; tabCounter < iTabItems; tabCounter++)
{
if (searchselect.GetItem(tabCounter, &tabitem) && tabitem.lParam != NULL)
{
if (((const SSearchParams*)tabitem.lParam)->dwSearchID == toshow->GetSearchID())
{
TCHAR szText[MAX_SEARCH_EXPRESSION_LEN+1];
tabitem.pszText = szText;
tabitem.cchTextMax = ARRSIZE(szText);
tabitem.mask = TCIF_TEXT;
if (searchselect.GetItem(tabCounter, &tabitem))
{
// TODO: Searching for the last '(' is wrong.
// If the search expression contains '(' and ')' characters, we'll truncate the string.
LPTSTR psz = _tcsrchr(szText, _T('('));
if (psz){
if (psz > szText)
psz--;
*psz = _T('\0');
}
CString sourceStr;
sourceStr.Format(_T("%s (%u)"), szText, searchlist->GetFoundFiles(toshow->GetSearchID()));
tabitem.pszText = const_cast<LPTSTR>((LPCTSTR)sourceStr);
searchselect.SetItem(tabCounter, &tabitem);
if (searchselect.GetCurSel() != tabCounter)
searchselect.HighlightItem(tabCounter);
}
break;
}
}
}
}
if (toshow->GetSearchID() != m_nResultsID)
return;
//TODO: Here we have a problem. Since this listview control is owner drawn the listview items may no longer
//contain the actual information which is displayed. The usage of the 'Find' command may therefore deal with
//wrong item contents (which are stored in the listview items right here in this function).
int itemnr = InsertItem(LVIF_TEXT|LVIF_PARAM,GetItemCount(),toshow->GetFileName(),0,0,0,(LPARAM)toshow);
SetItemText(itemnr,1,CastItoXBytes(toshow->GetFileSize(), false, false));
CString strBuffer;
uint32 nSources = toshow->GetSourceCount();
int iClients = toshow->GetClientsCount();
if ( thePrefs.IsExtControlsEnabled() && iClients > 0)
strBuffer.Format(_T("%u (%u)"), nSources, iClients);
else
strBuffer.Format(_T("%u"), nSources);
SetItemText(itemnr,2,strBuffer);
uint32 uCompleteSources;
if (toshow->IsKademlia())
strBuffer = _T("?");
else{
if ( (uCompleteSources = toshow->GetIntTagValue(FT_COMPLETE_SOURCES)) > 0 && nSources > 0)
strBuffer.Format(_T("%u%%"), (uCompleteSources*100)/nSources);
else
strBuffer = _T("0%");
}
SetItemText(itemnr,3,strBuffer);
SetItemText(itemnr,4,toshow->GetFileTypeDisplayStr());
SetItemText(itemnr,5,md4str(toshow->GetFileHash()));
SetItemText(itemnr,6,toshow->GetStrTagValue(FT_MEDIA_ARTIST));
SetItemText(itemnr,7,toshow->GetStrTagValue(FT_MEDIA_ALBUM));
SetItemText(itemnr,8,toshow->GetStrTagValue(FT_MEDIA_TITLE));
uint32 nMediaLength = toshow->GetIntTagValue(FT_MEDIA_LENGTH);
TCHAR cbuffer[80];
if (nMediaLength){
CString strMediaLength;
SecToTimeLength(nMediaLength, strMediaLength);
_sntprintf(cbuffer,ARRSIZE(cbuffer),_T("%s"),strMediaLength);
}
else
cbuffer[0] = _T('\0');
SetItemText(itemnr,9,cbuffer);
uint32 nBitrate = toshow->GetIntTagValue(FT_MEDIA_BITRATE);
if (nBitrate)
_sntprintf(cbuffer,ARRSIZE(cbuffer),_T("%u kBit/s"),nBitrate);
else
cbuffer[0] = _T('\0');
SetItemText(itemnr,10,cbuffer);
SetItemText(itemnr,11,toshow->GetStrTagValue(FT_MEDIA_CODEC));
if (toshow->GetDirectory())
SetItemText(itemnr,12,toshow->GetDirectory());
if (toshow->m_eKnown == CSearchFile::Shared)
SetItemText(itemnr,13,GetResString(IDS_SHARED));
else if (toshow->m_eKnown == CSearchFile::Downloading)
SetItemText(itemnr,13,GetResString(IDS_DOWNLOADING));
else if (toshow->m_eKnown == CSearchFile::Downloaded)
SetItemText(itemnr,13,GetResString(IDS_DOWNLOADED));
}
void CSearchListCtrl::UpdateSources(const CSearchFile* toupdate)
{
LVFINDINFO find;
find.flags = LVFI_PARAM;
find.lParam = (LPARAM)toupdate;
int index = FindItem(&find);
if (index != (-1)){
CString strBuffer;
uint32 nSources = toupdate->GetSourceCount();
int iClients = toupdate->GetClientsCount();
if ( thePrefs.IsExtControlsEnabled() && iClients > 0)
strBuffer.Format(_T("%u (%u)"), nSources, iClients);
else
strBuffer.Format(_T("%u"), nSources);
SetItemText(index,2,strBuffer);
uint32 uCompleteSources;
if (toupdate->IsKademlia())
strBuffer = _T("?");
else{
if ( (uCompleteSources = toupdate->GetIntTagValue(FT_COMPLETE_SOURCES)) > 0 && nSources > 0)
strBuffer.Format(_T("%u%%"), (uCompleteSources*100)/nSources);
else
strBuffer = _T("0%");
}
SetItemText(index,3,strBuffer);
uint16 maxhitsname = (uint16)-1;
bool change=false;
CString strFileName = toupdate->GetFileName();
// update expanded childs
if (toupdate->GetListIsExpanded()) {
for (POSITION pos = theApp.searchlist->list.GetHeadPosition(); pos != NULL; ){
const CSearchFile* cur_file = theApp.searchlist->list.GetNext(pos);
if (cur_file->GetListParent()==toupdate) {
if (maxhitsname<cur_file->GetListChildCount()) {
maxhitsname=cur_file->GetListChildCount();
strFileName=cur_file->GetFileName();
change=true;
}
// i am your child, darth! but do I exist? Do I?
LVFINDINFO find;
find.flags = LVFI_PARAM;
find.lParam = (LPARAM)cur_file;
int index2 = FindItem(&find);
if (index2!=-1)
// yes, I see you...
Update(index2);
else
// no, but I create you now for display
InsertItem(LVIF_PARAM|LVIF_TEXT,index+1,cur_file->GetFileName(),0,0,0,(LPARAM)cur_file);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -