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 "DownloadQueue.h"
11
12 #include <QMap>
13 #include <QTreeView>
14 #include <QAbstractItemModel>
15 #include <QItemSelectionModel>
16 #include <QFileDialog>
17 #include <QClipboard>
18 #include <QHeaderView>
19 #include <QDir>
20 #include <QShortcut>
21
22 #include "DownloadQueueModel.h"
23 #include "ArenaWidgetFactory.h"
24 #include "SearchFrame.h"
25 #include "HubFrame.h"
26 #include "HubManager.h"
27 #include "WulforUtil.h"
28 #include "WulforSettings.h"
29 #include "Magnet.h"
30 #include "dcpp/ClientManager.h"
31 #include "dcpp/User.h"
32
33 #define _DEBUG_ 1
34
35 #if _DEBUG_
36 #include <QtDebug>
37 #endif
38
39 using namespace dcpp;
40
41 class DownloadQueuePrivate {
42 typedef QMap<QString, QVariant> VarMap;
43 typedef QMap<QString, QMap<QString, QString> > SourceMap;
44
45 public:
46 QShortcut *deleteShortcut;
47
48 DownloadQueueModel *queue_model;
49 DownloadQueueModel *file_model;
50 DownloadQueueDelegate *delegate;
51
52 DownloadQueue::Menu *menu;
53
54 SourceMap sources;
55 SourceMap badSources;
56 };
57
Menu()58 DownloadQueue::Menu::Menu(){
59 menu = new QMenu();
60 QMenu *menu_magnet = new QMenu(tr("Magnet"), DownloadQueue::getInstance());
61
62 QAction *search_alt = new QAction(tr("Search for alternates"), menu);
63 QAction *copy_magnet = new QAction(tr("Copy magnet"), menu_magnet);
64 QAction *copy_magnet_web = new QAction(tr("Copy web-magnet"), menu_magnet);
65 QAction *magnet_info = new QAction(tr("Properties of magnet"), menu_magnet);
66 QAction *ren_move = new QAction(tr("Rename/Move"), menu);
67
68 QAction *sep1 = new QAction(menu);
69 sep1->setSeparator(true);
70
71 set_prio = new QMenu(tr("Set priority"), menu);
72 {
73 QAction *paused = new QAction(tr("Paused"), set_prio);
74 paused->setData(static_cast<int>(QueueItem::PAUSED));
75
76 QAction *lowest = new QAction(tr("Lowest"), set_prio);
77 lowest->setData(static_cast<int>(QueueItem::LOWEST));
78
79 QAction *low = new QAction(tr("Low"), set_prio);
80 low->setData(static_cast<int>(QueueItem::LOW));
81
82 QAction *normal = new QAction(tr("Normal"), set_prio);
83 normal->setData(static_cast<int>(QueueItem::NORMAL));
84
85 QAction *high = new QAction(tr("High"), set_prio);
86 high->setData(static_cast<int>(QueueItem::HIGH));
87
88 QAction *highest= new QAction(tr("Highest"), set_prio);
89 highest->setData(static_cast<int>(QueueItem::HIGHEST));
90
91 set_prio->addActions(QList<QAction*>() << paused << lowest << low << normal << high << highest);
92 }
93
94 browse = new QMenu(tr("Browse files"), menu);
95 send_pm = new QMenu(tr("Send private message"), menu);
96
97 QAction *sep2 = new QAction(menu);
98 sep2->setSeparator(true);
99
100 rem_src = new QMenu(tr("Remove source"), menu);
101 rem_usr = new QMenu(tr("Remove user"), menu);
102
103 QAction *remove = new QAction(tr("Remove"), menu);
104
105 QAction *sep3 = new QAction(menu);
106 sep3->setSeparator(true);
107
108 map[search_alt] = Alternates;
109 map[copy_magnet] = Magnet;
110 map[copy_magnet_web] = MagnetWeb;
111 map[magnet_info] = MagnetInfo;
112 map[ren_move] = RenameMove;
113 map[remove] = Remove;
114
115 menu_magnet->addActions(QList<QAction*>()
116 << copy_magnet << copy_magnet_web << sep3 << magnet_info);
117
118 menu->addAction(search_alt);
119 menu->addMenu(menu_magnet);
120 menu->addAction(ren_move);
121 menu->addAction(sep1);
122 menu->addMenu(set_prio);
123 menu->addMenu(browse);
124 menu->addMenu(send_pm);
125 menu->addAction(sep2);
126 menu->addMenu(rem_src);
127 menu->addMenu(rem_usr);
128 menu->addAction(remove);
129 }
130
~Menu()131 DownloadQueue::Menu::~Menu(){
132 delete menu;
133 }
134
clearMenu(QMenu * m)135 void DownloadQueue::Menu::clearMenu(QMenu *m){
136 if (!m)
137 return;
138
139 QList<QAction*> actions = m->actions();
140
141 for (const auto &a : actions)
142 m->removeAction(a);
143
144 qDeleteAll(actions);
145 }
146
exec(const DownloadQueue::SourceMap & sources,const QString & target,bool multiselect)147 DownloadQueue::Menu::Action DownloadQueue::Menu::exec(const DownloadQueue::SourceMap &sources, const QString &target, bool multiselect){
148 if (target.isEmpty() || sources.isEmpty() || !sources.contains(target))
149 return None;
150
151 arg = QVariant();
152
153 clearMenu(browse), clearMenu(send_pm), clearMenu(rem_src), clearMenu(rem_usr);
154
155 browse->setDisabled(multiselect);
156 send_pm->setDisabled(multiselect);
157 rem_src->setDisabled(multiselect);
158 rem_usr->setDisabled(multiselect);
159
160 QMap<QString, QString> users = sources[target];
161 auto it = users.constBegin();
162
163 for (; it != users.constEnd(); ++it){
164 QAction *act = new QAction(it.key(), menu);
165 act->setStatusTip(it.value());
166
167 browse->addAction(act);
168 send_pm->addAction(act);
169 rem_src->addAction(act);
170 rem_usr->addAction(act);
171 }
172
173 QAction *ret = menu->exec(QCursor::pos());
174 DownloadQueue::VarMap rmap;
175
176 if (!ret)
177 return None;
178 else if (map.contains(ret))
179 return map[ret];
180 else if (set_prio->actions().contains(ret)){
181 arg = ret->data();
182
183 return SetPriority;
184 }
185
186 rmap.insert(ret->text(), ret->statusTip());
187 arg = rmap;
188
189 if (browse->actions().contains(ret))
190 return Browse;
191 else if (send_pm->actions().contains(ret))
192 return SendPM;
193 else if (rem_src->actions().contains(ret))
194 return RemoveSource;
195 else if (rem_usr->actions().contains(ret))
196 return RemoveUser;
197 else
198 arg = QVariant();
199
200 return None;
201 }
202
getArg()203 QVariant DownloadQueue::Menu::getArg(){
204 return arg;
205 }
206
DownloadQueue(QWidget * parent)207 DownloadQueue::DownloadQueue(QWidget *parent):
208 QWidget(parent), d_ptr(new DownloadQueuePrivate())
209 {
210 setupUi(this);
211
212 init();
213
214 QueueManager::getInstance()->addListener(this);
215
216 setUnload(false);
217 }
218
~DownloadQueue()219 DownloadQueue::~DownloadQueue(){
220 save();
221
222 QueueManager::getInstance()->removeListener(this);
223 Q_D(DownloadQueue);
224
225 delete d->menu;
226 delete d_ptr;
227 }
228
closeEvent(QCloseEvent * e)229 void DownloadQueue::closeEvent(QCloseEvent *e){
230 isUnload()? e->accept() : e->ignore();
231 }
232
requestDelete()233 void DownloadQueue::requestDelete(){
234 if (!treeView_TARGET->hasFocus())
235 return;
236
237 QModelIndexList list = treeView_TARGET->selectionModel()->selectedRows(0);
238
239 if (list.isEmpty())
240 return;
241
242 QList<DownloadQueueItem*> items;
243
244 for (const auto &i : list){
245 DownloadQueueItem *item = reinterpret_cast<DownloadQueueItem*>(i.internalPointer());
246
247 if (!item)
248 continue;
249
250 if (item->dir)
251 getChilds(item, items);
252 else if (!items.contains(item))
253 items.push_front(item);
254 }
255
256 QueueManager *QM = QueueManager::getInstance();
257 for (const auto &i : items){
258 QString target = i->data(COLUMN_DOWNLOADQUEUE_PATH).toString() + i->data(COLUMN_DOWNLOADQUEUE_NAME).toString();
259
260 try {
261 QM->remove(target.toStdString());
262 }
263 catch (const Exception &){}
264 }
265 }
266
init()267 void DownloadQueue::init(){
268 Q_D(DownloadQueue);
269
270 d->queue_model = new DownloadQueueModel(this);
271
272 d->delegate = new DownloadQueueDelegate(d->queue_model);
273
274 treeView_TARGET->setItemDelegate(d->delegate);
275 treeView_TARGET->setModel(d->queue_model);
276 treeView_TARGET->setItemsExpandable(true);
277 treeView_TARGET->setRootIsDecorated(true);
278 treeView_TARGET->setContextMenuPolicy(Qt::CustomContextMenu);
279 treeView_TARGET->header()->setContextMenuPolicy(Qt::CustomContextMenu);
280
281 label_STATS->hide();
282
283 d->deleteShortcut = new QShortcut(QKeySequence(Qt::Key_Delete), this);
284 d->deleteShortcut->setContext(Qt::WidgetWithChildrenShortcut);
285
286 connect(this, SIGNAL(coreAdded(VarMap)), this, SLOT(addFile(VarMap)), Qt::QueuedConnection);
287 connect(this, SIGNAL(coreRemoved(VarMap)), this, SLOT(remFile(VarMap)), Qt::QueuedConnection);
288 connect(this, SIGNAL(coreSourcesUpdated(VarMap)), this, SLOT(updateFile(VarMap)), Qt::QueuedConnection);
289 connect(this, SIGNAL(coreStatusUpdated(VarMap)), this, SLOT(updateFile(VarMap)), Qt::QueuedConnection);
290 connect(this, SIGNAL(coreMoved(VarMap)), this, SLOT(remFile(VarMap)), Qt::QueuedConnection);
291 connect(this, SIGNAL(coreMoved(VarMap)), this, SLOT(addFile(VarMap)), Qt::QueuedConnection);
292
293 connect(d->deleteShortcut, SIGNAL(activated()), this, SLOT(requestDelete()));
294 connect(treeView_TARGET, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenu(QPoint)));
295 connect(treeView_TARGET->header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderMenu(QPoint)));
296 connect(d->queue_model, SIGNAL(needExpand(QModelIndex)), treeView_TARGET, SLOT(expand(QModelIndex)));
297 connect(d->queue_model, SIGNAL(rowRemoved(QModelIndex)), this, SLOT(slotCollapseRow(QModelIndex)));
298 connect(d->queue_model, SIGNAL(updateStats(quint64,quint64)), this, SLOT(slotUpdateStats(quint64,quint64)));
299 connect(pushButton_EXPAND, SIGNAL(clicked()), treeView_TARGET, SLOT(expandAll()));
300 connect(pushButton_COLLAPSE, SIGNAL(clicked()), treeView_TARGET, SLOT(collapseAll()));
301
302 d->menu = new Menu();
303
304 setAttribute(Qt::WA_DeleteOnClose);
305
306 load();
307
308 loadList();
309
310 treeView_TARGET->expandAll();
311
312 ArenaWidget::setState( ArenaWidget::Flags(ArenaWidget::state() | ArenaWidget::Singleton | ArenaWidget::Hidden) );
313 }
314
load()315 void DownloadQueue::load(){
316 treeView_TARGET->header()->restoreState(WVGET(WS_DQUEUE_STATE, QByteArray()).toByteArray());
317 treeView_TARGET->setSortingEnabled(true);
318 }
319
save()320 void DownloadQueue::save(){
321 WVSET(WS_DQUEUE_STATE, treeView_TARGET->header()->saveState());
322 }
323
getParams(DownloadQueue::VarMap & params,const QueueItem * item)324 void DownloadQueue::getParams(DownloadQueue::VarMap ¶ms, const QueueItem *item){
325 QString nick = "";
326 QMap<QString, QString> source;
327 int online = 0;
328
329 if (!item)
330 return;
331
332 params["FNAME"] = _q(item->getTargetFileName());
333 params["PATH"] = _q(Util::getFilePath(item->getTarget()));
334 params["TARGET"] = _q(item->getTarget());
335
336 params["USERS"] = QString("");
337
338 QStringList user_list;
339
340 QueueItem::SourceConstIter it = item->getSources().begin();
341
342 for (; it != item->getSources().end(); ++it){
343 HintedUser usr = it->getUser();
344 const dcpp::CID &cid = usr.user->getCID();
345
346 if (usr.user->isOnline())
347 ++online;
348
349 nick = WulforUtil::getInstance()->getNicks(cid, _q(usr.hint));
350
351 if (!nick.isEmpty()){
352 source[nick] = _q(cid.toBase32());
353 user_list.push_back(nick);
354 }
355 }
356
357 if (!user_list.isEmpty())
358 params["USERS"] = user_list.join(", ");
359 else
360 params["USERS"] = tr("No users...");
361
362 Q_D(DownloadQueue);
363
364 d->sources[_q(item->getTarget())] = source;
365
366 if (item->isWaiting())
367 params["STATUS"] = tr("%1 of %2 user(s) online").arg(online).arg(item->getSources().size());
368 else
369 params["STATUS"] = tr("Running...");
370
371 params["ESIZE"] = (qlonglong)item->getSize();
372 params["DOWN"] = (qlonglong)item->getDownloadedBytes();
373 params["PRIO"] = static_cast<int>(item->getPriority());
374
375 source.clear();
376
377 params["ERRORS"] = QString("");
378
379 it = item->getBadSources().begin();
380
381 for (; it != item->getBadSources().end(); ++it){
382 QString errors = params["ERRORS"].toString();
383 UserPtr usr = it->getUser();
384
385 nick = WulforUtil::getInstance()->getNicks(usr->getCID());
386 source[nick] = _q(usr->getCID().toBase32());
387
388 if (!it->isSet(QueueItem::Source::FLAG_REMOVED)){
389 if (!errors.isEmpty())
390 errors += ", ";
391
392 errors += nick + " (";
393
394 if (it->isSet(QueueItem::Source::FLAG_FILE_NOT_AVAILABLE))
395 errors += tr("File not available");
396 else if (it->isSet(QueueItem::Source::FLAG_PASSIVE))
397 errors += tr("Passive user");
398 else if (it->isSet(QueueItem::Source::FLAG_CRC_FAILED))
399 errors += tr("Checksum mismatch");
400 else if (it->isSet(QueueItem::Source::FLAG_BAD_TREE))
401 errors += tr("Full tree does not match TTH root");
402 else if (it->isSet(QueueItem::Source::FLAG_SLOW_SOURCE))
403 errors += tr("Source too slow");
404 else if (it->isSet(QueueItem::Source::FLAG_NO_TTHF))
405 errors += tr("Remote client does not fully support TTH - cannot download");
406
407 params["ERRORS"] = errors + ")";
408 }
409 }
410
411 if (params["ERRORS"].toString().isEmpty())
412 params["ERRORS"] = tr("No errors");
413
414 d->badSources[_q(item->getTarget())] = source;
415
416 params["ADDED"] = _q(Util::formatTime("%Y-%m-%d %H:%M", item->getAdded()));
417 params["TTH"] = _q(item->getTTH().toBase32());
418
419 }
420
getSources()421 QStringList DownloadQueue::getSources(){
422 Q_D(DownloadQueue);
423
424 auto s_it = d->sources.begin();
425 QStringList ret;
426
427 for (; s_it != d->sources.end(); ++s_it){
428 QString target = s_it.key();
429 QString users;
430 auto it = s_it.value().begin();
431
432 for (; it != s_it.value().end(); ++it){
433 users += it.key() + "(" + it.value() + ") ";
434 }
435
436 ret.push_back(target + "::" + users);
437 }
438
439 return ret;
440 }
441
removeTarget(const QString & target)442 void DownloadQueue::removeTarget(const QString &target){
443 QueueManager *QM = QueueManager::getInstance();
444
445 try {
446 QM->remove(target.toStdString());
447 }
448 catch (const Exception&){}
449 }
450
removeSource(const QString & cid,const QString & target)451 void DownloadQueue::removeSource(const QString &cid, const QString &target){
452 QueueManager *QM = QueueManager::getInstance();
453 Q_D(DownloadQueue);
454
455 if (d->sources.contains(target) && !cid.isEmpty()){
456 UserPtr user = ClientManager::getInstance()->findUser(CID(cid.toStdString()));
457
458 if (user){
459 try {
460 QM->removeSource(user, QueueItem::Source::FLAG_REMOVED);
461 }
462 catch (const Exception&){}
463 }
464 }
465 }
466
loadList()467 void DownloadQueue::loadList(){
468 VarMap params;
469
470 const QueueItem::StringMap &ll = QueueManager::getInstance()->lockQueue();
471
472 for (auto it = ll.begin(); it != ll.end(); ++it){
473 getParams(params, it->second);
474
475 addFile(params);
476 }
477
478 QueueManager::getInstance()->unlockQueue();
479
480 Q_D(DownloadQueue);
481
482 d->queue_model->sort();
483 }
484
addFile(const DownloadQueue::VarMap & map)485 void DownloadQueue::addFile(const DownloadQueue::VarMap &map){
486 Q_D(DownloadQueue);
487
488 d->queue_model->addItem(map);
489 }
490
remFile(const VarMap & map)491 void DownloadQueue::remFile(const VarMap &map){
492 Q_D(DownloadQueue);
493
494 if (d->queue_model->remItem(map)){
495 auto it = d->sources.find(map["TARGET"].toString());
496
497 if (it != d->sources.end())
498 d->sources.erase(it);
499
500 it = d->badSources.find(map["TARGET"].toString());
501
502 if (it != d->badSources.end())
503 d->badSources.erase(it);
504 }
505 }
506
updateFile(const DownloadQueue::VarMap & map)507 void DownloadQueue::updateFile(const DownloadQueue::VarMap &map){
508 Q_D(DownloadQueue);
509
510 d->queue_model->updItem(map);
511 }
512
getCID(const VarMap & map)513 QString DownloadQueue::getCID(const VarMap &map){
514 if (map.size() < 1)
515 return "";
516
517 auto it = map.constBegin();
518
519 return (it.value()).toString();
520 }
521
getChilds(DownloadQueueItem * i,QList<DownloadQueueItem * > & list)522 void DownloadQueue::getChilds(DownloadQueueItem *i, QList<DownloadQueueItem *> &list){
523 if (!i)
524 return;
525
526 if (!i->dir && !list.contains(i)){
527 list.push_back(i);
528
529 return;
530 }
531
532 if (i->childCount() < 1)
533 return;
534
535 for (const auto &ii : i->childItems)
536 getChilds(ii, list);
537 }
538
getItems(const QModelIndexList & list,QList<DownloadQueueItem * > & items)539 void DownloadQueue::getItems(const QModelIndexList &list, QList<DownloadQueueItem*> &items){
540 items.clear();
541
542 if (list.isEmpty())
543 return;
544
545 for (const auto &i : list){
546 DownloadQueueItem *item = reinterpret_cast<DownloadQueueItem*>(i.internalPointer());
547
548 getChilds(item, items);
549 }
550 }
551
slotContextMenu(const QPoint &)552 void DownloadQueue::slotContextMenu(const QPoint &){
553 QModelIndexList list = treeView_TARGET->selectionModel()->selectedRows(0);
554 QList<DownloadQueueItem*> items;
555
556 if (list.isEmpty())
557 return;
558
559 getItems(list, items);
560
561 if (items.isEmpty())
562 return;
563
564 DownloadQueueItem *item = reinterpret_cast<DownloadQueueItem*>(items.at(0));
565
566 QString target = item->data(COLUMN_DOWNLOADQUEUE_PATH).toString() + item->data(COLUMN_DOWNLOADQUEUE_NAME).toString();
567
568 if (target.isEmpty())
569 return;
570
571 Q_D(DownloadQueue);
572
573 Menu::Action act = d->menu->exec(d->sources, target, items.size() > 1);
574 QueueManager *QM = QueueManager::getInstance();
575 QVariant arg = d->menu->getArg();
576 VarMap rmap;
577
578 /** Now re-read selected indexes and remove broken items */
579 list = treeView_TARGET->selectionModel()->selectedRows(0);
580
581 getItems(list, items);
582
583 if (items.isEmpty())
584 return;
585
586 switch (act){
587 case Menu::Alternates:
588 {
589 SearchFrame *sf = ArenaWidgetFactory().create<SearchFrame>();
590
591 for (const auto &i : items)
592 sf->searchAlternates(i->data(COLUMN_DOWNLOADQUEUE_TTH).toString());
593
594 break;
595 }
596 case Menu::Magnet:
597 {
598 QString magnet = "";
599
600 for (const auto &i : items)
601 magnet += WulforUtil::getInstance()->makeMagnet(
602 i->data(COLUMN_DOWNLOADQUEUE_NAME).toString(),
603 i->data(COLUMN_DOWNLOADQUEUE_ESIZE).toLongLong(),
604 i->data(COLUMN_DOWNLOADQUEUE_TTH).toString()) + "\n";
605
606 if (!magnet.isEmpty())
607 qApp->clipboard()->setText(magnet, QClipboard::Clipboard);
608
609 break;
610 }
611 case Menu::MagnetWeb:
612 {
613 QString magnet = "";
614
615 for (const auto &i : items){
616 magnet += "[magnet=\"" +
617 WulforUtil::getInstance()->makeMagnet(
618 i->data(COLUMN_DOWNLOADQUEUE_NAME).toString(),
619 i->data(COLUMN_DOWNLOADQUEUE_ESIZE).toLongLong(),
620 i->data(COLUMN_DOWNLOADQUEUE_TTH).toString()) +
621 "\"]"+i->data(COLUMN_DOWNLOADQUEUE_NAME).toString()+"[/magnet]\n";
622 }
623
624 if (!magnet.isEmpty())
625 qApp->clipboard()->setText(magnet, QClipboard::Clipboard);
626
627 break;
628 }
629 case Menu::MagnetInfo:
630 {
631 QString magnet = "";
632
633 for (const auto &i : items){
634 magnet = WulforUtil::getInstance()->makeMagnet(
635 i->data(COLUMN_DOWNLOADQUEUE_NAME).toString(),
636 i->data(COLUMN_DOWNLOADQUEUE_ESIZE).toLongLong(),
637 i->data(COLUMN_DOWNLOADQUEUE_TTH).toString()) + "\n";
638
639 if (!magnet.isEmpty()){
640 Magnet m(this);
641 m.setLink(magnet);
642 m.exec();
643 }
644 }
645
646 break;
647 }
648 case Menu::RenameMove:
649 {
650 for (const auto &i : items){
651 QString target = i->data(COLUMN_DOWNLOADQUEUE_PATH).toString() +
652 i->data(COLUMN_DOWNLOADQUEUE_NAME).toString();
653 QString new_target = QFileDialog::getSaveFileName(this, tr("Choose filename"), target, tr("All files (*.*)"));
654
655 if (!new_target.isEmpty() && new_target != target){
656 new_target = QDir::toNativeSeparators(new_target);
657 try {
658 QM->move(target.toStdString(), new_target.toStdString());
659 }
660 catch (const Exception &){}
661 }
662 }
663
664 break;
665 }
666 case Menu::SetPriority:
667 {
668 for (const auto &i : items){
669 QString target = i->data(COLUMN_DOWNLOADQUEUE_PATH).toString() + i->data(COLUMN_DOWNLOADQUEUE_NAME).toString();
670
671 try {
672 QM->setPriority(target.toStdString(), static_cast<QueueItem::Priority>(arg.toInt()));
673 }
674 catch (const Exception&) {}
675 }
676
677 break;
678 }
679 case Menu::Browse:
680 {
681 rmap = arg.toMap();
682 QString cid = getCID(rmap);
683
684 if (d->sources.contains(target) && !cid.isEmpty()){
685 UserPtr user = ClientManager::getInstance()->findUser(CID(cid.toStdString()));
686
687 if (user){
688 try {
689 QM->addList(HintedUser(user, ""), QueueItem::FLAG_CLIENT_VIEW, "");
690 }
691 catch (const Exception&){}
692 }
693 }
694
695 break;
696 }
697 case Menu::SendPM:
698 {
699 rmap = arg.toMap();
700 auto it = rmap.constBegin();
701 dcpp::CID cid(_tq(getCID(rmap)));
702 QString nick = ((++it).key());
703 QList<QObject*> list = HubManager::getInstance()->getHubs();
704
705 for (const auto &obj : list){
706 HubFrame *fr = qobject_cast<HubFrame*>(obj);
707
708 if (!fr)
709 continue;
710
711 if (fr->hasCID(cid, nick)){
712 fr->createPMWindow(cid);
713
714 break;
715 }
716 }
717
718 break;
719 }
720 case Menu::RemoveSource:
721 {
722 rmap = arg.toMap();
723 QString cid = getCID(rmap);
724
725 if (d->sources.contains(target) && !cid.isEmpty()){
726 UserPtr user = ClientManager::getInstance()->findUser(CID(cid.toStdString()));
727
728 if (user){
729 try {
730 QM->removeSource(target.toStdString(), user, QueueItem::Source::FLAG_REMOVED);
731 }
732 catch (const Exception&){}
733 }
734 }
735
736 break;
737 }
738 case Menu::RemoveUser:
739 {
740 rmap = arg.toMap();
741 QString cid = getCID(rmap);
742
743 if (d->sources.contains(target) && !cid.isEmpty()){
744 UserPtr user = ClientManager::getInstance()->findUser(CID(cid.toStdString()));
745
746 if (user){
747 try {
748 QM->removeSource(user, QueueItem::Source::FLAG_REMOVED);
749 }
750 catch (const Exception&){}
751 }
752 }
753
754 break;
755 }
756 case Menu::Remove:
757 {
758 for (const auto &i : items){
759 QString target = i->data(COLUMN_DOWNLOADQUEUE_PATH).toString() + i->data(COLUMN_DOWNLOADQUEUE_NAME).toString();
760
761 try {
762 QM->remove(target.toStdString());
763 }
764 catch (const Exception &){}
765 }
766
767 break;
768 }
769 default:
770 break;
771 }
772 }
773
slotCollapseRow(const QModelIndex & row)774 void DownloadQueue::slotCollapseRow(const QModelIndex &row){
775 if (row.isValid())
776 treeView_TARGET->collapse(row);
777 }
778
slotHeaderMenu(const QPoint &)779 void DownloadQueue::slotHeaderMenu(const QPoint&){
780 WulforUtil::headerMenu(treeView_TARGET);
781 }
782
slotUpdateStats(quint64 files,quint64 size)783 void DownloadQueue::slotUpdateStats(quint64 files, quint64 size){
784 if (static_cast<qint64>(size) < 0)
785 size = 0;
786
787 if (files == size && size == 0)
788 label_STATS->hide();
789
790 if (label_STATS->isHidden())
791 label_STATS->show();
792
793 label_STATS->setText(tr("Total files: <b>%1</b> Total size: <b>%2</b>").arg(files).arg(WulforUtil::formatBytes(size)));
794 }
795
slotSettingsChanged(const QString & key,const QString & value)796 void DownloadQueue::slotSettingsChanged(const QString &key, const QString &value){
797 if (key == WS_TRANSLATION_FILE)
798 retranslateUi(this);
799 }
800
on(QueueManagerListener::Added,QueueItem * item)801 void DownloadQueue::on(QueueManagerListener::Added, QueueItem *item) noexcept{
802 VarMap params;
803 getParams(params, item);
804
805 emit coreAdded(params);
806 emit added(_q(item->getTargetFileName()));
807 }
808
on(QueueManagerListener::Moved,QueueItem * item,const std::string & oldTarget)809 void DownloadQueue::on(QueueManagerListener::Moved, QueueItem *item, const std::string &oldTarget) noexcept{
810 VarMap params;
811 getParams(params, item);
812
813 emit coreMoved(params);
814 emit moved(_q(oldTarget), _q(item->getTargetFileName()));
815 }
816
on(QueueManagerListener::Removed,QueueItem * item)817 void DownloadQueue::on(QueueManagerListener::Removed, QueueItem *item) noexcept{
818 VarMap params;
819 getParams(params, item);
820
821 emit coreRemoved(params);
822 emit removed(_q(item->getTargetFileName()));
823 }
824
on(QueueManagerListener::SourcesUpdated,QueueItem * item)825 void DownloadQueue::on(QueueManagerListener::SourcesUpdated, QueueItem *item) noexcept{
826 VarMap params;
827 getParams(params, item);
828
829 emit coreSourcesUpdated(params);
830 }
831
on(QueueManagerListener::StatusUpdated,QueueItem * item)832 void DownloadQueue::on(QueueManagerListener::StatusUpdated, QueueItem *item) noexcept{
833 VarMap params;
834 getParams(params, item);
835
836 emit coreStatusUpdated(params);
837 }
838