debian: fix build-deps for focal
[amule.git] / src / SearchDlg.cpp
blob085ac6da14cb2e91ae91ec18b16de7162ce8cb08
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <wx/app.h>
28 #include <wx/gauge.h> // Do_not_auto_remove (win32)
30 #include <tags/FileTags.h>
32 #include "SearchDlg.h" // Interface declarations.
33 #include "SearchListCtrl.h" // Needed for CSearchListCtrl
34 #include "muuli_wdr.h" // Needed for IDC_STARTS
35 #include "amuleDlg.h" // Needed for CamuleDlg
36 #include "MuleNotebook.h"
37 #include "GetTickCount.h"
38 #include "Preferences.h"
39 #include "amule.h" // Needed for theApp
40 #include "SearchList.h" // Needed for CSearchList
41 #include <common/Format.h>
42 #include "Logger.h"
44 #define ID_SEARCHLISTCTRL wxID_HIGHEST+667
46 // just to keep compiler happy
47 static wxCommandEvent nullEvent;
49 BEGIN_EVENT_TABLE(CSearchDlg, wxPanel)
50 EVT_BUTTON( IDC_STARTS, CSearchDlg::OnBnClickedStart)
51 EVT_TEXT_ENTER( IDC_SEARCHNAME, CSearchDlg::OnBnClickedStart)
53 EVT_BUTTON(IDC_CANCELS, CSearchDlg::OnBnClickedStop)
55 EVT_LIST_ITEM_SELECTED(ID_SEARCHLISTCTRL, CSearchDlg::OnListItemSelected)
57 EVT_BUTTON(IDC_SDOWNLOAD, CSearchDlg::OnBnClickedDownload)
58 EVT_BUTTON(IDC_SEARCH_RESET, CSearchDlg::OnBnClickedReset)
59 EVT_BUTTON(IDC_CLEAR_RESULTS, CSearchDlg::OnBnClickedClear)
61 EVT_CHECKBOX(IDC_EXTENDEDSEARCHCHECK,CSearchDlg::OnExtendedSearchChange)
62 EVT_CHECKBOX(IDC_FILTERCHECK,CSearchDlg::OnFilterCheckChange)
64 EVT_MULENOTEBOOK_PAGE_CLOSING(ID_NOTEBOOK, CSearchDlg::OnSearchClosing)
65 EVT_NOTEBOOK_PAGE_CHANGED(ID_NOTEBOOK, CSearchDlg::OnSearchPageChanged)
67 // Event handlers for the parameter fields getting changed
68 EVT_CUSTOM( wxEVT_COMMAND_TEXT_UPDATED, IDC_SEARCHNAME, CSearchDlg::OnFieldChanged)
69 EVT_CUSTOM( wxEVT_COMMAND_TEXT_UPDATED, IDC_EDITSEARCHEXTENSION, CSearchDlg::OnFieldChanged)
70 EVT_CUSTOM( wxEVT_COMMAND_SPINCTRL_UPDATED, wxID_ANY, CSearchDlg::OnFieldChanged)
71 EVT_CUSTOM( wxEVT_COMMAND_CHOICE_SELECTED, wxID_ANY, CSearchDlg::OnFieldChanged)
73 // Event handlers for the filter fields getting changed.
74 EVT_TEXT_ENTER(ID_FILTER_TEXT, CSearchDlg::OnFilteringChange)
75 EVT_CHECKBOX(ID_FILTER_INVERT, CSearchDlg::OnFilteringChange)
76 EVT_CHECKBOX(ID_FILTER_KNOWN, CSearchDlg::OnFilteringChange)
77 EVT_BUTTON(ID_FILTER, CSearchDlg::OnFilteringChange)
78 END_EVENT_TABLE()
82 CSearchDlg::CSearchDlg(wxWindow* pParent)
83 : wxPanel(pParent, -1)
85 m_last_search_time = 0;
87 wxSizer* content = searchDlg(this, true);
88 content->Show(this, true);
90 m_progressbar = CastChild( ID_SEARCHPROGRESS, wxGauge );
91 m_progressbar->SetRange(100);
93 m_notebook = CastChild( ID_NOTEBOOK, CMuleNotebook );
95 #ifdef __WXMAC__
96 //#warning TODO: restore the image list if/when wxMac supports locating the image
97 #else
98 // Initialise the image list
99 wxImageList* m_ImageList = new wxImageList(16,16);
100 m_ImageList->Add(amuleSpecial(3));
101 m_ImageList->Add(amuleSpecial(4));
102 m_notebook->AssignImageList(m_ImageList);
103 #endif
105 // Sanity sanity
106 wxChoice* searchchoice = CastChild( ID_SEARCHTYPE, wxChoice );
107 wxASSERT(searchchoice);
108 wxASSERT(searchchoice->GetString(0) == _("Local"));
109 wxASSERT(searchchoice->GetString(2) == _("Kad"));
110 wxASSERT(searchchoice->GetCount() == 3);
112 m_searchchoices = searchchoice->GetStrings();
114 // Let's break it now.
116 FixSearchTypes();
118 CastChild( IDC_TypeSearch, wxChoice )->SetSelection(0);
119 CastChild( IDC_SEARCHMINSIZE, wxChoice )->SetSelection(2);
120 CastChild( IDC_SEARCHMAXSIZE, wxChoice )->SetSelection(2);
122 // Not there initially.
123 s_searchsizer->Show(s_extendedsizer, false);
124 s_searchsizer->Show(s_filtersizer, false);
126 Layout();
130 CSearchDlg::~CSearchDlg()
134 void CSearchDlg::FixSearchTypes()
136 wxChoice* searchchoice = CastChild( ID_SEARCHTYPE, wxChoice );
138 searchchoice->Clear();
140 // We should have only filedonkey now. Let's insert stuff.
142 int pos = 0;
144 if (thePrefs::GetNetworkED2K()){
145 searchchoice->Insert(m_searchchoices[0], pos++);
146 searchchoice->Insert(m_searchchoices[1], pos++);
149 if (thePrefs::GetNetworkKademlia()) {
150 searchchoice->Insert(m_searchchoices[2], pos++);
153 searchchoice->SetSelection(0);
156 CSearchListCtrl* CSearchDlg::GetSearchList( wxUIntPtr id )
158 int nPages = m_notebook->GetPageCount();
159 for ( int i = 0; i < nPages; i++ ) {
160 CSearchListCtrl* page = dynamic_cast<CSearchListCtrl*>(m_notebook->GetPage(i));
162 if (page->GetSearchId() == id) {
163 return page;
167 return NULL;
171 void CSearchDlg::AddResult(CSearchFile* toadd)
173 CSearchListCtrl* outputwnd = GetSearchList( toadd->GetSearchID() );
175 if ( outputwnd ) {
176 outputwnd->AddResult( toadd );
178 // Update the result count
179 UpdateHitCount( outputwnd );
184 void CSearchDlg::UpdateResult(CSearchFile* toupdate)
186 CSearchListCtrl* outputwnd = GetSearchList( toupdate->GetSearchID() );
188 if ( outputwnd ) {
189 outputwnd->UpdateResult( toupdate );
191 // Update the result count
192 UpdateHitCount( outputwnd );
197 void CSearchDlg::OnListItemSelected(wxListEvent& event)
199 FindWindow(IDC_SDOWNLOAD)->Enable(true);
201 event.Skip();
205 void CSearchDlg::OnExtendedSearchChange(wxCommandEvent& event)
207 s_searchsizer->Show(s_extendedsizer, event.IsChecked());
209 Layout();
213 void CSearchDlg::OnFilterCheckChange(wxCommandEvent& event)
215 s_searchsizer->Show(s_filtersizer, event.IsChecked());
216 Layout();
218 int nPages = m_notebook->GetPageCount();
219 for ( int i = 0; i < nPages; i++ ) {
220 CSearchListCtrl* page = dynamic_cast<CSearchListCtrl*>(m_notebook->GetPage(i));
222 page->EnableFiltering(event.IsChecked());
224 UpdateHitCount(page);
229 void CSearchDlg::OnSearchClosing(wxBookCtrlEvent& evt)
231 // Abort global search if it was last tab that was closed.
232 if ( evt.GetSelection() == ((int)m_notebook->GetPageCount() - 1 ) ) {
233 OnBnClickedStop(nullEvent);
236 CSearchListCtrl *ctrl = dynamic_cast<CSearchListCtrl*>(m_notebook->GetPage(evt.GetSelection()));
237 wxASSERT(ctrl);
238 // Zero to avoid results added while destructing.
239 ctrl->ShowResults(0);
240 theApp->searchlist->RemoveResults(ctrl->GetSearchId());
242 // Do cleanups if this was the last tab
243 if ( m_notebook->GetPageCount() == 1 ) {
244 FindWindow(IDC_SDOWNLOAD)->Enable(FALSE);
245 FindWindow(IDC_CLEAR_RESULTS)->Enable(FALSE);
250 void CSearchDlg::OnSearchPageChanged(wxBookCtrlEvent& WXUNUSED(evt))
252 int selection = m_notebook->GetSelection();
254 // Workaround for a bug in wxWidgets, where deletions of pages
255 // can result in an invalid selection. This has been reported as
256 // http://sourceforge.net/tracker/index.php?func=detail&aid=1865141&group_id=9863&atid=109863
257 if (selection >= (int)m_notebook->GetPageCount()) {
258 selection = m_notebook->GetPageCount() - 1;
261 // Only enable the Download button for pages where files have been selected
262 if ( selection != -1 ) {
263 CSearchListCtrl *ctrl = dynamic_cast<CSearchListCtrl*>(m_notebook->GetPage(selection));
265 bool enable = (ctrl->GetSelectedItemCount() > 0);
266 FindWindow(IDC_SDOWNLOAD)->Enable( enable );
271 void CSearchDlg::OnBnClickedStart(wxCommandEvent& WXUNUSED(evt))
273 if (!thePrefs::GetNetworkED2K() && !thePrefs::GetNetworkKademlia()) {
274 wxMessageBox(_("It's impossible to search when both eD2k and Kademlia are disabled."),
275 _("Search error"),
276 wxOK|wxCENTRE|wxICON_ERROR
278 return;
281 // We mustn't search more often than once every 2 secs
282 if ((GetTickCount() - m_last_search_time) > 2000) {
283 m_last_search_time = GetTickCount();
284 OnBnClickedStop(nullEvent);
285 StartNewSearch();
290 void CSearchDlg::OnFieldChanged( wxEvent& WXUNUSED(evt) )
292 bool enable = false;
294 // These are the IDs of the search-fields
295 int textfields[] = { IDC_SEARCHNAME, IDC_EDITSEARCHEXTENSION };
297 for ( uint16 i = 0; i < itemsof(textfields); i++ ) {
298 enable |= !CastChild( textfields[i], wxTextCtrl )->GetValue().IsEmpty();
301 // Check if either of the dropdowns have been changed
302 enable |= (CastChild(IDC_SEARCHMINSIZE, wxChoice)->GetSelection() != 2);
303 enable |= (CastChild(IDC_SEARCHMAXSIZE, wxChoice)->GetSelection() != 2);
304 enable |= (CastChild(IDC_TypeSearch, wxChoice)->GetSelection() > 0);
305 enable |= (CastChild(ID_AUTOCATASSIGN, wxChoice)->GetSelection() > 0);
307 // These are the IDs of the search-fields
308 int spinfields[] = { IDC_SPINSEARCHMIN, IDC_SPINSEARCHMAX, IDC_SPINSEARCHAVAIBILITY };
309 for ( uint16 i = 0; i < itemsof(spinfields); i++ ) {
310 enable |= (CastChild( spinfields[i], wxSpinCtrl )->GetValue() > 0);
313 // Enable the "Reset" button if any fields contain text
314 FindWindow(IDC_SEARCH_RESET)->Enable( enable );
316 // Enable the Server Search button if the Name field contains text
317 enable = !CastChild( IDC_SEARCHNAME, wxTextCtrl )->GetValue().IsEmpty();
318 FindWindow(IDC_STARTS)->Enable( enable );
322 void CSearchDlg::OnFilteringChange(wxCommandEvent& WXUNUSED(evt))
324 wxString filter = CastChild(ID_FILTER_TEXT, wxTextCtrl)->GetValue();
325 bool invert = CastChild(ID_FILTER_INVERT, wxCheckBox)->GetValue();
326 bool known = CastChild(ID_FILTER_KNOWN, wxCheckBox)->GetValue();
328 // Check that the expression compiles before we try to assign it
329 // Otherwise we will get an error-dialog for each result-list.
330 if (wxRegEx(filter, wxRE_DEFAULT | wxRE_ICASE).IsValid()) {
331 int nPages = m_notebook->GetPageCount();
332 for ( int i = 0; i < nPages; i++ ) {
333 CSearchListCtrl* page = dynamic_cast<CSearchListCtrl*>(m_notebook->GetPage(i));
335 page->SetFilter(filter, invert, known);
337 UpdateHitCount(page);
343 bool CSearchDlg::CheckTabNameExists(const wxString& searchString)
345 int nPages = m_notebook->GetPageCount();
346 for ( int i = 0; i < nPages; i++ ) {
347 // The BeforeLast(' ') is to strip the hit-count from the name
348 if ( m_notebook->GetPageText(i).BeforeLast(wxT(' ')) == searchString ) {
349 return true;
353 return false;
357 void CSearchDlg::CreateNewTab(const wxString& searchString, wxUIntPtr nSearchID)
359 CSearchListCtrl* list = new CSearchListCtrl(m_notebook, ID_SEARCHLISTCTRL, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxNO_BORDER);
360 m_notebook->AddPage(list, searchString, true, 0);
362 // Ensure that new results are filtered
363 bool enable = CastChild(IDC_FILTERCHECK, wxCheckBox)->GetValue();
364 wxString filter = CastChild(ID_FILTER_TEXT, wxTextCtrl)->GetValue();
365 bool invert = CastChild(ID_FILTER_INVERT, wxCheckBox)->GetValue();
366 bool known = CastChild(ID_FILTER_KNOWN, wxCheckBox)->GetValue();
368 list->SetFilter(filter, invert, known);
369 list->EnableFiltering(enable);
370 list->ShowResults(nSearchID);
372 Layout();
373 FindWindow(IDC_CLEAR_RESULTS)->Enable(true);
377 void CSearchDlg::OnBnClickedStop(wxCommandEvent& WXUNUSED(evt))
379 theApp->searchlist->StopSearch();
380 ResetControls();
384 void CSearchDlg::ResetControls()
386 m_progressbar->SetValue(0);
388 FindWindow(IDC_CANCELS)->Disable();
389 FindWindow(IDC_STARTS)->Enable(!CastChild( IDC_SEARCHNAME, wxTextCtrl )->GetValue().IsEmpty());
393 void CSearchDlg::LocalSearchEnd()
395 ResetControls();
398 void CSearchDlg::KadSearchEnd(uint32 id)
400 int nPages = m_notebook->GetPageCount();
401 for (int i = 0; i < nPages; ++i) {
402 CSearchListCtrl* page =
403 dynamic_cast<CSearchListCtrl*>(m_notebook->GetPage(i));
404 if (page->GetSearchId() == id || id == 0) { // 0: just update all pages (there is only one KAD search running at a time anyway)
405 wxString rest;
406 if (m_notebook->GetPageText(i).StartsWith(wxT("!"),&rest)) {
407 m_notebook->SetPageText(i,rest);
413 void CSearchDlg::OnBnClickedDownload(wxCommandEvent& WXUNUSED(evt))
415 int sel = m_notebook->GetSelection();
416 if (sel != -1) {
417 CSearchListCtrl* list = dynamic_cast<CSearchListCtrl*>(m_notebook->GetPage(sel));
419 // Download with items added to category specified in the drop-down menu
420 list->DownloadSelected();
425 void CSearchDlg::OnBnClickedClear(wxCommandEvent& WXUNUSED(ev))
427 OnBnClickedStop(nullEvent);
429 m_notebook->DeleteAllPages();
431 FindWindow(IDC_CLEAR_RESULTS)->Enable(FALSE);
432 FindWindow(IDC_SDOWNLOAD)->Enable(FALSE);
436 void CSearchDlg::StartNewSearch()
438 static uint32 m_nSearchID = 0;
439 m_nSearchID++;
441 FindWindow(IDC_STARTS)->Disable();
442 FindWindow(IDC_SDOWNLOAD)->Disable();
443 FindWindow(IDC_CANCELS)->Enable();
445 CSearchList::CSearchParams params;
447 params.searchString = CastChild( IDC_SEARCHNAME, wxTextCtrl )->GetValue();
448 params.searchString.Trim(true);
449 params.searchString.Trim(false);
451 if (params.searchString.IsEmpty()) {
452 return;
455 if (CastChild(IDC_EXTENDEDSEARCHCHECK, wxCheckBox)->GetValue()) {
456 params.extension = CastChild( IDC_EDITSEARCHEXTENSION, wxTextCtrl )->GetValue();
458 uint32 sizemin = GetTypeSize( (uint8) CastChild( IDC_SEARCHMINSIZE, wxChoice )->GetSelection() );
459 uint32 sizemax = GetTypeSize( (uint8) CastChild( IDC_SEARCHMAXSIZE, wxChoice )->GetSelection() );
461 // Parameter Minimum Size
462 params.minSize = (uint64_t)(CastChild( IDC_SPINSEARCHMIN, wxSpinCtrl )->GetValue()) * (uint64_t)sizemin;
464 // Parameter Maximum Size
465 params.maxSize = (uint64_t)(CastChild( IDC_SPINSEARCHMAX, wxSpinCtrl )->GetValue()) * (uint64_t)sizemax;
467 if ((params.maxSize < params.minSize) && (params.maxSize)) {
468 wxMessageDialog dlg(this,
469 _("Min size must be smaller than max size. Max size ignored."),
470 _("Search warning"), wxOK|wxCENTRE|wxICON_INFORMATION);
471 dlg.ShowModal();
473 params.maxSize = 0;
476 // Parameter Availability
477 params.availability = CastChild( IDC_SPINSEARCHAVAIBILITY, wxSpinCtrl )->GetValue();
479 switch ( CastChild( IDC_TypeSearch, wxChoice )->GetSelection() ) {
480 case 0: params.typeText.Clear(); break;
481 case 1: params.typeText = ED2KFTSTR_ARCHIVE; break;
482 case 2: params.typeText = ED2KFTSTR_AUDIO; break;
483 case 3: params.typeText = ED2KFTSTR_CDIMAGE; break;
484 case 4: params.typeText = ED2KFTSTR_IMAGE; break;
485 case 5: params.typeText = ED2KFTSTR_PROGRAM; break;
486 case 6: params.typeText = ED2KFTSTR_DOCUMENT; break;
487 case 7: params.typeText = ED2KFTSTR_VIDEO; break;
488 default:
489 AddDebugLogLineC( logGeneral,
490 CFormat( wxT("Warning! Unknown search-category (%s) selected!") )
491 % params.typeText
493 break;
497 SearchType search_type = KadSearch;
499 int selection = CastChild( ID_SEARCHTYPE, wxChoice )->GetSelection();
501 if (!thePrefs::GetNetworkED2K()) {
502 selection += 2;
505 if (!thePrefs::GetNetworkKademlia()) {
506 selection += 1;
509 switch (selection) {
510 case 0: // Local Search
511 search_type = LocalSearch;
512 break;
513 case 1: // Global Search
514 search_type = GlobalSearch;
515 break;
516 case 2: // Kad search
517 search_type = KadSearch;
518 break;
519 default:
520 // Should never happen
521 wxFAIL;
522 break;
525 uint32 real_id = m_nSearchID;
526 wxString error = theApp->searchlist->StartNewSearch(&real_id, search_type, params);
527 if (!error.IsEmpty()) {
528 // Search failed / Remote in progress
529 wxMessageBox(error, _("Search warning"),
530 wxOK | wxCENTRE | wxICON_INFORMATION, this);
531 FindWindow(IDC_STARTS)->Enable();
532 FindWindow(IDC_SDOWNLOAD)->Disable();
533 FindWindow(IDC_CANCELS)->Disable();
534 } else {
535 CreateNewTab(
536 ((search_type == KadSearch) ? wxT("!") : wxEmptyString) +
537 params.searchString + wxT(" (0)"),
538 real_id);
543 void CSearchDlg::UpdateHitCount(CSearchListCtrl* page)
545 for ( uint32 i = 0; i < (uint32)m_notebook->GetPageCount(); ++i ) {
546 if ( m_notebook->GetPage(i) == page ) {
547 wxString searchtxt = m_notebook->GetPageText(i).BeforeLast(wxT(' '));
549 if ( !searchtxt.IsEmpty() ) {
550 size_t shown = page->GetItemCount();
551 size_t hidden = page->GetHiddenItemCount();
553 if (hidden) {
554 searchtxt += CFormat(wxT(" (%u/%u)")) % shown % (shown + hidden);
555 } else {
556 searchtxt += CFormat(wxT(" (%u)")) % shown;
559 m_notebook->SetPageText(i, searchtxt);
562 break;
568 void CSearchDlg::OnBnClickedReset(wxCommandEvent& WXUNUSED(evt))
570 CastChild( IDC_SEARCHNAME, wxTextCtrl )->Clear();
571 CastChild( IDC_EDITSEARCHEXTENSION, wxTextCtrl )->Clear();
572 CastChild( IDC_SPINSEARCHMIN, wxSpinCtrl )->SetValue(0);
573 CastChild( IDC_SEARCHMINSIZE, wxChoice )->SetSelection(2);
574 CastChild( IDC_SPINSEARCHMAX, wxSpinCtrl )->SetValue(0);
575 CastChild( IDC_SEARCHMAXSIZE, wxChoice )->SetSelection(2);
576 CastChild( IDC_SPINSEARCHAVAIBILITY, wxSpinCtrl )->SetValue(0);
577 CastChild( IDC_TypeSearch, wxChoice )->SetSelection(0);
578 CastChild( ID_AUTOCATASSIGN, wxChoice )->SetSelection(0);
580 FindWindow(IDC_SEARCH_RESET)->Enable(FALSE);
584 void CSearchDlg::UpdateCatChoice()
586 wxChoice* c_cat = CastChild( ID_AUTOCATASSIGN, wxChoice );
587 c_cat->Clear();
589 c_cat->Append(_("Main"));
591 for ( unsigned i = 1; i < theApp->glob_prefs->GetCatCount(); i++ ) {
592 c_cat->Append( theApp->glob_prefs->GetCategory( i )->title );
595 c_cat->SetSelection( 0 );
598 void CSearchDlg::UpdateProgress(uint32 new_value) {
599 m_progressbar->SetValue(new_value);
601 // File_checked_for_headers