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

📄 searchresultpage.cpp

📁 Last change: 2008-02-03 This is the source code of KCeasy。
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
This file is part of KCeasy (http://www.kceasy.com)
Copyright (C) 2002-2004 Markus Kern <mkern@kceasy.com>

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.
*/
//---------------------------------------------------------------------------
#include <vcl.h>
#include <KCeasy.h>
#pragma hdrstop

#include <Clipbrd.hpp>
#include <Math.hpp>
#include "SearchResultPage.h"
#include "SearchPage.h"
#include "BrowserPage.h"
#include "LibraryPage.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "VTHeaderPopup"
#pragma resource "*.dfm"
#pragma link "VirtualTrees"
//TSearchResultFrame *SearchResultFrame;
//---------------------------------------------------------------------------

// number of times user can try 'Search Again', -1 means unlimited
const int MaxSearchAgainCount = -1;

//---------------------------------------------------------------------------
__fastcall TSearchResultForm::TSearchResultForm(TComponent* Owner,
      TSearch* NSearch, AnsiString& NTabCaption)
:   Search(NSearch),
    TabCaption(NTabCaption),
    TForm(Owner),
    NoOfResults(0),
    NoOfUniqueResults(0),
    NoOfMultiSourceResults(0),
    UseSystemIcons(true),
    ShowSingleSources(true),
    ShowRawUserNames(true),
    SearchAgainCount(0),
    BeFunny(false)
{
    // don't translate filter until doing so doesn't brake it
    TP_Ignore(this,"FilterKeyCombo.Items");
    TranslateComponent(this);
    ResultTree->NodeDataSize = sizeof(TResultNodeData);

    if(Config->GetValueInt("search/allow_multiselect")) {
        ResultTree->TreeOptions->SelectionOptions << toMultiSelect;
        ResultTree->TreeOptions->PaintOptions >> toHideFocusRect;
    }
    // load column positions specific for this search realm
    VTSetColumnSettings(ResultTree,Config->GetValue(GetTreeColumnKey(Search->GetRealm())));

    StopSearchBtn->Enabled = false;
    SearchAgainBtn->Enabled = false;
    DownloadBtn->Enabled = false;
    QueryStatic->DoubleBuffered = true;

    // load availability bitmap and split it up
    Graphics::TBitmap* AvailBmp = new Graphics::TBitmap();
    AvailBmp->LoadFromResourceName((unsigned int)HInstance,"AVAILABILITY_BMP");
    for(int i=0; i<AVAILABILITY_BMP_LEN; i++) {
        AvailBitmaps[i] = new Graphics::TBitmap();
        AvailBitmaps[i]->Width = AvailBmp->Width;
        AvailBitmaps[i]->Height = 14;
        TRect DstRect(0,0,AvailBmp->Width,AvailBitmaps[i]->Height);
        TRect SrcRect(0,i*14,AvailBmp->Width,i*14+14);
        AvailBitmaps[i]->Canvas->CopyRect(DstRect,AvailBmp->Canvas,SrcRect);
        AvailBitmaps[i]->TransparentMode = tmAuto;
        AvailBitmaps[i]->Transparent = true;
    }

    delete AvailBmp;

    if(Search->GetNetwork() == "")
        // TRANSLATOR: "QUERY on NETWORK" in search result header.
        RealmStatic->Caption = AnsiString::Format(_("%s on %s"),
                               // TRANSLATOR: All Networks in search result header.
                               ARRAYOFCONST((TSearch::RealmToString(Search->GetRealm()), _("All Networks"))));
    else
        // TRANSLATOR: "QUERY on NETWORK" in search result header.
        RealmStatic->Caption = AnsiString::Format(_("%s on %s"),ARRAYOFCONST((TSearch::RealmToString(Search->GetRealm()),Search->GetNetwork().c_str())));
    QueryStatic->Caption = Search->GetQuery().c_str();
    ResultCountLbl->Caption =  AnsiString::Format("%d / %d",ARRAYOFCONST((NoOfMultiSourceResults, NoOfUniqueResults)));

    MarkLocalFiles = Config->GetValueInt("search/highlight_shared");
    MarkDownloads = Config->GetValueInt("search/highlight_downloads");
    UseSystemIcons = Config->GetValueInt("gui/use_system_file_icons");
    ShowRawUserNames = Config->GetValueInt("search/show_raw_user_names");
    ShowSingleSources = !Config->GetValueInt("search/filter_single_source_replies");
    SortByAlphaNum = Config->GetValueInt("search/sort_by_alphanum");

    // load filter settings
    FilterPanel->Visible = Config->GetValueInt("search/enable_filtering");
    list<string> LastFilter = string_split(Config->GetValue("search/last_filter"),"|");
    if(LastFilter.size() == 2) {
        FilterKeyCombo->ItemIndex = FilterKeyCombo->Items->IndexOf(LastFilter.front().c_str());
        if(FilterKeyCombo->ItemIndex == -1)
            FilterKeyCombo->ItemIndex = 0;
        FilterEdit->Text = LastFilter.back().c_str();
    }

    // are we funny today?
    char* FunnyAppName = Base64Encode(BRAND_APP_NAME,sizeof(BRAND_APP_NAME)-1);
    BeFunny = stricmp(FunnyAppName,BRAND_APP_NAME_BASE64);
    delete[] FunnyAppName;
}

__fastcall TSearchResultForm::~TSearchResultForm()
{
    for(int i=0; i<AVAILABILITY_BMP_LEN; i++)
        delete AvailBitmaps[i];
}
//---------------------------------------------------------------------------

bool __fastcall TSearchResultForm::EngineCallback(TCallbackInfo* CbInfo)
{
    switch(CbInfo->Code) {
    case CbcStateChange:
        if(Engine->IsOffline()) {
            ResultTree->Clear();
        }
        return true;
    case CbcNewSearch:
        return true;
    case CbcSearchRemoved:
        // clear tree so we don't reference results which are already removed
        if(((TSearch*)CbInfo->Data1) != Search)
            return false;

        ResultTree->Clear();
        return true;
    case CbcSearchBegin: {
        if(((TSearch*)CbInfo->Data1) != Search)
            return false;
        StopSearchBtn->Enabled = true;

        if(Search->GetNetwork() == "")
            // TRANSLATOR: "QUERY on NETWORK" in search result header.
            RealmStatic->Caption = AnsiString::Format(_("%s on %s"),
                                   // TRANSLATOR: All Networks in search result header.
                                   ARRAYOFCONST((TSearch::RealmToString(Search->GetRealm()), _("All Networks"))));
        else
            // TRANSLATOR: "QUERY on NETWORK" in search result header.
            RealmStatic->Caption = AnsiString::Format(_("%s on %s"), ARRAYOFCONST((TSearch::RealmToString(Search->GetRealm()),Search->GetNetwork().c_str())));
        QueryStatic->Caption = Search->GetQuery().c_str();
        ResultCountLbl->Caption = AnsiString::Format("%d / %d", ARRAYOFCONST((NoOfMultiSourceResults, NoOfUniqueResults)));

        return true;
    }
    case CbcSearchResult: {
        if(((TSearch*)CbInfo->Data1) != Search)
            return false;

        list<TSearchResult*>* ResultList = ((list<TSearchResult*> *)CbInfo->Data2);
        ResultTree->BeginUpdate();

        list<TSearchResult*>::iterator ritr = ResultList->begin();
        for(;ritr != ResultList->end(); ++ritr) {
            TSearchResult* Result = (*ritr);

            // this is what i mean by funny
            if(BeFunny && RandomRange(0,20) != 10)
                continue;

        // group same files if a hash is present
        TVirtualNode* ParentNode = NULL;
        if(Result->GetHashes()->Size() != 0) {
            for(ParentNode = ResultTree->GetFirst(); ParentNode; ParentNode=ResultTree->GetNextSibling(ParentNode))
                if(((TResultNodeData*)ResultTree->GetNodeData(ParentNode))->Result->GetHashes()->Equals(Result->GetHashes()))
                    break;
        }

        if(ParentNode && !ResultTree->HasChildren[ParentNode])
            NoOfMultiSourceResults++;

        TVirtualNode* Node = ResultTree->AddChild(ParentNode);
        TResultNodeData* ResultNodeData = (TResultNodeData*)ResultTree->GetNodeData(Node);
        // call constructor using placement new
        new(ResultNodeData) TResultNodeData();
        ResultNodeData->Result = Result;

        if(UseSystemIcons)
            ResultNodeData->ImageIndex = MainForm->IconManager->GetIconIndex(Result->FileName);
        else
            ResultNodeData->ImageIndex = MainForm->IconManager->GetIconIndex(Result->FileType);
        ResultNodeData->NetworkImageIndex = MainForm->IconManager->GetNetworkIconIndex(Result->Network);
        // normalize availability
        ResultNodeData->EffectiveAvail = Result->Availability > 0 ? 1 : 0;
        ResultNodeData->TimeFound = TDateTime::CurrentDateTime(); 

        if(ParentNode) {
            TResultNodeData* ParentResultNodeData = (TResultNodeData*)ResultTree->GetNodeData(ParentNode);

            ResultNodeData->Downloading = ParentResultNodeData->Downloading;
            ResultNodeData->LocalFile = ParentResultNodeData->LocalFile;
            if(ResultTree->IsVisible[ParentNode] == false)
                ResultTree->IsVisible[ParentNode] = !IsNodeFiltered(Node);
            // update parent availability
            ParentResultNodeData->EffectiveAvail += ResultNodeData->EffectiveAvail > 0 ? 1 : 0;
            // add result's ip to parent
            ParentResultNodeData->AddIP(Result->GetUser()->GetIP());
        } else {
            ResultTree->IsVisible[Node] = ShowSingleSources && !IsNodeFiltered(Node);

            NoOfUniqueResults++;
            // is this a local file?
            ResultNodeData->LocalFile = MarkLocalFiles && Engine->GetShares()->GetFileByHashes(Result->GetHashes()) != NULL;
            // is this a file we are currently downloading?
            ResultNodeData->Downloading = MarkDownloads && Engine->GetDownloadByHashes(Result->GetHashes()) != NULL;
            // add ip to ourselves since we are parent
            ResultNodeData->AddIP(Result->GetUser()->GetIP());
        }

        NoOfResults++;

        // if new result has meta data and parent node has not exchang the two
        TResultNodeData* ParentResultNodeData = (TResultNodeData*)ResultTree->GetNodeData(ParentNode);
        if(ParentNode && ParentResultNodeData->Result->MetaData.Empty() &&
           !ResultNodeData->Result->MetaData.Empty())
        {
            // make new node sibling of parent
            ResultTree->MoveTo(Node,ParentNode,amInsertAfter,false);
            // make all children of parent children of new node
            ResultTree->MoveTo(ParentNode,Node,amAddChildFirst,true);
            // make parent node child of new node
            ResultTree->MoveTo(ParentNode,Node,amAddChildFirst,false);
            // HACKHACK: brittle code ahead
            // update availability
            ResultNodeData->EffectiveAvail = ParentResultNodeData->EffectiveAvail;
            ParentResultNodeData->EffectiveAvail = ParentResultNodeData->Result->Availability > 0 ? 1 : 0;
            // update IP stuff
#if 0
            ResultNodeData->IPs = ParentResultNodeData->IPs;
            ResultNodeData->IPCount = ParentResultNodeData->IPCount;
            ResultNodeData->UniqueToTotal = ParentResultNodeData->UniqueToTotal;
            ParentResultNodeData->IPs.clear();
#endif            
        }

        } // for each result

        ResultTree->EndUpdate();

        // update results count
        ResultCountLbl->Caption = AnsiString::Format("%d / %d", ARRAYOFCONST((NoOfMultiSourceResults, NoOfUniqueResults)));
        SearchForm->SetTabCaption(this,TabCaption + AnsiString::Format(" (%d)", ARRAYOFCONST((NoOfResults))));
        return true;
    }
    case CbcSearchEnd:
        if(((TSearch*)CbInfo->Data1) != Search)
            return false;

        StopSearchBtn->Enabled = false;
        // enabled search again button if we are below the limit
        if(MaxSearchAgainCount == -1 || SearchAgainCount < MaxSearchAgainCount) {
            SearchAgainBtn->Enabled = true;
            SearchAgainCount++;
        }

        // update results count
        ResultCountLbl->Caption = AnsiString::Format("%d / %d", ARRAYOFCONST((NoOfMultiSourceResults, NoOfUniqueResults)));
        SearchForm->SetTabCaption(this,TabCaption + AnsiString::Format(" (%d)", ARRAYOFCONST((NoOfResults))));
        return true;
    }
    return false;
}
//---------------------------------------------------------------------------

void __fastcall TSearchResultForm::CloseSearchBtnClick(TObject *Sender)
{
    Engine->RemoveSearch(Search); // may send us cached results
    ResultTree->Clear();
    SearchForm->CloseSearch(this);
}

void __fastcall TSearchResultForm::StopSearchBtnClick(TObject *Sender)
{
    Search->Cancel();
}

void __fastcall TSearchResultForm::SearchAgainBtnClick(TObject *Sender)
{
    Search->Start();
    SearchAgainBtn->Enabled = false;
}

void __fastcall TSearchResultForm::DownloadBtnClick(
      TObject *Sender)
{
    DownloadMnuClick(NULL);
}

void __fastcall TSearchResultForm::ChangeHeaderBtnClick(TObject *Sender)
{
    TPoint Pt = TPoint(ChangeHeaderBtn->Left + ChangeHeaderBtn->Width,
                       ChangeHeaderBtn->Top + ChangeHeaderBtn->Height);
    Pt = ChangeHeaderBtn->Parent->ClientToScreen(Pt);
    ResultTreeHeaderPopup->PopupComponent = ResultTree;
    ResultTreeHeaderPopup->Alignment = paRight;
    ResultTreeHeaderPopup->Popup(Pt.x,Pt.y);
}
//---------------------------------------------------------------------------

void __fastcall TSearchResultForm::ResultTreeFreeNode(
      TBaseVirtualTree *Sender, PVirtualNode Node)
{
    // call TResultNodeData destructor
    ((TResultNodeData*)Sender->GetNodeData(Node))->~TResultNodeData();
}
//---------------------------------------------------------------------------

void __fastcall TSearchResultForm::ResultTreeGetText(
      TBaseVirtualTree *Sender, PVirtualNode Node, TColumnIndex Column,
      TVSTTextType TextType, WideString &CellText)
{
    if(TextType != ttNormal)
        return;
    TSearchResult* Result = ((TResultNodeData*)Sender->GetNodeData(Node))->Result;

    switch(Column) {
    case 0: // file name
        CellText = Result->FileName.c_str(); break;
    case 1: // media type
        switch(Result->FileType) {
        // TRANSLATOR: Media type in search results.
        case FTAudio:       CellText = _("Audio");    break;
        // TRANSLATOR: Media type in search results.
        case FTVideo:       CellText = _("Video");    break;
        // TRANSLATOR: Media type in search results.
        case FTImage:       CellText = _("Image");    break;
        // TRANSLATOR: Media type in search results.
        case FTDocument:    CellText = _("Document"); break;
        // TRANSLATOR: Media type in search results.
        case FTSoftware:    CellText = _("Software"); break;
        // TRANSLATOR: Media type in search results.
        case FTTorrent:     CellText = _("Torrent");  break;
        // TRANSLATOR: Media type in search results.
        case FTUnknown:     CellText = _("Unknown");  break;
        }
        break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -