1 /* 2 Copyright © 2014-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 #ifndef WIDGET_H 21 #define WIDGET_H 22 23 #include "ui_mainwindow.h" 24 25 #include <QFileInfo> 26 #include <QMainWindow> 27 #include <QPointer> 28 #include <QSystemTrayIcon> 29 30 #include "genericchatitemwidget.h" 31 32 #include "src/audio/iaudiocontrol.h" 33 #include "src/audio/iaudiosink.h" 34 #include "src/core/core.h" 35 #include "src/core/groupid.h" 36 #include "src/core/toxfile.h" 37 #include "src/core/toxid.h" 38 #include "src/core/toxpk.h" 39 #include "src/model/friendmessagedispatcher.h" 40 #include "src/model/groupmessagedispatcher.h" 41 #if DESKTOP_NOTIFICATIONS 42 #include "src/platform/desktop_notifications/desktopnotify.h" 43 #endif 44 45 #define PIXELS_TO_ACT 7 46 47 namespace Ui { 48 class MainWindow; 49 } 50 51 class AddFriendForm; 52 class AlSink; 53 class Camera; 54 class ChatForm; 55 class CircleWidget; 56 class ContentDialog; 57 class ContentLayout; 58 class Core; 59 class FilesForm; 60 class Friend; 61 class FriendChatroom; 62 class FriendListWidget; 63 class FriendWidget; 64 class GenericChatroomWidget; 65 class Group; 66 class GroupChatForm; 67 class GroupChatroom; 68 class GroupInvite; 69 class GroupInviteForm; 70 class GroupWidget; 71 class MaskablePixmapWidget; 72 class ProfileForm; 73 class ProfileInfo; 74 class QActionGroup; 75 class QMenu; 76 class QPushButton; 77 class QSplitter; 78 class QTimer; 79 class SettingsWidget; 80 class SystemTrayIcon; 81 class VideoSurface; 82 class UpdateCheck; 83 class Settings; 84 class IChatLog; 85 class ChatHistory; 86 87 class Widget final : public QMainWindow 88 { 89 Q_OBJECT 90 91 private: 92 enum class ActiveToolMenuButton 93 { 94 AddButton, 95 GroupButton, 96 TransferButton, 97 SettingButton, 98 None, 99 }; 100 101 enum class DialogType 102 { 103 AddDialog, 104 TransferDialog, 105 SettingDialog, 106 ProfileDialog, 107 GroupDialog 108 }; 109 110 enum class FilterCriteria 111 { 112 All = 0, 113 Online, 114 Offline, 115 Friends, 116 Groups 117 }; 118 119 public: 120 explicit Widget(IAudioControl& audio, QWidget* parent = nullptr); 121 ~Widget() override; 122 void init(); 123 void setCentralWidget(QWidget* widget, const QString& widgetName); 124 QString getUsername(); 125 Camera* getCamera(); 126 static Widget* getInstance(IAudioControl* audio = nullptr); 127 void showUpdateDownloadProgress(); 128 void addFriendDialog(const Friend* frnd, ContentDialog* dialog); 129 void addGroupDialog(Group* group, ContentDialog* dialog); 130 bool newFriendMessageAlert(const ToxPk& friendId, const QString& text, bool sound = true, 131 bool file = false); 132 bool newGroupMessageAlert(const GroupId& groupId, const ToxPk& authorPk, const QString& message, 133 bool notify); 134 bool getIsWindowMinimized(); 135 void updateIcons(); 136 137 static QString fromDialogType(DialogType type); 138 ContentDialog* createContentDialog() const; 139 ContentLayout* createContentDialog(DialogType type) const; 140 141 static void confirmExecutableOpen(const QFileInfo& file); 142 143 void clearAllReceipts(); 144 145 void reloadTheme(); 146 static inline QIcon prepareIcon(QString path, int w = 0, int h = 0); 147 148 bool groupsVisible() const; 149 150 void resetIcon(); 151 152 public slots: 153 void onShowSettings(); 154 void onSeparateWindowClicked(bool separate); 155 void onSeparateWindowChanged(bool separate, bool clicked); 156 void setWindowTitle(const QString& title); 157 void forceShow(); 158 void onConnected(); 159 void onDisconnected(); 160 void onStatusSet(Status::Status status); 161 void onFailedToStartCore(); 162 void onBadProxyCore(); 163 void onSelfAvatarLoaded(const QPixmap& pic); 164 void setUsername(const QString& username); 165 void setStatusMessage(const QString& statusMessage); 166 void addFriend(uint32_t friendId, const ToxPk& friendPk); 167 void addFriendFailed(const ToxPk& userId, const QString& errorInfo = QString()); 168 void onFriendStatusChanged(int friendId, Status::Status status); 169 void onFriendStatusMessageChanged(int friendId, const QString& message); 170 void onFriendDisplayedNameChanged(const QString& displayed); 171 void onFriendUsernameChanged(int friendId, const QString& username); 172 void onFriendAliasChanged(const ToxPk& friendId, const QString& alias); 173 void onFriendMessageReceived(uint32_t friendnumber, const QString& message, bool isAction); 174 void onReceiptReceived(int friendId, ReceiptNum receipt); 175 void onFriendRequestReceived(const ToxPk& friendPk, const QString& message); 176 void onFileReceiveRequested(const ToxFile& file); 177 void onEmptyGroupCreated(uint32_t groupnumber, const GroupId& groupId, const QString& title); 178 void onGroupJoined(int groupNum, const GroupId& groupId); 179 void onGroupInviteReceived(const GroupInvite& inviteInfo); 180 void onGroupInviteAccepted(const GroupInvite& inviteInfo); 181 void onGroupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction); 182 void onGroupPeerlistChanged(uint32_t groupnumber); 183 void onGroupPeerNameChanged(uint32_t groupnumber, const ToxPk& peerPk, const QString& newName); 184 void onGroupTitleChanged(uint32_t groupnumber, const QString& author, const QString& title); 185 void titleChangedByUser(const QString& title); 186 void onGroupPeerAudioPlaying(int groupnumber, ToxPk peerPk); 187 void onGroupSendFailed(uint32_t groupnumber); 188 void onFriendTypingChanged(uint32_t friendnumber, bool isTyping); 189 void nextContact(); 190 void previousContact(); 191 void onFriendDialogShown(const Friend* f); 192 void onGroupDialogShown(Group* g); 193 void toggleFullscreen(); 194 void refreshPeerListsLocal(const QString& username); 195 void onUpdateAvailable(); 196 void onCoreChanged(Core& core); 197 198 signals: 199 void friendRequestAccepted(const ToxPk& friendPk); 200 void friendRequested(const ToxId& friendAddress, const QString& message); 201 void statusSet(Status::Status status); 202 void statusSelected(Status::Status status); 203 void usernameChanged(const QString& username); 204 void changeGroupTitle(uint32_t groupnumber, const QString& title); 205 void statusMessageChanged(const QString& statusMessage); 206 void resized(); 207 void windowStateChanged(Qt::WindowStates states); 208 209 private slots: 210 void onAddClicked(); 211 void onGroupClicked(); 212 void onTransferClicked(); 213 void showProfile(); 214 void openNewDialog(GenericChatroomWidget* widget); 215 void onChatroomWidgetClicked(GenericChatroomWidget* widget); 216 void onStatusMessageChanged(const QString& newStatusMessage); 217 void removeFriend(const ToxPk& friendId); 218 void copyFriendIdToClipboard(const ToxPk& friendId); 219 void removeGroup(const GroupId& groupId); 220 void setStatusOnline(); 221 void setStatusAway(); 222 void setStatusBusy(); 223 void onIconClick(QSystemTrayIcon::ActivationReason); 224 void onUserAwayCheck(); 225 void onEventIconTick(); 226 void onTryCreateTrayIcon(); 227 void onSetShowSystemTray(bool newValue); 228 void onSplitterMoved(int pos, int index); 229 void friendListContextMenu(const QPoint& pos); 230 void friendRequestsUpdate(); 231 void groupInvitesUpdate(); 232 void groupInvitesClear(); 233 void onDialogShown(GenericChatroomWidget* widget); 234 void outgoingNotification(); 235 void onCallEnd(); 236 void incomingNotification(uint32_t friendId); 237 void onRejectCall(uint32_t friendId); 238 void onStopNotification(); 239 void dispatchFile(ToxFile file); 240 void dispatchFileWithBool(ToxFile file, bool); 241 void dispatchFileSendFailed(uint32_t friendId, const QString& fileName); 242 void connectCircleWidget(CircleWidget& circleWidget); 243 void connectFriendWidget(FriendWidget& friendWidget); 244 void searchCircle(CircleWidget& circleWidget); 245 void updateFriendActivity(const Friend& frnd); 246 void registerContentDialog(ContentDialog& contentDialog) const; 247 248 private: 249 // QMainWindow overrides 250 bool eventFilter(QObject* obj, QEvent* event) final override; 251 bool event(QEvent* e) final override; 252 void closeEvent(QCloseEvent* event) final override; 253 void changeEvent(QEvent* event) final override; 254 void resizeEvent(QResizeEvent* event) final override; 255 void moveEvent(QMoveEvent* event) final override; 256 257 bool newMessageAlert(QWidget* currentWindow, bool isActive, bool sound = true, bool notify = true); 258 void setActiveToolMenuButton(ActiveToolMenuButton newActiveButton); 259 void hideMainForms(GenericChatroomWidget* chatroomWidget); 260 Group* createGroup(uint32_t groupnumber, const GroupId& groupId); 261 void removeFriend(Friend* f, bool fake = false); 262 void removeGroup(Group* g, bool fake = false); 263 void saveWindowGeometry(); 264 void saveSplitterGeometry(); 265 void cycleContacts(bool forward); 266 void searchContacts(); 267 void changeDisplayMode(); 268 void updateFilterText(); 269 FilterCriteria getFilterCriteria() const; 270 static bool filterGroups(FilterCriteria index); 271 static bool filterOnline(FilterCriteria index); 272 static bool filterOffline(FilterCriteria index); 273 void retranslateUi(); 274 void focusChatInput(); 275 void openDialog(GenericChatroomWidget* widget, bool newWindow); 276 void playNotificationSound(IAudioSink::Sound sound, bool loop = false); 277 void cleanupNotificationSound(); 278 279 private: 280 std::unique_ptr<QSystemTrayIcon> icon; 281 QMenu* trayMenu; 282 QAction* statusOnline; 283 QAction* statusAway; 284 QAction* statusBusy; 285 QAction* actionLogout; 286 QAction* actionQuit; 287 QAction* actionShow; 288 289 QMenu* filterMenu; 290 291 QActionGroup* filterGroup; 292 QAction* filterAllAction; 293 QAction* filterOnlineAction; 294 QAction* filterOfflineAction; 295 QAction* filterFriendsAction; 296 QAction* filterGroupsAction; 297 298 QActionGroup* filterDisplayGroup; 299 QAction* filterDisplayName; 300 QAction* filterDisplayActivity; 301 302 Ui::MainWindow* ui; 303 QSplitter* centralLayout; 304 QPoint dragPosition; 305 ContentLayout* contentLayout; 306 AddFriendForm* addFriendForm; 307 GroupInviteForm* groupInviteForm; 308 309 ProfileInfo* profileInfo; 310 ProfileForm* profileForm; 311 312 QPointer<SettingsWidget> settingsWidget; 313 std::unique_ptr<UpdateCheck> updateCheck; // ownership should be moved outside Widget once non-singleton 314 FilesForm* filesForm; 315 static Widget* instance; 316 GenericChatroomWidget* activeChatroomWidget; 317 FriendListWidget* contactListWidget; 318 MaskablePixmapWidget* profilePicture; 319 bool notify(QObject* receiver, QEvent* event); 320 bool autoAwayActive = false; 321 QTimer* timer; 322 bool eventFlag; 323 bool eventIcon; 324 bool wasMaximized = false; 325 QPushButton* friendRequestsButton; 326 QPushButton* groupInvitesButton; 327 unsigned int unreadGroupInvites; 328 int icon_size; 329 330 IAudioControl& audio; 331 std::unique_ptr<IAudioSink> audioNotification = nullptr; 332 Settings& settings; 333 334 QMap<ToxPk, FriendWidget*> friendWidgets; 335 // Shared pointer because qmap copies stuff all over the place 336 QMap<ToxPk, std::shared_ptr<FriendMessageDispatcher>> friendMessageDispatchers; 337 // Stop gap method of linking our friend messages back to a group id. 338 // Eventual goal is to have a notification manager that works on 339 // Messages hooked up to message dispatchers but we aren't there 340 // yet 341 QMap<ToxPk, QMetaObject::Connection> friendAlertConnections; 342 QMap<ToxPk, std::shared_ptr<ChatHistory>> friendChatLogs; 343 QMap<ToxPk, std::shared_ptr<FriendChatroom>> friendChatrooms; 344 QMap<ToxPk, ChatForm*> chatForms; 345 346 QMap<GroupId, GroupWidget*> groupWidgets; 347 QMap<GroupId, std::shared_ptr<GroupMessageDispatcher>> groupMessageDispatchers; 348 349 // Stop gap method of linking our group messages back to a group id. 350 // Eventual goal is to have a notification manager that works on 351 // Messages hooked up to message dispatchers but we aren't there 352 // yet 353 QMap<GroupId, QMetaObject::Connection> groupAlertConnections; 354 QMap<GroupId, std::shared_ptr<IChatLog>> groupChatLogs; 355 QMap<GroupId, std::shared_ptr<GroupChatroom>> groupChatrooms; 356 QMap<GroupId, QSharedPointer<GroupChatForm>> groupChatForms; 357 Core* core = nullptr; 358 359 360 MessageProcessor::SharedParams sharedMessageProcessorParams; 361 #if DESKTOP_NOTIFICATIONS 362 DesktopNotify notifier; 363 #endif 364 365 #ifdef Q_OS_MAC 366 QAction* fileMenu; 367 QAction* editMenu; 368 QAction* contactMenu; 369 QMenu* changeStatusMenu; 370 QAction* editProfileAction; 371 QAction* logoutAction; 372 QAction* addContactAction; 373 QAction* nextConversationAction; 374 QAction* previousConversationAction; 375 #endif 376 }; 377 378 bool toxActivateEventHandler(const QByteArray& data); 379 380 #endif // WIDGET_H 381