1 /***************************************************************************
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 3 of the License, or *
6 * (at your option) any later version. *
7 * *
8 ***************************************************************************/
9
10 #include <QComboBox>
11 #include <QTreeView>
12 #include <QAction>
13 #include <QTextCodec>
14 #include <QDir>
15 #include <QItemSelectionModel>
16 #include <QFileDialog>
17 #include <QClipboard>
18 #include <QHeaderView>
19 #include <QKeyEvent>
20 #include <QMessageBox>
21 #include <QStringListModel>
22 #include <QKeyEvent>
23 #include <QTimer>
24 #include <QShortcut>
25 #include <QStringListModel>
26 #include <QCompleter>
27 #include <QListWidget>
28 #include <QListWidgetItem>
29
30 #include "SearchFrame.h"
31 #include "MainWindow.h"
32 #include "HubFrame.h"
33 #include "HubManager.h"
34 #include "SearchModel.h"
35 #include "SearchBlacklist.h"
36 #include "SearchBlacklistDialog.h"
37 #include "WulforUtil.h"
38 #include "Magnet.h"
39 #include "ArenaWidgetManager.h"
40 #include "ArenaWidgetFactory.h"
41 #include "DownloadToHistory.h"
42 #include "GlobalTimer.h"
43
44 #include "dcpp/CID.h"
45 #include "dcpp/ClientManager.h"
46 #include "dcpp/FavoriteManager.h"
47 #include "dcpp/StringTokenizer.h"
48 #include "dcpp/SettingsManager.h"
49 #include "dcpp/Encoder.h"
50 #include "dcpp/UserCommand.h"
51
52 #include <QtDebug>
53
54 using namespace dcpp;
55
56 class SearchFramePrivate{
57 public:
58 QString arena_title;
59 QString token;
60
61 TStringList currentSearch;
62
63 qulonglong dropped;
64 qulonglong results;
65 SearchFrame::AlreadySharedAction filterShared;
66 bool withFreeSlots;
67
68 QStringList hubs;
69 QStringList searchHistory;
70
71 QList<dcpp::Client*> client_list;
72
73 QTimer *timer;
74
75 QCompleter *completer;
76
77 QMenu *arena_menu;
78
79 QShortcut *focusShortcut;
80
81 bool saveFileType;
82
83 SearchModel *model;
84 SearchStringListModel *str_model;
85 SearchProxyModel *proxy;
86
87 bool isHash;
88 bool stop;
89 int left_pane_old_size;
90
91 QString target;
92 uint64_t searchStartTime;
93 uint64_t searchEndTime;
94 bool waitingResults;
95 };
96
data(const QModelIndex & index,int role) const97 QVariant SearchStringListModel::data(const QModelIndex &index, int role) const{
98 if (role != Qt::CheckStateRole || !index.isValid())
99 return QStringListModel::data(index, role);
100
101 return (checked.contains(index.data().toString())? Qt::Checked : Qt::Unchecked);
102 }
103
setData(const QModelIndex & index,const QVariant & value,int role)104 bool SearchStringListModel::setData(const QModelIndex &index, const QVariant &value, int role){
105 if (role != Qt::CheckStateRole || !index.isValid())
106 return QStringListModel::setData(index, value, role);
107
108 if (value.toInt() == Qt::Checked)
109 checked.push_back(index.data().toString());
110 else if (checked.contains(index.data().toString()))
111 checked.removeAt(checked.indexOf(index.data().toString()));
112
113 return true;
114 }
115
Menu()116 SearchFrame::Menu::Menu(){
117 WulforUtil *WU = WulforUtil::getInstance();
118
119 menu = new QMenu();
120
121 magnet_menu = new QMenu(tr("Magnet"));
122
123 QAction *down = new QAction(tr("Download"), NULL);
124 down->setIcon(WU->getPixmap(WulforUtil::eiDOWNLOAD));
125
126 down_to = new QMenu(tr("Download to..."));
127 down_to->setIcon(WU->getPixmap(WulforUtil::eiDOWNLOAD_AS));
128
129 QAction *down_wh = new QAction(tr("Download Whole Directory"), NULL);
130 down_wh->setIcon(WU->getPixmap(WulforUtil::eiDOWNLOAD));
131
132 down_wh_to = new QMenu(tr("Download Whole Directory to..."));
133 down_wh_to->setIcon(WU->getPixmap(WulforUtil::eiDOWNLOAD_AS));
134
135 QAction *sep = new QAction(menu);
136 sep->setSeparator(true);
137
138 QAction *find_tth = new QAction(tr("Search TTH"), NULL);
139 find_tth->setIcon(WU->getPixmap(WulforUtil::eiFILEFIND));
140
141 QAction *magnet = new QAction(tr("Copy magnet"), NULL);
142 magnet->setIcon(WU->getPixmap(WulforUtil::eiEDITCOPY));
143
144 QAction *magnet_web = new QAction(tr("Copy web-magnet"), NULL);
145 magnet_web->setIcon(WU->getPixmap(WulforUtil::eiEDITCOPY));
146
147 QAction *magnet_info = new QAction(tr("Properties of magnet"), NULL);
148 magnet_info->setIcon(WU->getPixmap(WulforUtil::eiDOWNLOAD));
149
150 QAction *browse = new QAction(tr("Browse files"), NULL);
151 browse->setIcon(WU->getPixmap(WulforUtil::eiFOLDER_BLUE));
152
153 QAction *match = new QAction(tr("Match Queue"), NULL);
154 match->setIcon(WU->getPixmap(WulforUtil::eiDOWN));
155
156 QAction *send_pm = new QAction(tr("Send Private Message"), NULL);
157 send_pm->setIcon(WU->getPixmap(WulforUtil::eiMESSAGE));
158
159 QAction *add_to_fav = new QAction(tr("Add to favorites"), NULL);
160 add_to_fav->setIcon(WU->getPixmap(WulforUtil::eiBOOKMARK_ADD));
161
162 QAction *grant = new QAction(tr("Grant extra slot"), NULL);
163 grant->setIcon(WU->getPixmap(WulforUtil::eiEDITADD));
164
165 QAction *sep1 = new QAction(menu);
166 sep1->setSeparator(true);
167
168 QAction *sep2 = new QAction(menu);
169 sep2->setSeparator(true);
170
171 QAction *sep3 = new QAction(menu);
172 sep3->setSeparator(true);
173
174 QAction *rem_queue = new QAction(tr("Remove from Queue"), NULL);
175 rem_queue->setIcon(WU->getPixmap(WulforUtil::eiEDITDELETE));
176
177 QAction *rem = new QAction(tr("Remove"), NULL);
178 rem->setIcon(WU->getPixmap(WulforUtil::eiEDITDELETE));
179
180 black_list_menu = new QMenu(tr("Blacklist..."));
181 black_list_menu->setIcon(WU->getPixmap(WulforUtil::eiFILTER));
182
183 QAction *blacklist = new QAction(tr("Blacklist"), NULL);
184 blacklist->setIcon(WU->getPixmap(WulforUtil::eiFILTER));
185
186 QAction *add_to_blacklist = new QAction(tr("Add to Blacklist"), NULL);
187 add_to_blacklist->setIcon(WU->getPixmap(WulforUtil::eiEDITADD));
188
189 black_list_menu->addActions(QList<QAction*>()
190 << add_to_blacklist << blacklist);
191
192 magnet_menu->addActions(QList<QAction*>()
193 << magnet << magnet_web << sep3 << magnet_info);
194
195 actions.insert(down, Download);
196 actions.insert(down_wh, DownloadWholeDir);
197 actions.insert(find_tth, SearchTTH);
198 actions.insert(magnet, Magnet);
199 actions.insert(magnet_web, MagnetWeb);
200 actions.insert(magnet_info, MagnetInfo);
201 actions.insert(browse, Browse);
202 actions.insert(match, MatchQueue);
203 actions.insert(send_pm, SendPM);
204 actions.insert(add_to_fav, AddToFav);
205 actions.insert(grant, GrantExtraSlot);
206 actions.insert(rem_queue, RemoveFromQueue);
207 actions.insert(rem, Remove);
208 actions.insert(blacklist, Blacklist);
209 actions.insert(add_to_blacklist, AddToBlacklist);
210
211 action_list << down
212 << down_wh
213 << sep
214 << find_tth
215 << browse
216 << match
217 << send_pm
218 << add_to_fav
219 << grant
220 << sep1
221 << rem_queue
222 << rem
223 << sep2;
224 }
225
~Menu()226 SearchFrame::Menu::~Menu(){
227 qDeleteAll(action_list);
228
229 magnet_menu->deleteLater();
230 menu->deleteLater();
231 down_to->deleteLater();
232 down_wh_to->deleteLater();
233 black_list_menu->deleteLater();
234 }
235
exec(QStringList list=QStringList ())236 SearchFrame::Menu::Action SearchFrame::Menu::exec(QStringList list = QStringList()){
237 for (const auto &a : action_list)
238 a->setParent(NULL);
239
240 qDeleteAll(down_to->actions());
241 qDeleteAll(down_wh_to->actions());
242 down_to->clear();
243 down_wh_to->clear();
244
245 QString aliases, paths;
246
247 aliases = QByteArray::fromBase64(WSGET(WS_DOWNLOADTO_ALIASES).toUtf8());
248 paths = QByteArray::fromBase64(WSGET(WS_DOWNLOADTO_PATHS).toUtf8());
249
250 QStringList a = aliases.split("\n", QString::SkipEmptyParts);
251 QStringList p = paths.split("\n", QString::SkipEmptyParts);
252
253 QStringList temp_pathes = DownloadToDirHistory::get();
254
255 if (!temp_pathes.isEmpty()){
256 for (const auto &t : temp_pathes){
257 QAction *act = new QAction(WICON(WulforUtil::eiFOLDER_BLUE), QDir(t).dirName(), down_to);
258 act->setToolTip(t);
259 act->setData(t);
260
261 down_to->addAction(act);
262
263 QAction *act1 = new QAction(WICON(WulforUtil::eiFOLDER_BLUE), QDir(t).dirName(), down_to);
264 act1->setToolTip(t);
265 act1->setData(t);
266
267 down_wh_to->addAction(act1);
268 }
269
270 down_to->addSeparator();
271 down_wh_to->addSeparator();
272 }
273
274 if (a.size() == p.size() && !a.isEmpty()){
275 for (int i = 0; i < a.size(); i++){
276 QAction *act = new QAction(WICON(WulforUtil::eiFOLDER_BLUE), a.at(i), down_to);
277 act->setData(p.at(i));
278
279 down_to->addAction(act);
280
281 QAction *act1 = new QAction(WICON(WulforUtil::eiFOLDER_BLUE), a.at(i), down_to);
282 act1->setData(p.at(i));
283
284 down_wh_to->addAction(act1);
285 }
286
287 down_to->addSeparator();
288 down_wh_to->addSeparator();
289 }
290
291 QAction *browse = new QAction(WICON(WulforUtil::eiFOLDER_BLUE), tr("Browse"), down_to);
292 browse->setData("");
293
294 QAction *browse1 = new QAction(WICON(WulforUtil::eiFOLDER_BLUE), tr("Browse"), down_to);
295 browse->setData("");
296
297 down_to->addAction(browse);
298 down_wh_to->addAction(browse1);
299
300 menu->clear();
301 menu->addActions(action_list);
302 menu->insertMenu(action_list.at(1), down_to);
303 menu->insertMenu(action_list.at(2), down_wh_to);
304 menu->insertMenu(action_list.at(5), magnet_menu);
305 menu->insertMenu(action_list.at(12),black_list_menu);
306
307 QScopedPointer<QMenu> userm(buildUserCmdMenu(list));
308
309 if (!userm.isNull() && !userm->actions().isEmpty())
310 menu->addMenu(userm.data());
311
312 QAction *ret = menu->exec(QCursor::pos());
313
314 if (actions.contains(ret)) {
315 return actions.value(ret);
316 } else if (down_to->actions().contains(ret)) {
317 downToPath = ret->data().toString();
318 return DownloadTo;
319 } else if (down_wh_to->actions().contains(ret)) {
320 downToPath = ret->data().toString();
321 return DownloadWholeDirTo;
322 } else if (ret && ret->data().canConvert(QVariant::Int)) {
323 uc_cmd_id = ret->data().toInt();
324 return UserCommands;
325 } else {
326 return None;
327 }
328 }
329
buildUserCmdMenu(QList<QString> hub_list)330 QMenu *SearchFrame::Menu::buildUserCmdMenu(QList<QString> hub_list){
331 if (hub_list.empty())
332 return NULL;
333
334 return WulforUtil::getInstance()->buildUserCmdMenu(hub_list, UserCommand::CONTEXT_SEARCH);
335 }
336
addTempPath(const QString & path)337 void SearchFrame::Menu::addTempPath(const QString &path){
338 QStringList temp_pathes = DownloadToDirHistory::get();
339 temp_pathes.push_front(path);
340
341 DownloadToDirHistory::put(temp_pathes);
342 }
343
SearchFrame(QWidget * parent)344 SearchFrame::SearchFrame(QWidget *parent): QWidget(parent), d_ptr(new SearchFramePrivate())
345 {
346 if (!SearchBlacklist::getInstance())
347 SearchBlacklist::newInstance();
348
349 Q_D(SearchFrame);
350
351 d->isHash = false;
352 d->arena_menu = NULL;
353 d->timer = NULL;
354 d->dropped = 0L;
355 d->results = 0L;
356 d->filterShared = SearchFrame::None;
357 d->withFreeSlots = false;
358 d->saveFileType = true;
359 d->proxy = NULL;
360 d->completer = NULL;
361 d->stop = false;
362 d->arena_title = tr("Search");
363 d->searchStartTime = 0;
364 d->searchEndTime = 1;
365 d->waitingResults = false;
366
367 setupUi(this);
368
369 init();
370
371 ClientManager* clientMgr = ClientManager::getInstance();
372
373 #ifdef DO_NOT_USE_MUTEX
374 clientMgr->lock();
375 #else // DO_NOT_USE_MUTEX
376 auto lock = clientMgr->lock();
377 #endif // DO_NOT_USE_MUTEX
378 clientMgr->addListener(this);
379 Client::List& clients = clientMgr->getClients();
380
381 for (const auto &client : clients) {
382 if(!client->isConnected())
383 continue;
384
385 d->hubs.push_back(_q(client->getHubUrl()));
386 d->client_list.push_back(client);
387 }
388
389 #ifdef DO_NOT_USE_MUTEX
390 clientMgr->unlock();
391 #endif // DO_NOT_USE_MUTEX
392
393 d->str_model->setStringList(d->hubs);
394
395
396 for (int i = 0; i < d->str_model->rowCount(); i++)
397 d-> str_model->setData(d->str_model->index(i, 0), Qt::Checked, Qt::CheckStateRole);
398
399 SearchManager::getInstance()->addListener(this);
400 }
401
~SearchFrame()402 SearchFrame::~SearchFrame(){
403 Menu::deleteInstance();
404
405 Q_D(SearchFrame);
406
407 treeView_RESULTS->setModel(NULL);
408
409 if (d->completer)
410 d->completer->deleteLater();
411
412 if (d->proxy)
413 d->proxy->deleteLater();
414
415 d->arena_menu->deleteLater();
416
417 delete d->model;
418 delete d->timer;
419
420 delete d_ptr;
421 }
422
closeEvent(QCloseEvent * e)423 void SearchFrame::closeEvent(QCloseEvent *e){
424 SearchManager::getInstance()->removeListener(this);
425 ClientManager::getInstance()->removeListener(this);
426
427 Q_D(SearchFrame);
428
429 if (d->timer)
430 d->timer->stop();
431
432 save();
433
434 setAttribute(Qt::WA_DeleteOnClose);
435
436 QWidget::disconnect(this, NULL, this, NULL);
437
438 e->accept();
439 }
440
eventFilter(QObject * obj,QEvent * e)441 bool SearchFrame::eventFilter(QObject *obj, QEvent *e){
442 if (e->type() == QEvent::KeyRelease){
443 QKeyEvent *k_e = reinterpret_cast<QKeyEvent*>(e);
444
445 if (static_cast<LineEdit*>(obj) == lineEdit_FILTER && k_e->key() == Qt::Key_Escape){
446 lineEdit_FILTER->clear();
447
448 requestFilter();
449
450 return true;
451 }
452 }
453
454 return QWidget::eventFilter(obj, e);
455 }
456
init()457 void SearchFrame::init(){
458 Q_D(SearchFrame);
459
460 d->model = new SearchModel(NULL);
461 d->str_model = new SearchStringListModel(this);
462
463 for (int i = 0; i < d->model->columnCount(); i++)
464 comboBox_FILTERCOLUMNS->addItem(d->model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
465
466 comboBox_FILTERCOLUMNS->setCurrentIndex(COLUMN_SF_FILENAME);
467
468 frame_FILTER->setVisible(false);
469
470 pushButton_STOP->hide();
471
472 toolButton_CLOSEFILTER->setIcon(WICON(WulforUtil::eiEDITDELETE));
473
474 treeView_RESULTS->setModel(d->model);
475 treeView_RESULTS->setContextMenuPolicy(Qt::CustomContextMenu);
476 treeView_RESULTS->header()->setContextMenuPolicy(Qt::CustomContextMenu);
477
478 treeView_HUBS->setModel(d->str_model);
479
480 d->arena_menu = new QMenu(this->windowTitle());
481 QAction *close_wnd = new QAction(WICON(WulforUtil::eiFILECLOSE), tr("Close"), d->arena_menu);
482 d->arena_menu->addAction(close_wnd);
483 const SettingsManager::SearchTypes &searchTypes = SettingsManager::getInstance()->getSearchTypes();
484 QStringList filetypes;
485 // Predefined
486 for (int i = SearchManager::TYPE_ANY; i < SearchManager::TYPE_LAST; i++)
487 {
488 filetypes << _q(SearchManager::getTypeStr(i));
489 }
490
491 // Customs
492 for (const auto &i : searchTypes)
493 {
494 string type = i.first;
495 if (!(type.size() == 1 && type[0] >= '1' && type[0] <= '7'))
496 {
497 filetypes << _q(type);
498 }
499 }
500 comboBox_FILETYPES->addItems(filetypes);
501 comboBox_FILETYPES->setCurrentIndex(0);
502
503 QList<WulforUtil::Icons> icons;
504 icons << WulforUtil::eiFILETYPE_UNKNOWN << WulforUtil::eiFILETYPE_MP3 << WulforUtil::eiFILETYPE_ARCHIVE
505 << WulforUtil::eiFILETYPE_DOCUMENT << WulforUtil::eiFILETYPE_APPLICATION << WulforUtil::eiFILETYPE_PICTURE
506 << WulforUtil::eiFILETYPE_VIDEO << WulforUtil::eiFOLDER_BLUE << WulforUtil::eiFIND
507 << WulforUtil::eiFILETYPE_ARCHIVE;
508
509 for (int i = 0; i < icons.size(); i++)
510 comboBox_FILETYPES->setItemIcon(i, WICON(icons.at(i)));
511
512 QString raw = QByteArray::fromBase64(WSGET(WS_SEARCH_HISTORY).toUtf8());
513 d->searchHistory = raw.replace("\r","").split('\n', QString::SkipEmptyParts);
514
515 QMenu *m = new QMenu();
516
517 for (const auto &s : d->searchHistory)
518 m->addAction(s);
519
520 d->focusShortcut = new QShortcut(QKeySequence(Qt::Key_F6), this);
521 d->focusShortcut->setContext(Qt::WidgetWithChildrenShortcut);
522
523 lineEdit_SEARCHSTR->setMenu(m);
524 lineEdit_SEARCHSTR->setPixmap(WICON(WulforUtil::eiEDITADD).scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
525
526 lineEdit_FILTER->installEventFilter(this);
527
528 connect(this, SIGNAL(coreClientConnected(QString)), this, SLOT(onHubAdded(QString)), Qt::QueuedConnection);
529 connect(this, SIGNAL(coreClientDisconnected(QString)), this, SLOT(onHubRemoved(QString)),Qt::QueuedConnection);
530 connect(this, SIGNAL(coreClientUpdated(QString)), this, SLOT(onHubChanged(QString)), Qt::QueuedConnection);
531 connect(this, SIGNAL(coreSR(VarMap)), this, SLOT(addResult(VarMap)), Qt::QueuedConnection);
532
533 connect(d->focusShortcut, SIGNAL(activated()), lineEdit_SEARCHSTR, SLOT(setFocus()));
534 connect(d->focusShortcut, SIGNAL(activated()), lineEdit_SEARCHSTR, SLOT(selectAll()));
535 connect(close_wnd, SIGNAL(triggered()), this, SLOT(slotClose()));
536 connect(pushButton_SEARCH, SIGNAL(clicked()), this, SLOT(slotStartSearch()));
537 connect(pushButton_STOP, SIGNAL(clicked()), this, SLOT(slotStopSearch()));
538 connect(pushButton_CLEAR, SIGNAL(clicked()), this, SLOT(slotClear()));
539 connect(treeView_RESULTS, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotResultDoubleClicked(QModelIndex)));
540 connect(treeView_RESULTS, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenu(QPoint)));
541 connect(treeView_RESULTS->header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderMenu(QPoint)));
542 connect(GlobalTimer::getInstance(), SIGNAL(second()), this, SLOT(slotTimer()));
543 connect(pushButton_SIDEPANEL, SIGNAL(clicked()), this, SLOT(slotToggleSidePanel()));
544 connect(lineEdit_SEARCHSTR, SIGNAL(returnPressed()), this, SLOT(slotStartSearch()));
545 connect(lineEdit_SIZE, SIGNAL(returnPressed()), this, SLOT(slotStartSearch()));
546 connect(comboBox_FILETYPES, SIGNAL(currentIndexChanged(int)), lineEdit_SEARCHSTR, SLOT(setFocus()));
547 connect(comboBox_FILETYPES, SIGNAL(currentIndexChanged(int)), lineEdit_SEARCHSTR, SLOT(selectAll()));
548 connect(toolButton_CLOSEFILTER, SIGNAL(clicked()), this, SLOT(slotFilter()));
549 connect(comboBox_FILTERCOLUMNS, SIGNAL(currentIndexChanged(int)), lineEdit_FILTER, SLOT(selectAll()));
550 connect(comboBox_FILTERCOLUMNS, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeProxyColumn(int)));
551
552 connect(WulforSettings::getInstance(), SIGNAL(strValueChanged(QString,QString)), this, SLOT(slotSettingsChanged(QString,QString)));
553
554 load();
555
556 setAttribute(Qt::WA_DeleteOnClose);
557
558 QList<int> panes = splitter->sizes();
559 d->left_pane_old_size = panes[0];
560
561 lineEdit_SEARCHSTR->setFocus();
562 }
563
load()564 void SearchFrame::load(){
565 Q_D(SearchFrame);
566
567 treeView_RESULTS->header()->restoreState(QByteArray::fromBase64(WSGET(WS_SEARCH_STATE).toUtf8()));
568 treeView_RESULTS->setSortingEnabled(true);
569
570 d->filterShared = static_cast<SearchFrame::AlreadySharedAction>(WIGET(WI_SEARCH_SHARED_ACTION));
571
572 comboBox_SHARED->setCurrentIndex(static_cast<int>(d->filterShared));
573
574 checkBox_FILTERSLOTS->setChecked(WBGET(WB_SEARCHFILTER_NOFREE));
575 checkBox_HIDEPANEL->setChecked(WBGET(WB_SEARCH_DONTHIDEPANEL));
576
577 comboBox_FILETYPES->setCurrentIndex(WIGET(WI_SEARCH_LAST_TYPE));
578
579 treeView_RESULTS->sortByColumn(WIGET(WI_SEARCH_SORT_COLUMN), WulforUtil::getInstance()->intToSortOrder(WIGET(WI_SEARCH_SORT_ORDER)));
580
581 QString raw = QByteArray::fromBase64(WSGET(WS_SEARCH_HISTORY).toUtf8());
582 QStringList list = raw.replace("\r","").split('\n', QString::SkipEmptyParts);
583
584 d->completer = new QCompleter(list, lineEdit_SEARCHSTR);
585 d->completer->setCaseSensitivity(Qt::CaseInsensitive);
586 d->completer->setWrapAround(false);
587
588 lineEdit_SEARCHSTR->setCompleter(d->completer);
589 }
590
save()591 void SearchFrame::save(){
592 Q_D(SearchFrame);
593
594 WSSET(WS_SEARCH_STATE, treeView_RESULTS->header()->saveState().toBase64());
595 WISET(WI_SEARCH_SORT_COLUMN, d->model->getSortColumn());
596 WISET(WI_SEARCH_SORT_ORDER, WulforUtil::getInstance()->sortOrderToInt(d->model->getSortOrder()));
597 WISET(WI_SEARCH_SHARED_ACTION, static_cast<int>(d->filterShared));
598
599 if (d->saveFileType)
600 WISET(WI_SEARCH_LAST_TYPE, comboBox_FILETYPES->currentIndex());
601
602 WBSET(WB_SEARCHFILTER_NOFREE, checkBox_FILTERSLOTS->isChecked());
603 WBSET(WB_SEARCH_DONTHIDEPANEL, checkBox_HIDEPANEL->isChecked());
604 }
605
initSecond()606 void SearchFrame::initSecond(){
607 /*Q_D(SearchFrame);
608
609 if (!d->timer){
610 d->timer = new QTimer(this);
611 d->timer->setInterval(1000);
612 d->timer->setSingleShot(true);
613
614 connect(d->timer, SIGNAL(timeout()), this, SLOT(timerTick()));
615 }
616
617 d->timer->start();*/
618 }
619
getWidget()620 QWidget *SearchFrame::getWidget(){
621 return this;
622 }
623
getArenaTitle()624 QString SearchFrame::getArenaTitle(){
625 Q_D(SearchFrame);
626
627 return d->arena_title;
628 }
629
getArenaShortTitle()630 QString SearchFrame::getArenaShortTitle(){
631 return getArenaTitle();
632 }
633
getMenu()634 QMenu *SearchFrame::getMenu(){
635 Q_D(SearchFrame);
636
637 return d->arena_menu;
638 }
639
getPixmap()640 const QPixmap &SearchFrame::getPixmap(){
641 return WICON(WulforUtil::eiFILEFIND);
642 }
643
download(const SearchFrame::VarMap & params)644 void SearchFrame::download(const SearchFrame::VarMap ¶ms){
645 string target, cid, filename, hubUrl;
646 int64_t size;
647
648 target = params["TARGET"].toString().toStdString();
649 cid = params["CID"].toString().toStdString();
650 filename = params["FNAME"].toString().toStdString();
651 hubUrl = params["HOST"].toString().toStdString();
652 size = (int64_t)params["ESIZE"].toLongLong();
653
654 try{
655 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
656
657 if (!user)
658 return;
659 // Only files have a TTH
660 if (!params["TTH"].toString().isEmpty()){
661 string subdir = params["FNAME"].toString().split("\\", QString::SkipEmptyParts).last().toStdString();
662 QueueManager::getInstance()->add(target + subdir, size, TTHValue(params["TTH"].toString().toStdString()), HintedUser(user, hubUrl));
663 }
664 else{
665 QueueManager::getInstance()->addDirectory(filename, HintedUser(user, hubUrl), target);
666 }
667 }
668 catch (const Exception&){}
669 }
670
getFileList(const VarMap & params,bool match)671 void SearchFrame::getFileList(const VarMap ¶ms, bool match){
672 string cid = params["CID"].toString().toStdString();
673 string dir = params["FNAME"].toString().toStdString();
674 string host = params["HOST"].toString().toStdString();
675
676 if (cid.empty())
677 return;
678
679 try {
680 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
681
682 if (user){
683 QueueItem::FileFlags flag = match? QueueItem::FLAG_MATCH_QUEUE : QueueItem::FLAG_CLIENT_VIEW;
684
685 QueueManager::getInstance()->addList(HintedUser(user, host), flag, dir);
686 }
687 }
688 catch (const Exception&){}
689
690 }
691
addToFav(const QString & cid)692 void SearchFrame::addToFav(const QString &cid){
693 if (!cid.isEmpty()){
694 try {
695 UserPtr user = ClientManager::getInstance()->findUser(CID(cid.toStdString()));
696
697 if (user)
698 FavoriteManager::getInstance()->addFavoriteUser(user);
699 }
700 catch (const Exception&){}
701 }
702 }
703
grant(const VarMap & params)704 void SearchFrame::grant(const VarMap ¶ms){
705 string cid = params["CID"].toString().toStdString();
706 string host = params["HOST"].toString().toStdString();
707
708 if (cid.empty())
709 return;
710
711 try {
712 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
713
714 if (user)
715 UploadManager::getInstance()->reserveSlot(HintedUser(user, host));
716 }
717 catch (const Exception&){}
718 }
719
removeSource(const VarMap & params)720 void SearchFrame::removeSource(const VarMap ¶ms){
721 string cid = params["CID"].toString().toStdString();
722
723 if (cid.empty())
724 return;
725
726 try {
727 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
728
729 if (user)
730 QueueManager::getInstance()->removeSource(user, QueueItem::Source::FLAG_REMOVED);
731 }
732 catch (const Exception&){}
733
734 }
735
timerTick()736 void SearchFrame::timerTick() {
737
738 }
739
onHubAdded(const QString & info)740 void SearchFrame::onHubAdded(const QString &info){
741 Q_D(SearchFrame);
742
743 if (d->hubs.contains(info) || info.isEmpty())
744 return;
745
746 d->hubs.push_back(info);
747 d->client_list.push_back(ClientManager::getInstance()->getClient(_tq(info)));
748
749 d->str_model->setStringList(d->hubs);
750 }
751
onHubChanged(const QString & info)752 void SearchFrame::onHubChanged(const QString &info){
753 Q_D(SearchFrame);
754
755 if (!d->hubs.contains(info) || info.isEmpty())
756 return;
757
758 Client *cl = ClientManager::getInstance()->getClient(_tq(info));
759 if (!cl || d->client_list.indexOf(cl) < 0)
760 return;
761
762 d->hubs.removeAt(d->client_list.indexOf(cl));
763 d->client_list.removeAt(d->client_list.indexOf(cl));
764
765 d->hubs.push_back(info);
766 d->client_list.push_back(cl);
767
768 d->str_model->setStringList(d->hubs);
769 }
770
onHubRemoved(const QString & info)771 void SearchFrame::onHubRemoved(const QString &info){
772 Q_D(SearchFrame);
773
774 if (!d->hubs.contains(info) || info.isEmpty())
775 return;
776
777 d->client_list.removeAt(d->hubs.indexOf(info));
778 d->hubs.removeAt(d->hubs.indexOf(info));
779
780 d->str_model->setStringList(d->hubs);
781 }
782
getParams(SearchFrame::VarMap & map,const dcpp::SearchResultPtr & ptr)783 void SearchFrame::getParams(SearchFrame::VarMap &map, const dcpp::SearchResultPtr &ptr){
784 map.clear();
785
786 map["SIZE"] = qulonglong(ptr->getSize());
787
788 QString fname = _q(ptr->getFile());
789 const QStringList &fname_parts = fname.split('\\', QString::SkipEmptyParts);
790
791 map["FILE"] = fname_parts.isEmpty()? fname : fname_parts.last();
792
793 if (ptr->getType() == SearchResult::TYPE_FILE){
794 map["TTH"] = _q(ptr->getTTH().toBase32());
795
796 QString path = fname.left(fname.lastIndexOf("\\"));
797
798 if (!path.endsWith("\\"))
799 path += "\\";
800
801 map["PATH"] = path;
802 map["ISDIR"] = false;
803 }
804 else{
805 map["PATH"] = _q(ptr->getFile()).left(_q(ptr->getFile()).lastIndexOf(map["FILE"].toString()));
806 map["TTH"] = "";
807 map["ISDIR"] = true;
808 }
809
810 map["NICK"] = WulforUtil::getInstance()->getNicks(ptr->getUser()->getCID());
811 map["FSLS"] = ptr->getFreeSlots();
812 map["ASLS"] = ptr->getSlots();
813 map["IP"] = _q(ptr->getIP());
814 map["HUB"] = _q(ptr->getHubName());
815 map["HOST"] = _q(ptr->getHubURL());
816 map["CID"] = _q(ptr->getUser()->getCID().toBase32());
817 }
818
getDownloadParams(SearchFrame::VarMap & params,SearchItem * item)819 bool SearchFrame::getDownloadParams(SearchFrame::VarMap ¶ms, SearchItem *item){
820 if (!item)
821 return false;
822
823 params.clear();
824
825 QString fname = item->data(COLUMN_SF_PATH).toString() + item->data(COLUMN_SF_FILENAME).toString();
826
827 if (item->isDir && !fname.endsWith('\\'))
828 fname += "\\";
829
830 params["CID"] = item->cid;
831 params["FNAME"] = fname;
832 params["ESIZE"] = item->data(COLUMN_SF_ESIZE);
833 params["TTH"] = item->data(COLUMN_SF_TTH);
834 params["HOST"] = item->data(COLUMN_SF_HOST);
835 params["TARGET"]= _q(SETTING(DOWNLOAD_DIRECTORY));
836
837 return true;
838 }
839
getWholeDirParams(SearchFrame::VarMap & params,SearchItem * item)840 bool SearchFrame::getWholeDirParams(SearchFrame::VarMap ¶ms, SearchItem *item){
841 if (!item)
842 return false;
843
844 params.clear();
845
846 params["CID"] = item->cid;
847
848 if (item->isDir)
849 params["FNAME"] = item->data(COLUMN_SF_PATH).toString() + item->data(COLUMN_SF_FILENAME).toString();
850 else
851 params["FNAME"] = item->data(COLUMN_SF_PATH).toString();//Download directory that containing a file
852
853 params["ESIZE"] = 0;
854 params["TTH"] = "";
855 params["HOST"] = item->data(COLUMN_SF_HOST);
856 params["TARGET"]= _q(SETTING(DOWNLOAD_DIRECTORY));
857
858 return true;
859 }
860
addResult(const QMap<QString,QVariant> & map)861 void SearchFrame::addResult(const QMap<QString, QVariant> &map){
862 Q_D(SearchFrame);
863 static SearchBlacklist *SB = SearchBlacklist::getInstance();
864
865 try {
866 if (SB->ok(map["FILE"].toString(), SearchBlacklist::NAME) && SB->ok(map["TTH"].toString(), SearchBlacklist::TTH)){
867 if (d->model->addResult(map["FILE"].toString(),
868 map["SIZE"].toULongLong(),
869 map["TTH"].toString(),
870 map["PATH"].toString(),
871 map["NICK"].toString(),
872 map["FSLS"].toULongLong(),
873 map["ASLS"].toULongLong(),
874 map["IP"].toString(),
875 map["HUB"].toString(),
876 map["HOST"].toString(),
877 map["CID"].toString(),
878 map["ISDIR"].toBool()))
879 d->results++;
880 }
881 }
882 catch (const SearchListException&){}
883 }
884
searchAlternates(const QString & tth)885 void SearchFrame::searchAlternates(const QString &tth){
886 if (tth.isEmpty())
887 return;
888
889 Q_D(SearchFrame);
890
891 lineEdit_SEARCHSTR->setText(tth);
892 comboBox_FILETYPES->setCurrentIndex(SearchManager::TYPE_TTH);
893 lineEdit_SIZE->setText("");
894
895 slotStartSearch();
896
897 d->saveFileType = false;
898 }
899
searchFile(const QString & file)900 void SearchFrame::searchFile(const QString &file){
901 if (file.isEmpty())
902 return;
903
904 Q_D(SearchFrame);
905
906 lineEdit_SEARCHSTR->setText(file);
907 comboBox_FILETYPES->setCurrentIndex(SearchManager::TYPE_ANY);
908 lineEdit_SIZE->setText("");
909
910 d->saveFileType = false;
911
912 slotStartSearch();
913 }
914
fastSearch(const QString & text,bool isTTH)915 void SearchFrame::fastSearch(const QString &text, bool isTTH){
916 if (text.isEmpty())
917 return;
918
919 if (!isTTH)
920 comboBox_FILETYPES->setCurrentIndex(0); // set type "Any"
921 else
922 comboBox_FILETYPES->setCurrentIndex(8); // set type "TTH"
923
924 lineEdit_SEARCHSTR->setText(text);
925
926 slotStartSearch();
927 }
928
slotStartSearch()929 void SearchFrame::slotStartSearch(){
930 if (qobject_cast<QPushButton*>(sender()) != pushButton_SEARCH){
931 pushButton_SEARCH->click(); //Generating clicked() signal that shows pushButton_STOP button.
932 //Anybody can suggest something better?
933 return;
934 }
935
936 Q_D(SearchFrame);
937
938 d->stop = false;
939
940 if (lineEdit_SEARCHSTR->text().trimmed().isEmpty())
941 return;
942
943 MainWindow *MW = MainWindow::getInstance();
944 QString s = lineEdit_SEARCHSTR->text().trimmed();
945 StringList clients;
946
947 for (int i = 0; i < d->str_model->rowCount(); i++){
948 QModelIndex index = d->str_model->index(i, 0);
949
950 if (index.data(Qt::CheckStateRole).toInt() == Qt::Checked)
951 clients.push_back(_tq(index.data().toString()));
952 }
953
954 #ifndef WITH_DHT
955 if (clients.empty())
956 return;
957 #endif
958
959 QString str_size = lineEdit_SIZE->text();
960 double lsize = Util::toDouble(Text::fromT(str_size.toStdString()));
961
962 switch (comboBox_SIZE->currentIndex()){
963 case 1:
964 lsize *= 1024.0;
965
966 break;
967 case 2:
968 lsize *= (1024.0*1024.0);
969
970 break;
971 case 3:
972 lsize *= (1024.0*1024.0*1024.0);
973
974 break;
975 }
976
977 quint64 llsize = (quint64)lsize;
978
979 if (!d->searchHistory.contains(s)){
980 bool isTTH = WulforUtil::isTTH(s);
981
982 if ((WBGET("memorize-tth-search-phrases", false) && isTTH) || !isTTH)
983 d->searchHistory.push_front(s);
984
985 QMenu *m = new QMenu();
986
987 for (const auto &s : d->searchHistory)
988 m->addAction(s);
989
990 lineEdit_SEARCHSTR->setMenu(m);
991
992 uint maxItemsNumber = WIGET("search-history-items-number", 10);
993 while (d->searchHistory.count() > maxItemsNumber)
994 d->searchHistory.removeLast();
995
996 QString hist = d->searchHistory.join("\n");
997 WSSET(WS_SEARCH_HISTORY, hist.toUtf8().toBase64());
998 }
999
1000 {
1001 d->currentSearch = StringTokenizer<tstring>(s.toStdString(), ' ').getTokens();
1002 s = "";
1003
1004 //strip out terms beginning with -
1005 for (auto si = d->currentSearch.begin(); si != d->currentSearch.end(); ) {
1006 if(si->empty()) {
1007 si = d->currentSearch.erase(si);
1008 continue;
1009 }
1010
1011 if ((*si)[0] != '-')
1012 s += QString::fromStdString(*si) + ' ';
1013
1014 ++si;
1015 }
1016
1017 d->token = _q(Util::toString(Util::rand()));
1018 }
1019
1020 SearchManager::SizeModes searchMode((SearchManager::SizeModes)comboBox_SIZETYPE->currentIndex());
1021
1022 if(!llsize || lineEdit_SIZE->text() == "")
1023 searchMode = SearchManager::SIZE_DONTCARE;
1024
1025 int ftype = comboBox_FILETYPES->currentIndex();
1026
1027 d->isHash = (ftype == SearchManager::TYPE_TTH);
1028 d->filterShared = static_cast<AlreadySharedAction>(comboBox_SHARED->currentIndex());
1029 d->withFreeSlots = checkBox_FILTERSLOTS->isChecked();
1030
1031 d->model->setFilterRole(static_cast<int>(d->filterShared));
1032 d->model->clearModel();
1033
1034 d->dropped = d->results = 0;
1035
1036 string ftypeStr;
1037 if (ftype > SearchManager::TYPE_ANY && ftype < SearchManager::TYPE_LAST)
1038 ftypeStr = SearchManager::getInstance()->getTypeStr(ftype);
1039 else
1040 {
1041 ftypeStr = _tq(lineEdit_SEARCHSTR->text());
1042 ftype = SearchManager::TYPE_ANY;
1043 }
1044
1045 StringList exts;
1046 try{
1047 if (ftype == SearchManager::TYPE_ANY){
1048 // Custom searchtype
1049 exts = SettingsManager::getInstance()->getExtensions(ftypeStr);
1050 }
1051 else if ((ftype > SearchManager::TYPE_ANY && ftype < SearchManager::TYPE_DIRECTORY) || ftype == SearchManager::TYPE_CD_IMAGE){
1052 // Predefined searchtype
1053 exts = SettingsManager::getInstance()->getExtensions(string(1, '0' + ftype));
1054 }
1055 }
1056 catch (const SearchTypeException&){
1057 ftype = SearchManager::TYPE_ANY;
1058 }
1059
1060 d->target = s;
1061 d->searchStartTime = GlobalTimer::getInstance()->getTicks()*1000;
1062
1063 uint64_t maxDelayBeforeSearch = SearchManager::getInstance()->search(clients, s.toStdString(), llsize, (SearchManager::TypeModes)ftype, searchMode, d->token.toStdString(), exts, (void*)this);
1064 uint64_t waitingResultsTime = 20000; // just assumption that user receives most of results in 20 seconds
1065
1066 d->searchEndTime = d->searchStartTime + maxDelayBeforeSearch + waitingResultsTime;
1067 d->waitingResults = true;
1068
1069 if (!checkBox_HIDEPANEL->isChecked()){
1070 QList<int> panes = splitter->sizes();
1071
1072 panes[1] = panes[0] + panes[1];
1073
1074 d->left_pane_old_size = panes[0] > 15 ? panes[0] : d->left_pane_old_size;
1075
1076 panes[0] = 0;
1077
1078 splitter->setSizes(panes);
1079 }
1080
1081 d->arena_title = tr("Search - %1").arg(s);
1082
1083 lineEdit_SEARCHSTR->setEnabled(false);
1084
1085 MW->redrawToolPanel();
1086 }
1087
slotClear()1088 void SearchFrame::slotClear(){
1089 Q_D(SearchFrame);
1090
1091 treeView_RESULTS->clearSelection();
1092 d->model->clearModel();
1093 lineEdit_SEARCHSTR->clear();
1094 lineEdit_SIZE->setText("");
1095
1096 d->dropped = d->results = 0;
1097 }
1098
slotResultDoubleClicked(const QModelIndex & index)1099 void SearchFrame::slotResultDoubleClicked(const QModelIndex &index){
1100 if (!index.isValid() || !index.internalPointer())
1101 return;
1102
1103 Q_D(SearchFrame);
1104
1105 QModelIndex i = d->proxy? d->proxy->mapToSource(index) : index;
1106
1107 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1108 VarMap params;
1109
1110 if (getDownloadParams(params, item)){
1111 download(params);
1112
1113 if (item->childCount() > 0 && !SETTING(DONT_DL_ALREADY_QUEUED)){//download all child items
1114 QString fname = params["FNAME"].toString();
1115
1116 for (const auto &i : item->childItems){
1117 if (getDownloadParams(params, i)){
1118 params["FNAME"] = fname;
1119
1120 download(params);
1121 }
1122 }
1123 }
1124 }
1125 }
1126
slotContextMenu(const QPoint &)1127 void SearchFrame::slotContextMenu(const QPoint &){
1128 QItemSelectionModel *selection_model = treeView_RESULTS->selectionModel();
1129 QModelIndexList list = selection_model->selectedRows(0);
1130 Q_D(SearchFrame);
1131
1132 if (list.size() < 1)
1133 return;
1134
1135 if (d->proxy)
1136 std::transform(list.begin(), list.end(), list.begin(), [&d](QModelIndex i) { return d->proxy->mapToSource(i); } );
1137
1138 if (!Menu::getInstance())
1139 Menu::newInstance();
1140
1141 QStringList hubs;
1142
1143 for (const auto &i : list){
1144 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1145 QString host = item->data(COLUMN_SF_HOST).toString();
1146
1147 if (!hubs.contains(host))
1148 hubs.push_back(host);
1149 }
1150
1151 Menu::Action act = Menu::getInstance()->exec(hubs);
1152
1153 switch (act){
1154 case Menu::None:
1155 {
1156 break;
1157 }
1158 case Menu::Download:
1159 {
1160 for (const auto &i : list){
1161 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1162 VarMap params;
1163
1164 if (getDownloadParams(params, item)){
1165 download(params);
1166
1167 if (item->childCount() > 0 && !SETTING(DONT_DL_ALREADY_QUEUED)){//download all child items
1168 QString fname = params["FNAME"].toString();
1169
1170 for (const auto &i : item->childItems){
1171 if (getDownloadParams(params, i)){
1172 params["FNAME"] = fname;
1173
1174 download(params);
1175 }
1176 }
1177 }
1178 }
1179 }
1180
1181 break;
1182 }
1183 case Menu::DownloadTo:
1184 {
1185 static QString old_target = QDir::homePath();
1186 QString target = Menu::getInstance()->getDownloadToPath();
1187
1188 if (!QDir(target).exists() || target.isEmpty()){
1189 target = QFileDialog::getExistingDirectory(this, tr("Select directory"), old_target);
1190
1191 target = QDir::toNativeSeparators(target);
1192
1193 Menu::getInstance()->addTempPath(target);
1194 }
1195
1196 if (target.isEmpty())
1197 break;
1198
1199 if (!target.endsWith(QDir::separator()))
1200 target += QDir::separator();
1201
1202 old_target = target;
1203
1204 for (const auto &i : list){
1205 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1206 VarMap params;
1207
1208 if (getDownloadParams(params, item)){
1209 params["TARGET"] = target;
1210 download(params);
1211
1212 if (item->childCount() > 0 && !SETTING(DONT_DL_ALREADY_QUEUED)){//download all child items
1213 QString fname = params["FNAME"].toString();
1214
1215 for (const auto &i : item->childItems){
1216 if (getDownloadParams(params, i)){
1217 params["FNAME"] = fname;
1218 params["TARGET"] = target;
1219
1220 download(params);
1221 }
1222 }
1223 }
1224 }
1225 }
1226
1227 break;
1228 }
1229 case Menu::DownloadWholeDir:
1230 {
1231 for (const auto &i : list){
1232 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1233 VarMap params;
1234
1235 if (getWholeDirParams(params, item))
1236 download(params);
1237 }
1238
1239 break;
1240 }
1241 case Menu::DownloadWholeDirTo:
1242 {
1243 static QString old_target = QDir::homePath();
1244 QString target = Menu::getInstance()->getDownloadToPath();
1245
1246 if (!QDir(target).exists() || target.isEmpty()){
1247 target = QFileDialog::getExistingDirectory(this, tr("Select directory"), old_target);
1248
1249 target = QDir::toNativeSeparators(target);
1250
1251 Menu::getInstance()->addTempPath(target);
1252 }
1253
1254 if (target.isEmpty())
1255 break;
1256
1257 if (!target.endsWith(QDir::separator()))
1258 target += QDir::separator();
1259
1260 old_target = target;
1261
1262 for (const auto &i : list){
1263 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1264 VarMap params;
1265
1266 if (getWholeDirParams(params, item)){
1267 params["TARGET"] = target;
1268 download(params);
1269 }
1270 }
1271
1272 break;
1273 }
1274 case Menu::SearchTTH:
1275 {
1276 for (const auto &i : list){
1277 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1278
1279 if (!item->isDir){//only one file
1280 SearchFrame *sf = ArenaWidgetFactory().create<SearchFrame>();
1281
1282 sf->searchAlternates(item->data(COLUMN_SF_TTH).toString());
1283
1284 break;
1285 }
1286 }
1287
1288 break;
1289 }
1290 case Menu::Magnet:
1291 {
1292 QString magnets = "";
1293 WulforUtil *WU = WulforUtil::getInstance();
1294
1295 for (const auto &i : list){
1296 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1297
1298 if (!item->isDir){//only files
1299 qlonglong size = item->data(COLUMN_SF_ESIZE).toLongLong();
1300 QString tth = item->data(COLUMN_SF_TTH).toString();
1301 QString name = item->data(COLUMN_SF_FILENAME).toString();
1302
1303 QString magnet = WU->makeMagnet(name, size, tth);
1304
1305 if (!magnet.isEmpty())
1306 magnets += magnet + "\n";
1307 }
1308 }
1309
1310 magnets = magnets.trimmed();
1311
1312 if (!magnets.isEmpty())
1313 qApp->clipboard()->setText(magnets, QClipboard::Clipboard);
1314
1315 break;
1316 }
1317 case Menu::MagnetWeb:
1318 {
1319 QString magnets = "";
1320 WulforUtil *WU = WulforUtil::getInstance();
1321
1322 for (const auto &i : list){
1323 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1324
1325 if (!item->isDir){//only files
1326 qlonglong size = item->data(COLUMN_SF_ESIZE).toLongLong();
1327 QString tth = item->data(COLUMN_SF_TTH).toString();
1328 QString name = item->data(COLUMN_SF_FILENAME).toString();
1329
1330 QString magnet = "[magnet=\"" + WU->makeMagnet(name, size, tth) + "\"]"+name+"[/magnet]";
1331
1332 if (!magnet.isEmpty())
1333 magnets += magnet + "\n";
1334 }
1335 }
1336
1337 magnets = magnets.trimmed();
1338
1339 if (!magnets.isEmpty())
1340 qApp->clipboard()->setText(magnets, QClipboard::Clipboard);
1341
1342 break;
1343 }
1344 case Menu::MagnetInfo:
1345 {
1346 WulforUtil *WU = WulforUtil::getInstance();
1347
1348 for (const auto &i : list){
1349 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1350
1351 if (!item->isDir){//only files
1352 qlonglong size = item->data(COLUMN_SF_ESIZE).toLongLong();
1353 QString tth = item->data(COLUMN_SF_TTH).toString();
1354 QString name = item->data(COLUMN_SF_FILENAME).toString();
1355
1356 QString magnet = WU->makeMagnet(name, size, tth);
1357
1358 if (!magnet.isEmpty()){
1359 Magnet m(this);
1360 m.setLink(magnet + "\n");
1361 m.exec();
1362 }
1363 }
1364 }
1365
1366 break;
1367 }
1368 case Menu::Browse:
1369 {
1370 for (const auto &i : list){
1371 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1372 VarMap params;
1373
1374 if (getWholeDirParams(params, item))
1375 getFileList(params, false);
1376 }
1377
1378 break;
1379 }
1380 case Menu::MatchQueue:
1381 {
1382 for (const auto &i : list){
1383 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1384 VarMap params;
1385
1386 if (getWholeDirParams(params, item)){
1387 params["FNAME"] = "";
1388 getFileList(params, true);
1389 }
1390 }
1391
1392 break;
1393 }
1394 case Menu::SendPM:
1395 {
1396 HubFrame *fr = NULL;
1397
1398 for (const auto &i : list){
1399 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1400
1401 QString hubUrl = item->data(COLUMN_SF_HOST).toString();
1402 dcpp::CID cid(_tq(item->cid));
1403
1404 fr = qobject_cast<HubFrame*>(HubManager::getInstance()->getHub(hubUrl));
1405
1406 if (fr)
1407 fr->createPMWindow(cid);
1408 }
1409
1410 break;
1411 }
1412 case Menu::AddToFav:
1413 {
1414 for (const auto &i : list){
1415 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1416 VarMap params;
1417
1418 if (getDownloadParams(params, item))
1419 addToFav(params["CID"].toString());
1420
1421 }
1422
1423 break;
1424 }
1425 case Menu::GrantExtraSlot:
1426 {
1427 for (const auto &i : list){
1428 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1429 VarMap params;
1430
1431 if (getDownloadParams(params, item))
1432 grant(params);
1433
1434 }
1435
1436 break;
1437 }
1438 case Menu::RemoveFromQueue:
1439 {
1440 for (const auto &i : list){
1441 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1442 VarMap params;
1443
1444 if (getDownloadParams(params, item))
1445 removeSource(params);
1446
1447 }
1448
1449 break;
1450 }
1451 case Menu::Remove:
1452 {
1453 selection_model->clearSelection();
1454
1455 for (const auto &i : list){
1456 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1457
1458 d->model->removeItem(item);
1459
1460 d->model->repaint();
1461 }
1462
1463 break;
1464 }
1465 case Menu::UserCommands:
1466 {
1467 for (const auto &i : list){
1468 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1469
1470 int id = Menu::getInstance()->getCommandId();
1471
1472 UserCommand uc;
1473 if (id == -1 || !FavoriteManager::getInstance()->getUserCommand(id, uc))
1474 break;
1475
1476 StringMap params;
1477
1478 if (WulforUtil::getInstance()->getUserCommandParams(uc, params)){
1479 UserPtr user = ClientManager::getInstance()->findUser(CID(item->cid.toStdString()));
1480
1481 if (user && user->isOnline()){
1482 params["fileFN"] = _tq(item->data(COLUMN_SF_PATH).toString() + item->data(COLUMN_SF_FILENAME).toString());
1483 params["fileSI"] = _tq(item->data(COLUMN_SF_ESIZE).toString());
1484 params["fileSIshort"]= _tq(item->data(COLUMN_SF_SIZE).toString());
1485
1486 if(!item->isDir)
1487 params["fileTR"] = _tq(item->data(COLUMN_SF_TTH).toString());
1488
1489 // compatibility with 0.674 and earlier
1490 params["file"] = params["fileFN"];
1491 params["filesize"] = params["fileSI"];
1492 params["filesizeshort"] = params["fileSIshort"];
1493 params["tth"] = params["fileTR"];
1494
1495 string hubUrl = _tq(i.data(COLUMN_SF_HOST).toString());
1496
1497 ClientManager::getInstance()->userCommand(HintedUser(user, hubUrl), uc, params, true);
1498 }
1499
1500 }
1501 }
1502
1503 break;
1504 }
1505 case Menu::Blacklist:
1506 {
1507 SearchBlackListDialog dlg(this);
1508
1509 dlg.exec();
1510
1511 break;
1512 }
1513 case Menu::AddToBlacklist:
1514 {
1515 QList <QString> new_inst;
1516
1517 for (const auto &i : list){
1518 SearchItem *item = reinterpret_cast<SearchItem*>(i.internalPointer());
1519 VarMap params;
1520
1521 if (getDownloadParams(params, item))
1522 new_inst << item->data(COLUMN_SF_FILENAME).toString();
1523 }
1524 if (!new_inst.isEmpty()){
1525 static SearchBlacklist *SB = SearchBlacklist::getInstance();
1526 QList <QString> list = SB->getList(SearchBlacklist::NAME);
1527 list.append(new_inst);
1528 SB->setList(SearchBlacklist::NAME, list);
1529 }
1530
1531 break;
1532 }
1533 default:
1534 {
1535 break;
1536 }
1537 }
1538 }
1539
slotHeaderMenu(const QPoint &)1540 void SearchFrame::slotHeaderMenu(const QPoint&){
1541 WulforUtil::headerMenu(treeView_RESULTS);
1542 }
1543
slotTimer()1544 void SearchFrame::slotTimer(){
1545 Q_D(SearchFrame);
1546
1547 if (d->waitingResults) {
1548 uint64_t now = GlobalTimer::getInstance()->getTicks()*1000;
1549 float fraction = 100.0f*(now - d->searchStartTime)/(d->searchEndTime - d->searchStartTime);
1550 if (fraction >= 100.0) {
1551 fraction = 100.0;
1552 d->waitingResults = false;
1553 }
1554 QString msg = tr("Searching for %1 ...").arg(d->target);
1555 progressBar->setFormat(msg);
1556 progressBar->setValue(static_cast<unsigned>(fraction));
1557 } else {
1558 QString msg = "";
1559 progressBar->setFormat(msg);
1560 progressBar->setValue(0);
1561 lineEdit_SEARCHSTR->setEnabled(true);
1562 }
1563
1564 if (d->dropped == d->results && !d->dropped){
1565
1566 if (d->currentSearch.empty())
1567 frame_PROGRESS->hide();
1568 else {
1569 frame_PROGRESS->show();
1570
1571 QString text = QString(tr("<b>No results</b>"));
1572
1573 status->setText(text);
1574 }
1575 }
1576 else {
1577 if (!frame_PROGRESS->isVisible())
1578 frame_PROGRESS->show();
1579
1580 QString text = QString(tr("Found: <b>%1</b> Dropped: <b>%2</b>")).arg(d->results).arg(d->dropped);
1581
1582 status->setText(text);
1583 }
1584 }
1585
slotToggleSidePanel()1586 void SearchFrame::slotToggleSidePanel(){
1587 QList<int> panes = splitter->sizes();
1588 Q_D(SearchFrame);
1589
1590 if (panes[0] < 15){//left pane can't have width less than 15px
1591 panes[0] = d->left_pane_old_size;
1592 panes[1] = panes[1] - d->left_pane_old_size;
1593 }
1594 else {
1595 panes[1] = panes[0] + panes[1];
1596 d->left_pane_old_size = panes[0];
1597 panes[0] = 0;
1598 }
1599
1600 splitter->setSizes(panes);
1601 }
1602
slotFilter()1603 void SearchFrame::slotFilter(){
1604 Q_D(SearchFrame);
1605
1606 if (frame_FILTER->isVisible()){
1607 treeView_RESULTS->setModel(d->model);
1608
1609 disconnect(lineEdit_FILTER, SIGNAL(textChanged(QString)), d->proxy, SLOT(setFilterFixedString(QString)));
1610 }
1611 else {
1612 d->proxy = (d->proxy? d->proxy : (new SearchProxyModel(this)));
1613 d->proxy->setDynamicSortFilter(true);
1614 d->proxy->setFilterFixedString(lineEdit_FILTER->text());
1615 d->proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
1616 d->proxy->setFilterKeyColumn(comboBox_FILTERCOLUMNS->currentIndex());
1617 d->proxy->setSourceModel(d->model);
1618
1619 treeView_RESULTS->setModel(d->proxy);
1620
1621 connect(lineEdit_FILTER, SIGNAL(textChanged(QString)), d->proxy, SLOT(setFilterFixedString(QString)));
1622
1623 if (!lineEdit_SEARCHSTR->selectedText().isEmpty()){
1624 lineEdit_FILTER->setText(lineEdit_SEARCHSTR->selectedText());
1625 lineEdit_FILTER->selectAll();
1626 }
1627
1628 lineEdit_FILTER->setFocus();
1629
1630 if (!lineEdit_FILTER->text().isEmpty())
1631 lineEdit_FILTER->selectAll();
1632 }
1633
1634 frame_FILTER->setVisible(!frame_FILTER->isVisible());
1635 }
1636
slotChangeProxyColumn(int col)1637 void SearchFrame::slotChangeProxyColumn(int col){
1638 Q_D(SearchFrame);
1639
1640 if (d->proxy)
1641 d->proxy->setFilterKeyColumn(col);
1642 }
1643
slotSettingsChanged(const QString & key,const QString & value)1644 void SearchFrame::slotSettingsChanged(const QString &key, const QString &value){
1645 if (key == WS_TRANSLATION_FILE)
1646 retranslateUi(this);
1647 }
1648
on(SearchManagerListener::SR,const dcpp::SearchResultPtr & aResult)1649 void SearchFrame::on(SearchManagerListener::SR, const dcpp::SearchResultPtr& aResult) noexcept {
1650 Q_D(SearchFrame);
1651
1652 if (d->currentSearch.empty() || !aResult || d->stop == true)
1653 return;
1654
1655 if (!aResult->getToken().empty() && d->token != _q(aResult->getToken())){
1656 d->dropped++;
1657
1658 return;
1659 }
1660
1661 if(d->isHash) {
1662 if(aResult->getType() != SearchResult::TYPE_FILE || TTHValue(Text::fromT(d->currentSearch[0])) != aResult->getTTH()) {
1663 d->dropped++;
1664
1665 return;
1666 }
1667 }
1668 else {
1669 for (const auto &j : d->currentSearch) {
1670 if((*j.begin() != ('-') && Util::findSubString(aResult->getFile(), j) == tstring::npos) ||
1671 (*j.begin() == ('-') && j.size() != 1 && Util::findSubString(aResult->getFile(), j.substr(1)) != tstring::npos)
1672 )
1673 {
1674 d->dropped++;
1675
1676 return;
1677 }
1678 }
1679 }
1680
1681 if (d->filterShared == Filter && aResult->getType() == SearchResult::TYPE_FILE){
1682 const TTHValue& t = aResult->getTTH();
1683
1684 if (ShareManager::getInstance()->isTTHShared(t)) {
1685 d->dropped++;
1686
1687 return;
1688 }
1689 }
1690
1691 if (d->withFreeSlots && !aResult->getFreeSlots()){
1692 d->dropped++;
1693
1694 return;
1695 }
1696
1697 QMap<QString, QVariant> map;
1698 getParams(map, aResult);
1699
1700 emit coreSR(map);
1701 }
1702
slotClose()1703 void SearchFrame::slotClose() {
1704 ArenaWidgetManager::getInstance()->rem(this);
1705 }
1706
on(ClientConnected,Client * c)1707 void SearchFrame::on(ClientConnected, Client* c) noexcept{
1708 emit coreClientConnected(_q(c->getHubUrl()));
1709 }
1710
on(ClientUpdated,Client * c)1711 void SearchFrame::on(ClientUpdated, Client* c) noexcept{
1712 emit coreClientUpdated((_q(c->getHubUrl())));
1713 }
1714
on(ClientDisconnected,Client * c)1715 void SearchFrame::on(ClientDisconnected, Client* c) noexcept{
1716 emit coreClientDisconnected((_q(c->getHubUrl())));
1717 }
1718
slotStopSearch()1719 void SearchFrame::slotStopSearch(){
1720 Q_D(SearchFrame);
1721
1722 d->stop = true;
1723 d->waitingResults = false;
1724 }
1725