1 /*
2     Copyright © 2019 by The qTox Project Contributors
3 
4     This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6     qTox is libre software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10 
11     qTox is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with qTox.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "contentdialogmanager.h"
21 
22 #include "src/friendlist.h"
23 #include "src/grouplist.h"
24 #include "src/model/friend.h"
25 #include "src/model/group.h"
26 #include "src/widget/friendwidget.h"
27 #include "src/widget/groupwidget.h"
28 
29 #include <tuple>
30 
31 namespace {
removeDialog(ContentDialog * dialog,QHash<const ContactId &,ContentDialog * > & dialogs)32 void removeDialog(ContentDialog* dialog, QHash<const ContactId&, ContentDialog*>& dialogs)
33 {
34     for (auto it = dialogs.begin(); it != dialogs.end();) {
35         if (*it == dialog) {
36             it = dialogs.erase(it);
37         } else {
38             ++it;
39         }
40     }
41 }
42 } // namespace
43 
44 ContentDialogManager* ContentDialogManager::instance;
45 
current()46 ContentDialog* ContentDialogManager::current()
47 {
48     return currentDialog;
49 }
50 
contactWidgetExists(const ContactId & contactId)51 bool ContentDialogManager::contactWidgetExists(const ContactId& contactId)
52 {
53     const auto dialog = contactDialogs.value(contactId, nullptr);
54     if (dialog == nullptr) {
55         return false;
56     }
57 
58     return dialog->hasContact(contactId);
59 }
60 
addFriendToDialog(ContentDialog * dialog,std::shared_ptr<FriendChatroom> chatroom,GenericChatForm * form)61 FriendWidget* ContentDialogManager::addFriendToDialog(ContentDialog* dialog,
62                                                       std::shared_ptr<FriendChatroom> chatroom,
63                                                       GenericChatForm* form)
64 {
65     auto friendWidget = dialog->addFriend(chatroom, form);
66     const auto& friendPk = friendWidget->getFriend()->getPublicKey();
67 
68     ContentDialog* lastDialog = getFriendDialog(friendPk);
69     if (lastDialog) {
70         lastDialog->removeFriend(friendPk);
71     }
72 
73     contactDialogs[friendPk] = dialog;
74     return friendWidget;
75 }
76 
addGroupToDialog(ContentDialog * dialog,std::shared_ptr<GroupChatroom> chatroom,GenericChatForm * form)77 GroupWidget* ContentDialogManager::addGroupToDialog(ContentDialog* dialog,
78                                                     std::shared_ptr<GroupChatroom> chatroom,
79                                                     GenericChatForm* form)
80 {
81     auto groupWidget = dialog->addGroup(chatroom, form);
82     const auto& groupId = groupWidget->getGroup()->getPersistentId();
83 
84     ContentDialog* lastDialog = getGroupDialog(groupId);
85     if (lastDialog) {
86         lastDialog->removeGroup(groupId);
87     }
88 
89     contactDialogs[groupId] = dialog;
90     return groupWidget;
91 }
92 
focusContact(const ContactId & contactId)93 void ContentDialogManager::focusContact(const ContactId& contactId)
94 {
95     auto dialog = focusDialog(contactId, contactDialogs);
96     if (dialog != nullptr) {
97         dialog->focusContact(contactId);
98     }
99 }
100 
101 /**
102  * @brief Focus the dialog if it exists.
103  * @param id User Id.
104  * @param list List with dialogs
105  * @return ContentDialog if found, nullptr otherwise
106  */
focusDialog(const ContactId & id,const QHash<const ContactId &,ContentDialog * > & list)107 ContentDialog* ContentDialogManager::focusDialog(const ContactId& id,
108                                                  const QHash<const ContactId&, ContentDialog*>& list)
109 {
110     auto iter = list.find(id);
111     if (iter == list.end()) {
112         return nullptr;
113     }
114 
115     ContentDialog* dialog = *iter;
116     if (dialog->windowState() & Qt::WindowMinimized) {
117         dialog->showNormal();
118     }
119 
120     dialog->raise();
121     dialog->activateWindow();
122     return dialog;
123 }
124 
updateFriendStatus(const ToxPk & friendPk)125 void ContentDialogManager::updateFriendStatus(const ToxPk& friendPk)
126 {
127     auto dialog = contactDialogs.value(friendPk);
128     if (dialog == nullptr) {
129         return;
130     }
131 
132     dialog->updateContactStatusLight(friendPk);
133     if (dialog->isContactActive(friendPk)) {
134         dialog->updateTitleAndStatusIcon();
135     }
136 
137     Friend* f = FriendList::findFriend(friendPk);
138     dialog->updateFriendStatus(friendPk, f->getStatus());
139 }
140 
updateGroupStatus(const GroupId & groupId)141 void ContentDialogManager::updateGroupStatus(const GroupId& groupId)
142 {
143     auto dialog = contactDialogs.value(groupId);
144     if (dialog == nullptr) {
145         return;
146     }
147 
148     dialog->updateContactStatusLight(groupId);
149     if (dialog->isContactActive(groupId)) {
150         dialog->updateTitleAndStatusIcon();
151     }
152 }
153 
isContactActive(const ContactId & contactId)154 bool ContentDialogManager::isContactActive(const ContactId& contactId)
155 {
156     const auto dialog = contactDialogs.value(contactId);
157     if (dialog == nullptr) {
158         return false;
159     }
160 
161     return dialog->isContactActive(contactId);
162 }
163 
getFriendDialog(const ToxPk & friendPk) const164 ContentDialog* ContentDialogManager::getFriendDialog(const ToxPk& friendPk) const
165 {
166     return contactDialogs.value(friendPk);
167 }
168 
getGroupDialog(const GroupId & groupId) const169 ContentDialog* ContentDialogManager::getGroupDialog(const GroupId& groupId) const
170 {
171     return contactDialogs.value(groupId);
172 }
173 
getInstance()174 ContentDialogManager* ContentDialogManager::getInstance()
175 {
176     if (instance == nullptr) {
177         instance = new ContentDialogManager();
178     }
179 
180     return instance;
181 }
182 
addContentDialog(ContentDialog & dialog)183 void ContentDialogManager::addContentDialog(ContentDialog& dialog)
184 {
185     currentDialog = &dialog;
186     connect(&dialog, &ContentDialog::willClose, this, &ContentDialogManager::onDialogClose);
187     connect(&dialog, &ContentDialog::activated, this, &ContentDialogManager::onDialogActivate);
188 }
189 
onDialogActivate()190 void ContentDialogManager::onDialogActivate()
191 {
192     ContentDialog* dialog = qobject_cast<ContentDialog*>(sender());
193     currentDialog = dialog;
194 }
195 
onDialogClose()196 void ContentDialogManager::onDialogClose()
197 {
198     ContentDialog* dialog = qobject_cast<ContentDialog*>(sender());
199     if (currentDialog == dialog) {
200         currentDialog = nullptr;
201     }
202 
203     removeDialog(dialog, contactDialogs);
204 }
205 
getFriendDialogs(const ToxPk & friendPk) const206 IDialogs* ContentDialogManager::getFriendDialogs(const ToxPk& friendPk) const
207 {
208     return getFriendDialog(friendPk);
209 }
210 
getGroupDialogs(const GroupId & groupId) const211 IDialogs* ContentDialogManager::getGroupDialogs(const GroupId& groupId) const
212 {
213     return getGroupDialog(groupId);
214 }
215