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 "FavoriteUsers.h"
11 #include "WulforUtil.h"
12 #include "FavoriteUsersModel.h"
13 
14 #include <QMenu>
15 #include <QInputDialog>
16 #include <QKeyEvent>
17 #include <QHeaderView>
18 #include <QItemSelectionModel>
19 
20 #include "dcpp/ClientManager.h"
21 #include "dcpp/QueueManager.h"
22 #include "dcpp/User.h"
23 #include "dcpp/CID.h"
24 #include "dcpp/Util.h"
25 
26 
27 using namespace dcpp;
28 
FavoriteUsers(QWidget * parent)29 FavoriteUsers::FavoriteUsers(QWidget *parent) :
30     QWidget(parent)
31 {
32     setupUi(this);
33 
34     setUnload(false);
35 
36     model = new FavoriteUsersModel(this);
37 
38     treeView->setContextMenuPolicy(Qt::CustomContextMenu);
39     treeView->installEventFilter(this);
40     treeView->setModel(model);
41     treeView->header()->setContextMenuPolicy(Qt::CustomContextMenu);
42     treeView->header()->restoreState(WVGET(WS_FAVUSERS_STATE, QByteArray()).toByteArray());
43     treeView->setSortingEnabled(true);
44 
45     connect(treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenu()));
46     connect(treeView->header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderMenu()));
47     connect(checkBox_AUTOGRANT, SIGNAL(toggled(bool)), this, SLOT(slotAutoGrant(bool)));
48 
49     connect(this, SIGNAL(coreUserAdded(VarMap)),                this, SLOT(addUser(VarMap)), Qt::QueuedConnection);
50     connect(this, SIGNAL(coreUserRemoved(QString)),             this, SLOT(remUser(QString)), Qt::QueuedConnection);
51     connect(this, SIGNAL(coreStatusChanged(QString,QString)),   this, SLOT(updateUser(QString,QString)), Qt::QueuedConnection);
52 
53     WulforSettings *WS = WulforSettings::getInstance();
54     connect(WS, SIGNAL(strValueChanged(QString,QString)), this, SLOT(slotSettingsChanged(QString,QString)));
55 
56     FavoriteManager::FavoriteMap ul = FavoriteManager::getInstance()->getFavoriteUsers();
57     VarMap params;
58 
59     for (auto &i : ul) {
60         dcpp::FavoriteUser &u = i.second;
61 
62         if (WBGET(WB_FAVUSERS_AUTOGRANT)){
63             u.setFlag(FavoriteUser::FLAG_GRANTSLOT);
64             FavoriteManager::getInstance()->setAutoGrant(u.getUser(), true);
65         }
66 
67         getParams(params, u);
68         addUser(params);
69     }
70 
71     checkBox_AUTOGRANT->setChecked(WBGET(WB_FAVUSERS_AUTOGRANT));
72 
73     FavoriteManager::getInstance()->addListener(this);
74 
75     ArenaWidget::setState( ArenaWidget::Flags(ArenaWidget::state() | ArenaWidget::Singleton | ArenaWidget::Hidden) );
76 }
77 
~FavoriteUsers()78 FavoriteUsers::~FavoriteUsers(){
79     WVSET(WS_FAVUSERS_STATE, treeView->header()->saveState());
80 
81     FavoriteManager::getInstance()->removeListener(this);
82 
83     delete model;
84 }
85 
closeEvent(QCloseEvent * e)86 void FavoriteUsers::closeEvent(QCloseEvent *e){
87     isUnload()? e->accept() : e->ignore();
88 }
89 
eventFilter(QObject * obj,QEvent * e)90 bool FavoriteUsers::eventFilter(QObject *obj, QEvent *e){
91     if (e->type() == QEvent::KeyRelease){
92         QKeyEvent *k_e = reinterpret_cast<QKeyEvent*>(e);
93 
94         if (k_e->key() == Qt::Key_Delete){
95             if (treeView == reinterpret_cast<QTreeView*>(obj)){
96                 QModelIndexList indexes = treeView->selectionModel()->selectedRows(0);
97                 QList<FavoriteUserItem*> items;
98 
99                 for (const auto &i : indexes)
100                     items.push_back(reinterpret_cast<FavoriteUserItem*>(i.internalPointer()));
101 
102                 for (const auto &i : items)
103                     handleRemove(i->cid);
104 
105                 return true;
106             }
107         }
108     }
109 
110     return QWidget::eventFilter(obj, e);
111 }
112 
getParams(VarMap & params,const FavoriteUser & user)113 void FavoriteUsers::getParams(VarMap &params, const FavoriteUser &user){
114     const UserPtr &u = user.getUser();
115 
116     params["CID"]   = _q(u->getCID().toBase32());
117     params["NICK"]  = _q(user.getNick());
118     params["HUB"]   = u->isOnline()? (WulforUtil::getInstance()->getHubNames(u)) : _q(user.getUrl());
119     params["SEEN"]  = u->isOnline()? tr("Online") : _q(Util::formatTime("%Y-%m-%d %H:%M", user.getLastSeen()));
120     params["DESC"]  = _q(user.getDescription());
121     params["SLOT"]  = user.isSet(FavoriteUser::FLAG_GRANTSLOT);
122 }
123 
addUserToFav(const QString & id)124 bool FavoriteUsers::addUserToFav(const QString &id){
125     if (id.isEmpty())
126         return false;
127 
128     string cid = id.toStdString();
129 
130     UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
131 
132     if (user){
133         if (user != ClientManager::getInstance()->getMe() && !FavoriteManager::getInstance()->isFavoriteUser(user))
134             FavoriteManager::getInstance()->addFavoriteUser(user);
135     }
136 
137     return true;
138 }
139 
remUserFromFav(const QString & id)140 bool FavoriteUsers::remUserFromFav(const QString &id){
141     if (id.isEmpty())
142         return false;
143 
144     string cid = id.toStdString();
145 
146     UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
147 
148     if (user){
149         if (user != ClientManager::getInstance()->getMe() && FavoriteManager::getInstance()->isFavoriteUser(user))
150             FavoriteManager::getInstance()->removeFavoriteUser(user);
151     }
152 
153     return true;
154 }
155 
getUsers() const156 QStringList FavoriteUsers::getUsers() const {
157     return model->getUsers();
158 }
159 
addUser(const VarMap & params)160 void FavoriteUsers::addUser(const VarMap &params){
161     model->addUser(params);
162 }
163 
updateUser(const QString & _cid,const QString & stat)164 void FavoriteUsers::updateUser(const QString &_cid, const QString &stat){
165     dcpp::CID cid(_tq(_cid));
166     const dcpp::UserPtr &user = ClientManager::getInstance()->findUser(cid);
167 
168     QString userUrl = user ? _q(FavoriteManager::getInstance()->getUserURL(user)) : QString();
169     model->updateUserStatus(_cid, stat,
170         (user && user->isOnline()) ? (WulforUtil::getInstance()->getHubNames(user)) : userUrl);
171 }
172 
remUser(const QString & cid)173 void FavoriteUsers::remUser(const QString &cid){
174     model->removeUser(cid);
175 }
176 
handleRemove(const QString & _cid)177 void FavoriteUsers::handleRemove(const QString & _cid){
178     dcpp::CID cid(_tq(_cid));
179     const dcpp::UserPtr &user = ClientManager::getInstance()->findUser(cid);
180 
181     if (user)
182         FavoriteManager::getInstance()->removeFavoriteUser(user);
183 }
184 
handleDesc(const QString & _cid)185 void FavoriteUsers::handleDesc(const QString & _cid){
186     FavoriteUserItem *item = model->itemForCID(_cid);
187     static QString old = "";
188 
189     if (!item)
190         return;
191 
192     dcpp::CID cid(_tq(_cid));
193     const dcpp::UserPtr &user = ClientManager::getInstance()->findUser(cid);
194 
195     if (user){
196         QString desc = QInputDialog::getText(this, item->data(COLUMN_USER_NICK).toString(), tr("Description"), QLineEdit::Normal, old);
197 
198         if (!desc.isEmpty()){
199             old = desc;
200             item->updateColumn(COLUMN_USER_DESC, desc);
201             FavoriteManager::getInstance()->setUserDescription(user, _tq(desc));
202         }
203     }
204 }
205 
getFileList(const VarMap & params)206 void FavoriteUsers::getFileList(const VarMap &params){
207     string cid  = params["CID"].toString().toStdString();
208     string hub  = params["HUB"].toString().toStdString();
209 
210     if (cid.empty())
211         return;
212 
213     UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
214     if (user){
215         try {
216             QueueManager::getInstance()->addList(HintedUser(user, hub),  QueueItem::FLAG_CLIENT_VIEW, "");
217         } catch(const Exception&) {
218             // ...
219         }
220     }
221 }
222 
handleBrowseShare(const QString & cid)223 void FavoriteUsers::handleBrowseShare(const QString &cid){
224     FavoriteManager::FavoriteMap ul = FavoriteManager::getInstance()->getFavoriteUsers();
225 
226     auto i = ul.find(CID(_tq(cid)));
227     if (i != ul.end()){
228         dcpp::FavoriteUser &user = i->second;
229 
230         VarMap params;
231         getParams(params, user);
232         getFileList(params);
233     }
234 }
235 
handleGrant(const QString & cid)236 void FavoriteUsers::handleGrant(const QString &cid){
237     FavoriteManager::FavoriteMap ul = FavoriteManager::getInstance()->getFavoriteUsers();
238 
239     auto i = ul.find(CID(_tq(cid)));
240     if (i != ul.end()){
241         dcpp::FavoriteUser &u = i->second;
242 
243         if (_q(u.getUser()->getCID().toBase32()) == cid){
244             if (u.isSet(FavoriteUser::FLAG_GRANTSLOT)){
245                 u.unsetFlag(FavoriteUser::FLAG_GRANTSLOT);
246                 FavoriteManager::getInstance()->setAutoGrant(u.getUser(), false);
247             }
248             else {
249                 u.setFlag(FavoriteUser::FLAG_GRANTSLOT);
250                 FavoriteManager::getInstance()->setAutoGrant(u.getUser(), true);
251             }
252         }
253     }
254 }
255 
slotContextMenu()256 void FavoriteUsers::slotContextMenu(){
257     QModelIndexList indexes = treeView->selectionModel()->selectedRows(0);
258     QList<FavoriteUserItem*> items;
259 
260     for (const auto &i : indexes)
261         items.push_back(reinterpret_cast<FavoriteUserItem*>(i.internalPointer()));
262 
263     if (items.size() < 1)
264         return;
265 
266     QMenu *menu = new QMenu(this);
267     menu->deleteLater();
268 
269     QAction *remove = new QAction(tr("Remove"), menu);
270     remove->setIcon(WICON(WulforUtil::eiEDITDELETE));
271 
272     QAction *desc   = new QAction(tr("Description"), menu);
273     desc->setIcon(WICON(WulforUtil::eiEDIT));
274 
275     QAction *grant  = new QAction(tr("Grant/Remove slot"), menu);
276     grant->setIcon(WICON(WulforUtil::eiBALL_GREEN));
277 
278     QAction *browse  = new QAction(tr("Browse Files"), menu);
279     browse->setIcon(WICON(WulforUtil::eiFOLDER_BLUE));
280 
281     menu->addActions(QList<QAction*>() << browse << desc << grant << remove);
282 
283     QAction *ret = menu->exec(QCursor::pos());
284 
285     if (!ret)
286         return;
287 
288     if (ret == remove){
289         for (const auto &i : items)
290             handleRemove(i->cid);
291     }
292     else if (ret == grant){
293         for (const auto &i : items)
294             handleGrant(i->cid);
295     }
296     else if(ret == browse){
297         for (const auto &i : items)
298             handleBrowseShare(i->cid);
299     }
300     else {
301         for (const auto &i : items)
302             handleDesc(i->cid);
303     }
304 }
305 
slotHeaderMenu()306 void FavoriteUsers::slotHeaderMenu(){
307     WulforUtil::headerMenu(treeView);
308 }
309 
slotSettingsChanged(const QString & key,const QString &)310 void FavoriteUsers::slotSettingsChanged(const QString &key, const QString &){
311     if (key == WS_TRANSLATION_FILE)
312         retranslateUi(this);
313 }
314 
on(UserAdded,const FavoriteUser & aUser)315 void FavoriteUsers::on(UserAdded, const FavoriteUser& aUser) noexcept {
316     if (WBGET(WB_FAVUSERS_AUTOGRANT))
317         FavoriteManager::getInstance()->setAutoGrant(aUser.getUser(), true);
318 
319     VarMap params;
320 
321     getParams(params, aUser);
322 
323     emit coreUserAdded(params);
324 }
325 
on(UserRemoved,const FavoriteUser & aUser)326 void FavoriteUsers::on(UserRemoved, const FavoriteUser& aUser) noexcept {
327     emit coreUserRemoved(_q(aUser.getUser()->getCID().toBase32()));
328 }
329 
on(StatusChanged,const FavoriteUser & u)330 void FavoriteUsers::on(StatusChanged, const FavoriteUser& u) noexcept{
331     emit coreStatusChanged(_q(u.getUser()->getCID().toBase32()), u.getUser()->isOnline()?
332                                                                     tr("Online")
333                                                                     :
334                                _q(Util::formatTime("%Y-%m-%d %H:%M", FavoriteManager::getInstance()->getLastSeen(u.getUser()))));
335 
336 }
337