📄 searchresultpage.cpp
字号:
TResultNodeData* NodeData = (TResultNodeData*)ResultTree->GetNodeData(Node);
// should we download this file?
if(Config->GetValueInt("search/never_download_shared") && NodeData->LocalFile)
return;
// add first source
TDownload* Download = Engine->NewDownload(NodeData->Result,SaveFileName);
NodeData->Downloading = MarkDownloads;
// set number of max sources
int MaxSources = Config->GetValueInt("gift/max_sources");
Download->SetMaxSources(MaxSources < 1 ? 1 : MaxSources);
// add additional sources
Node = ResultTree->GetFirstChild(Node);
for(;Node;Node=ResultTree->GetNextSibling(Node)) {
NodeData = (TResultNodeData*)ResultTree->GetNodeData(Node);
Download->AddSource(NodeData->Result);
NodeData->Downloading = MarkDownloads;
}
// invalidate nodes so they get drawn with 'downloading' marker
ResultTree->InvalidateChildren(Node,true);
}
// popup menu
void __fastcall TSearchResultForm::DownloadMnuClick(TObject *Sender)
{
if(ResultTree->TreeOptions->SelectionOptions.Contains(toMultiSelect) &&
ResultTree->SelectedCount > 1)
{
// more than one file selected
ResultTree->BeginUpdate();
// first select all parents of selected children
TVirtualNode* Node = ResultTree->GetFirstSelected();
for(;Node;Node = ResultTree->GetNextSelected(Node)) {
if(ResultTree->GetNodeLevel(Node) > 0) {
// select parent
ResultTree->Selected[Node->Parent] = true;
ResultTree->Selected[Node] = false;
// start over because the selection array changed
Node = ResultTree->GetFirstSelected();
}
}
// now only download selected top nodes
Node = ResultTree->GetFirstSelected();
for(;Node;Node = ResultTree->GetNextSelected(Node)) {
if(ResultTree->GetNodeLevel(Node) == 0)
DownloadNode(Node);
}
ResultTree->EndUpdate();
} else {
// single file selected
TVirtualNode* Node = ResultTree->FocusedNode;
if(Node)
DownloadNode(Node);
}
}
void __fastcall TSearchResultForm::FindFileInLibraryMnuClick(
TObject *Sender)
{
if(!ResultTree->FocusedNode)
return;
TResultNodeData* NodeData = (TResultNodeData*)ResultTree->GetNodeData(ResultTree->FocusedNode);
// switches to library page if file is found
LibraryForm->FindFileByHash(NodeData->Result->GetHashes());
}
void __fastcall TSearchResultForm::FindMoreFromUserMnuClick(TObject *Sender)
{
if(!ResultTree->FocusedNode)
return;
TResultNodeData* NodeData = (TResultNodeData*)ResultTree->GetNodeData(ResultTree->FocusedNode);
SearchForm->RunSearch(NodeData->Result->GetUser()->GetId().c_str(), SRUser, NodeData->Result->Network.c_str());
}
void __fastcall TSearchResultForm::HideSingleSourcesMnuClick(
TObject *Sender)
{
ShowSingleSources = !ShowSingleSources;
ApplyFilter();
}
void __fastcall TSearchResultForm::CopyMagnetMnuClick(TObject *Sender)
{
if(!ResultTree->FocusedNode)
return;
TResultNodeData* NodeData = (TResultNodeData*)ResultTree->GetNodeData(ResultTree->FocusedNode);
Clipboard()->SetTextBuf((char*)NodeData->Result->GetMagnetStr().c_str());
}
void __fastcall TSearchResultForm::CopyTrackerMnuClick(TObject *Sender)
{
if(!ResultTree->FocusedNode)
return;
TResultNodeData* NodeData = (TResultNodeData*)ResultTree->GetNodeData(ResultTree->FocusedNode);
Clipboard()->SetTextBuf((char*)NodeData->Result->MetaData.Get("announce").c_str());
}
void __fastcall TSearchResultForm::GotoBitziMnuClick(TObject *Sender)
{
if(!ResultTree->FocusedNode)
return;
TResultNodeData* NodeData = (TResultNodeData*)ResultTree->GetNodeData(ResultTree->FocusedNode);
string Url = NodeData->Result->GetHashes()->GetBitziUrl();
if (Url == "")
return;
BrowserForm->NavigateTo(Url);
MainForm->SetVisiblePage(BrowserForm);
}
//---------------------------------------------------------------------------
string TSearchResultForm::GetTreeColumnKey(TSearchRealm Realm)
{
string Key = "tree_columns/results_";
switch(Realm) {
case SRAudio: Key += "audio"; break;
case SRVideo: Key += "video"; break;
case SRImage: Key += "images"; break;
case SRDocument: Key += "documents"; break;
case SRSoftware: Key += "software"; break;
case SRTorrent: Key += "torrents"; break;
case SRAny:
case SRSource:
case SRUser:
default: Key += "any"; break;
}
return Key;
}
void TSearchResultForm::SaveTreeColumns()
{
// save column positions specific for this search realm
Config->SetValue(GetTreeColumnKey(Search->GetRealm()),VTGetColumnSettings(ResultTree));
}
void __fastcall TSearchResultForm::ResultTreeHeaderMouseUp(
TVTHeader *Sender, TMouseButton Button, TShiftState Shift, int X,
int Y)
{
// the user most likely changed something in the header, save it now
SaveTreeColumns();
}
void __fastcall TSearchResultForm::ResultTreeHeaderPopupColumnChange(
const TBaseVirtualTree *Sender, const TColumnIndex Column,
bool Visible)
{
// save new visibility state
SaveTreeColumns();
}
//---------------------------------------------------------------------------
bool TSearchResultForm::IsNodeFiltered(TVirtualNode* Node)
{
static char Value[1024];
if(!Node)
return false;
TSearchResult* Result = ((TResultNodeData*)ResultTree->GetNodeData(Node))->Result;
if(!FilterPanel->Visible || FilterKeyCombo->ItemIndex <= 0 || FilterEdit->Text.Length() == 0)
return false;
string Key = FilterKeyCombo->Text.LowerCase().c_str();
string Filter = FilterEdit->Text.LowerCase().c_str();
// TODO: localization
if(Key == "Everything") {
// all keys
// check filename
strncpy(Value,Result->FileName.c_str(),1024)[1023] = 0;
strlwr(Value);
if(strstr(Value,Filter.c_str()))
return false;
// check all meta data
TMetaData::Iterator itr = Result->MetaData.Begin();
for(;itr!=Result->MetaData.End();++itr) {
strncpy(Value,(*itr).Value.c_str(),1024)[1023] = 0;
strlwr(Value);
if(strstr(Value,Filter.c_str()))
return false;
}
return true;
} else if(Key == "size" || Key == "bitrate" || Key == "mediasize") {
// integer cmp
enum { gt, lt, eq } FilterCmp;
int FilterInt;
int ValueInt;
// get cmp mode and integer
if(Filter[0] == '>') {
FilterCmp = gt;
FilterInt = string_to_int(Filter.substr(1));
} else if(Filter[0] == '<') {
FilterCmp = lt;
FilterInt = string_to_int(Filter.substr(1));
} else {
FilterCmp = eq;
FilterInt = string_to_int(Filter);
}
// prepare integer to check
if(Key == "size")
ValueInt = Result->FileSize / 1024 / 1024; // MB
else if (Key == "mediasize")
ValueInt = Result->MetaData.GetInt("mediasize") / 1024 / 1024; // MB
else if (Key == "bitrate")
ValueInt = Result->MetaData.GetInt("bitrate") / 1000; // kbps
else
ValueInt = 0; // cannot happen
// do the actual compare
switch(FilterCmp) {
case eq: return !(ValueInt == FilterInt);
case gt: return !(ValueInt >= FilterInt);
case lt: return !(ValueInt <= FilterInt);
}
} else {
// substr cmp
if(Key == "filename")
strncpy(Value,Result->FileName.c_str(),1024)[1023] = 0;
else
strncpy(Value,Result->MetaData.Get(Key.c_str()).c_str(),1024)[1023] = 0;
strlwr(Value);
if(strstr(Value,Filter.c_str()) == NULL)
return true;
}
return false;
}
void TSearchResultForm::ApplyFilter()
{
// hide all filtered nodes
ResultTree->BeginUpdate();
TVirtualNode* ParentNode = ResultTree->GetFirst();
for(;ParentNode;ParentNode=ResultTree->GetNextSibling(ParentNode)) {
if(ResultTree->HasChildren[ParentNode]) {
// check this node
ResultTree->IsVisible[ParentNode] = !IsNodeFiltered(ParentNode);
if(ResultTree->IsVisible[ParentNode])
continue;
// enable node if a child is not filtered
TVirtualNode* Node = ResultTree->GetFirstChild(ParentNode);
for(;Node;Node=ResultTree->GetNextSibling(Node)) {
if(!IsNodeFiltered(Node)) {
ResultTree->IsVisible[ParentNode] = true;
break;
}
}
} else {
ResultTree->IsVisible[ParentNode] = !IsNodeFiltered(ParentNode) && ShowSingleSources;
}
}
ResultTree->EndUpdate();
}
// this is also called on FilterKeyCombo changes
void __fastcall TSearchResultForm::FilterEditChange(TObject *Sender)
{
// apply filter
ApplyFilter();
// save filter
string LastFilter = string(FilterKeyCombo->Text.c_str()) + "|" + FilterEdit->Text.c_str();
Config->SetValue("search/last_filter",LastFilter);
}
//---------------------------------------------------------------------------
void __fastcall TSearchResultForm::ResultTreeKeyAction(
TBaseVirtualTree *Sender, WORD &CharCode, TShiftState &Shift,
bool &DoDefault)
{
TVirtualNode* Node;
if(!ResultTree->TreeOptions->SelectionOptions.Contains(toMultiSelect))
return;
if(!Shift.Contains(ssCtrl))
return;
switch (CharCode) {
case VK_DOWN:
// explorer style multi selection with keyboard
if((Node = Sender->FocusedNode))
Node = Sender->GetNextVisible(Node);
else
Node = Sender->GetFirstVisible();
if(Node)
Sender->FocusedNode = Node;
DoDefault = false;
CharCode = 0;
return;
case VK_UP:
// explorer style multi selection with keyboard
if((Node = Sender->FocusedNode))
Node = Sender->GetPreviousVisible(Node);
else
Node = Sender->GetFirstVisible();
if(Node)
Sender->FocusedNode = Node;
DoDefault = false;
CharCode = 0;
return;
case VK_SPACE:
// explorer style multi selection with keyboard
if((Node = Sender->FocusedNode))
Sender->Selected[Node] = !Sender->Selected[Node];
DoDefault = false;
CharCode = 0;
return;
case VK_RIGHT:
// explorer style multi selection with keyboard
if((Node = Sender->FocusedNode))
Sender->Expanded[Node] = true;
DoDefault = false;
CharCode = 0;
return;
case VK_LEFT:
// explorer style multi selection with keyboard
if((Node = Sender->FocusedNode))
Sender->Expanded[Node] = false;
DoDefault = false;
CharCode = 0;
return;
}
}
//---------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -