File indexing completed on 2024-12-01 07:42:31

0001 /*
0002    SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "ruqolamainwindow.h"
0008 #include "databasedialog/exploredatabasedialog.h"
0009 #include "explorepermissionsdialog/explorepermissionsdialog.h"
0010 #include "notificationhistorymanager.h"
0011 #include "ruqolaglobalconfig.h"
0012 #include "ruqolawidgets_debug.h"
0013 
0014 #include "accountmanager.h"
0015 #include "administratordialog/administratordialog.h"
0016 #include "administratorsettingsdialog/administratorsettingsdialog.h"
0017 #include "servererrorinfohistory/servererrorinfomessagehistorydialog.h"
0018 
0019 #include "bannerinfodialog/bannerinfodialog.h"
0020 #include "config-ruqola.h"
0021 #include "configuredialog/configuresettingsdialog.h"
0022 #include "connection.h"
0023 #include "createnewserver/createnewserverdialog.h"
0024 #include "dialogs/channelpassworddialog.h"
0025 #include "dialogs/createdirectmessagesdialog.h"
0026 #include "dialogs/createnewchanneldialog.h"
0027 #include "dialogs/createnewdiscussiondialog.h"
0028 #include "dialogs/modifystatusdialog.h"
0029 #include "dialogs/serverinfo/serverinfodialog.h"
0030 #include "directory/directorydialog.h"
0031 #include "importexportdata/exportdata/exportdatawizard.h"
0032 #include "importexportdata/importdata/importdatawizard.h"
0033 #include "localdatabase/localmessagelogger.h"
0034 #include "misc/accountsoverviewwidget.h"
0035 #include "misc/messagestylelayoutmenu.h"
0036 #include "misc/servermenu.h"
0037 #include "misc/statuscombobox.h"
0038 #include "model/statusmodel.h"
0039 #include "model/statusmodelfilterproxymodel.h"
0040 #include "myaccount/myaccountconfiguredialog.h"
0041 #include "notificationhistory/notificationhistorydialog.h"
0042 #include "notifications/notification.h"
0043 #include "ownuser/ownuserpreferences.h"
0044 #include "receivetypingnotificationmanager.h"
0045 #include "registeruser/registeruserdialog.h"
0046 #include "rocketchataccount.h"
0047 #include "room.h"
0048 #include "ruqola.h"
0049 #include "ruqolacentralwidget.h"
0050 #include "ruqolacommandlineoptions.h"
0051 #include "ruqolaserverconfig.h"
0052 #include "switchchannelhistory/switchchanneltreeviewmanager.h"
0053 #include "teams/teamscreatejob.h"
0054 #include "whatsnew/whatsnewdialog.h"
0055 
0056 #include <KActionCollection>
0057 #include <KColorSchemeManager>
0058 #include <KConfigGroup>
0059 #include <KIO/JobUiDelegateFactory>
0060 #include <KIO/OpenUrlJob>
0061 #include <KLocalizedString>
0062 #include <KMessageBox>
0063 #include <KNotifyConfigWidget>
0064 #include <KSharedConfig>
0065 #include <KStandardAction>
0066 #include <KToggleFullScreenAction>
0067 #include <KToolBar>
0068 #include <QActionGroup>
0069 #include <QApplication>
0070 #include <QCommandLineParser>
0071 #include <QDir>
0072 #include <QFontDatabase>
0073 #include <QHBoxLayout>
0074 #include <QIcon>
0075 #include <QKeyCombination>
0076 #include <QLabel>
0077 #include <QMenu>
0078 #include <QMenuBar>
0079 #include <QStatusBar>
0080 #include <QTemporaryFile>
0081 #include <QToolButton>
0082 #include <QWidgetAction>
0083 
0084 #include <KColorSchemeMenu>
0085 
0086 #if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
0087 #include <KWindowSystem>
0088 #endif
0089 
0090 #if HAVE_KUSERFEEDBACK
0091 #include "userfeedback/userfeedbackmanager.h"
0092 #include <KUserFeedback/NotificationPopup>
0093 #include <KUserFeedback/Provider>
0094 #endif
0095 #include "colorsandmessageviewstyle.h"
0096 
0097 namespace
0098 {
0099 static const char myRuqolaMainWindowGroupName[] = "RuqolaMainWindow";
0100 }
0101 
0102 RuqolaMainWindow::RuqolaMainWindow(QWidget *parent)
0103     : KXmlGuiWindow(parent)
0104     , mMainWidget(new RuqolaCentralWidget(this))
0105     , mStatusProxyModel(new StatusModelFilterProxyModel(this))
0106     , mSwitchChannelTreeManager(new SwitchChannelTreeViewManager(this))
0107 {
0108     mMainWidget->setObjectName(QStringLiteral("mMainWidget"));
0109     connect(mMainWidget, &RuqolaCentralWidget::loginPageActivated, this, &RuqolaMainWindow::slotLoginPageActivated);
0110     setCentralWidget(mMainWidget);
0111     setupActions();
0112     setupStatusBar();
0113     setupGUI(/*QStringLiteral(":/kxmlgui5/ruqola/ruqolaui.rc")*/);
0114     readConfig();
0115     createSystemTray();
0116     mSwitchChannelTreeManager->setParentWidget(mMainWidget);
0117     connect(mSwitchChannelTreeManager, &SwitchChannelTreeViewManager::switchToChannel, this, &RuqolaMainWindow::slotHistorySwitchChannel);
0118     mAccountManager = Ruqola::self()->accountManager();
0119     connect(mAccountManager, &AccountManager::currentAccountChanged, this, &RuqolaMainWindow::slotAccountChanged);
0120     connect(mAccountManager, &AccountManager::updateNotification, this, &RuqolaMainWindow::updateNotification);
0121     connect(mAccountManager, &AccountManager::roomNeedAttention, this, &RuqolaMainWindow::slotRoomNeedAttention);
0122     connect(mAccountManager, &AccountManager::messageUrlNotFound, this, &RuqolaMainWindow::slotMessageUrlNotFound);
0123     connect(mAccountManager, &AccountManager::logoutAccountDone, this, &RuqolaMainWindow::logout);
0124 
0125     slotAccountChanged();
0126 #if HAVE_KUSERFEEDBACK
0127     auto userFeedBackNotificationPopup = new KUserFeedback::NotificationPopup(this);
0128     userFeedBackNotificationPopup->setFeedbackProvider(UserFeedBackManager::self()->userFeedbackProvider());
0129 #endif
0130     mShowMenuBarAction->setChecked(RuqolaGlobalConfig::self()->showMenuBar());
0131     slotToggleMenubar(true);
0132 }
0133 
0134 RuqolaMainWindow::~RuqolaMainWindow()
0135 {
0136     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0137     KConfigGroup group = config->group(QLatin1String(myRuqolaMainWindowGroupName));
0138     group.writeEntry("Size", size());
0139 
0140     delete mMainWidget; // before Ruqola::destroy()
0141 
0142     Ruqola::destroy();
0143 }
0144 
0145 void RuqolaMainWindow::parseCommandLine(QCommandLineParser *parser)
0146 {
0147     if (parser->isSet(QStringLiteral("messageurl"))) {
0148         const QString messageUrl = parser->value(QStringLiteral("messageurl"));
0149         if (!messageUrl.isEmpty()) {
0150             Ruqola::self()->openMessageUrl(messageUrl);
0151         }
0152     }
0153     if (parser->isSet(QStringLiteral("account"))) {
0154         const QString loadAccount = parser->value(QStringLiteral("account"));
0155         if (!loadAccount.isEmpty()) {
0156             Ruqola::self()->setCurrentAccount(loadAccount);
0157         }
0158     }
0159 }
0160 
0161 #if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
0162 void RuqolaMainWindow::slotActivateRequested(const QStringList &arguments, const QString &workingDirectory)
0163 {
0164     Q_UNUSED(workingDirectory)
0165     if (!arguments.isEmpty()) {
0166         QCommandLineParser parser;
0167         ruqolaOptions(&parser);
0168         parser.parse(arguments);
0169         parseCommandLine(&parser);
0170     }
0171 
0172     KWindowSystem::updateStartupId(windowHandle());
0173     KWindowSystem::activateWindow(windowHandle());
0174 }
0175 #endif
0176 
0177 void RuqolaMainWindow::slotRoomNeedAttention()
0178 {
0179     if (mNotification) {
0180         mNotification->roomNeedAttention();
0181     }
0182 }
0183 
0184 void RuqolaMainWindow::logout(const QString &accountName)
0185 {
0186     if (mNotification) {
0187         mNotification->clearNotification(accountName);
0188     }
0189 }
0190 
0191 void RuqolaMainWindow::updateNotification(bool hasAlert, int nbUnread, const QString &accountName)
0192 {
0193     if (mNotification) {
0194         mNotification->updateNotification(hasAlert, nbUnread, accountName);
0195     }
0196 }
0197 
0198 void RuqolaMainWindow::setupStatusBar()
0199 {
0200     mStatusBarTypingMessage = new QLabel(this);
0201     mStatusBarTypingMessage->setTextFormat(Qt::RichText);
0202     mStatusBarTypingMessage->setObjectName(QStringLiteral("mStatusBarTypingMessage"));
0203     statusBar()->addPermanentWidget(mStatusBarTypingMessage);
0204     mAccountOverviewWidget = new AccountsOverviewWidget(this);
0205     mAccountOverviewWidget->setObjectName(QStringLiteral("mAccountOverviewWidget"));
0206     statusBar()->addPermanentWidget(mAccountOverviewWidget);
0207     mNotificationToolButton = new QToolButton(this);
0208     mNotificationToolButton->setIcon(QIcon::fromTheme(QStringLiteral("notifications")));
0209     mNotificationToolButton->setObjectName(QStringLiteral("mNotificationToolButton"));
0210     mNotificationToolButton->setToolTip(i18n("Show New Notifications"));
0211 #ifndef QT_NO_ACCESSIBILITY
0212     mNotificationToolButton->setAccessibleName(i18n("Show New Notifications"));
0213 #endif
0214 
0215     mNotificationToolButton->hide(); // Hide at start
0216     mNotificationToolButton->setAutoRaise(true);
0217     connect(mNotificationToolButton, &QToolButton::clicked, this, &RuqolaMainWindow::slotOpenNotificationHistory);
0218     statusBar()->addPermanentWidget(mNotificationToolButton);
0219     connect(NotificationHistoryManager::self(), &NotificationHistoryManager::newNotification, this, &RuqolaMainWindow::slotNewNotification);
0220 }
0221 
0222 void RuqolaMainWindow::slotNewNotification()
0223 {
0224     mNotificationToolButton->show();
0225 }
0226 
0227 void RuqolaMainWindow::slotAccountChanged()
0228 {
0229     if (mCurrentRocketChatAccount) {
0230         disconnect(mCurrentRocketChatAccount, nullptr, this, nullptr);
0231         disconnect(mCurrentRocketChatAccount->receiveTypingNotificationManager(), nullptr, this, nullptr);
0232     }
0233     mCurrentRocketChatAccount = Ruqola::self()->rocketChatAccount();
0234     connect(mCurrentRocketChatAccount->receiveTypingNotificationManager(),
0235             &ReceiveTypingNotificationManager::notificationChanged,
0236             this,
0237             &RuqolaMainWindow::slotTypingNotificationChanged);
0238     connect(mCurrentRocketChatAccount->receiveTypingNotificationManager(),
0239             &ReceiveTypingNotificationManager::clearNotification,
0240             this,
0241             &RuqolaMainWindow::slotClearNotification);
0242     connect(mCurrentRocketChatAccount, &RocketChatAccount::missingChannelPassword, this, &RuqolaMainWindow::slotMissingChannelPassword);
0243     connect(mCurrentRocketChatAccount, &RocketChatAccount::publicSettingChanged, this, &RuqolaMainWindow::updateActions);
0244     connect(mCurrentRocketChatAccount, &RocketChatAccount::serverVersionChanged, this, [this]() {
0245         slotPermissionChanged();
0246         updateActions();
0247     });
0248     connect(mCurrentRocketChatAccount, &RocketChatAccount::ownInfoChanged, this, [this]() {
0249         updateActions();
0250         slotPermissionChanged();
0251     });
0252     connect(mCurrentRocketChatAccount, &RocketChatAccount::ownUserPreferencesChanged, this, [this]() {
0253         updateActions();
0254     });
0255     connect(mCurrentRocketChatAccount, &RocketChatAccount::raiseWindow, this, &RuqolaMainWindow::slotRaiseWindow);
0256     connect(mCurrentRocketChatAccount, &RocketChatAccount::permissionChanged, this, &RuqolaMainWindow::slotPermissionChanged);
0257     connect(mCurrentRocketChatAccount, &RocketChatAccount::registerUserSuccess, this, &RuqolaMainWindow::slotRegisterUserSuccessed);
0258     connect(mCurrentRocketChatAccount,
0259             &RocketChatAccount::userStatusUpdated,
0260             this,
0261             [this](User::PresenceStatus status, const QString &customText, const QString &accountName) {
0262                 if (mCurrentRocketChatAccount->accountName() == accountName) {
0263                     mStatusComboBox->blockSignals(true);
0264                     mStatusComboBox->setStatus(status, customText);
0265                     mStatusComboBox->blockSignals(false);
0266                 }
0267             });
0268     connect(mCurrentRocketChatAccount, &RocketChatAccount::customStatusChanged, this, &RuqolaMainWindow::slotUpdateCustomUserStatus);
0269     connect(mCurrentRocketChatAccount, &RocketChatAccount::privateSettingsChanged, this, &RuqolaMainWindow::slotPrivateSettingsChanged);
0270     connect(mCurrentRocketChatAccount, &RocketChatAccount::publicSettingChanged, this, &RuqolaMainWindow::slotPrivateSettingsChanged);
0271 
0272     updateActions();
0273     slotClearNotification(); // Clear notification when we switch too.
0274     mMainWidget->setCurrentRocketChatAccount(mCurrentRocketChatAccount);
0275     mSwitchChannelTreeManager->setCurrentRocketChatAccount(mCurrentRocketChatAccount);
0276 
0277     mStatusComboBox->blockSignals(true);
0278     mStatusProxyModel->setSourceModel(mCurrentRocketChatAccount->statusModel());
0279     slotPrivateSettingsChanged();
0280     mStatusComboBox->setModel(mStatusProxyModel);
0281 
0282     slotUpdateCustomUserStatus();
0283     mStatusComboBox->setStatus(mCurrentRocketChatAccount->presenceStatus());
0284     mStatusComboBox->blockSignals(false);
0285 
0286     slotUpdateStatusMenu();
0287 }
0288 
0289 void RuqolaMainWindow::slotPrivateSettingsChanged()
0290 {
0291     mStatusProxyModel->setAllowOfflineSupport(mCurrentRocketChatAccount->ruqolaServerConfig()->accountsAllowInvisibleStatusOption());
0292     mStatusProxyModel->setUseOnlyStandardStatus(!mCurrentRocketChatAccount->ruqolaServerConfig()->allowCustomStatusMessage());
0293 }
0294 
0295 void RuqolaMainWindow::slotRaiseWindow()
0296 {
0297     show();
0298     raise();
0299 #if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
0300     KWindowSystem::activateWindow(windowHandle());
0301 #else
0302     activateWindow();
0303 #endif
0304 }
0305 
0306 void RuqolaMainWindow::slotPermissionChanged()
0307 {
0308     mCreateNewChannel->setEnabled(canCreateChannels());
0309     mCreateDirectMessages->setEnabled(canCreateDirectMessages());
0310     mCreateTeam->setEnabled(canCreateTeams());
0311 }
0312 
0313 void RuqolaMainWindow::updateActions()
0314 {
0315     mUnreadOnTop->setChecked(mCurrentRocketChatAccount->ownUserPreferences().showUnread());
0316     const auto roomListSortOrder = mCurrentRocketChatAccount->ownUserPreferences().roomListSortOrder();
0317     mRoomListSortByLastMessage->setChecked(roomListSortOrder == OwnUserPreferences::RoomListSortOrder::ByLastMessage);
0318     mRoomListSortAlphabetically->setChecked(roomListSortOrder == OwnUserPreferences::RoomListSortOrder::Alphabetically);
0319     mRegisterNewUser->setVisible(mCurrentRocketChatAccount->registrationFormEnabled());
0320     mCreateDiscussion->setEnabled(mCurrentRocketChatAccount->discussionEnabled()
0321                                   && (mCurrentRocketChatAccount->loginStatus() == DDPAuthenticationManager::LoggedIn));
0322     const bool isAdministrator{mCurrentRocketChatAccount->isAdministrator()};
0323     mAdministrator->setEnabled(isAdministrator);
0324     mAdministratorServerSettings->setEnabled(isAdministrator);
0325     mAdministratorMenu->setVisible(isAdministrator);
0326     mShowRocketChatServerInfo->setVisible(hasBannerInfo());
0327     mRoomAvatar->setChecked(mCurrentRocketChatAccount->ownUserPreferences().showRoomAvatar());
0328     mRoomFavorite->setChecked(mCurrentRocketChatAccount->ownUserPreferences().showFavorite());
0329     mCreateNewChannel->setEnabled(canCreateChannels());
0330     mCreateDirectMessages->setEnabled(canCreateDirectMessages());
0331     mCreateTeam->setEnabled(canCreateTeams());
0332 }
0333 
0334 bool RuqolaMainWindow::canCreateChannels() const
0335 {
0336     return mCurrentRocketChatAccount && mCurrentRocketChatAccount->hasPermission(QStringLiteral("create-c"));
0337 }
0338 
0339 bool RuqolaMainWindow::canCreateDirectMessages() const
0340 {
0341     return mCurrentRocketChatAccount && mCurrentRocketChatAccount->hasPermission(QStringLiteral("create-d"));
0342 }
0343 
0344 bool RuqolaMainWindow::canCreateTeams() const
0345 {
0346     return mCurrentRocketChatAccount && mCurrentRocketChatAccount->hasPermission(QStringLiteral("create-team"));
0347 }
0348 
0349 bool RuqolaMainWindow::hasBannerInfo() const
0350 {
0351     return mCurrentRocketChatAccount && !mCurrentRocketChatAccount->bannerInfos().isEmpty();
0352 }
0353 
0354 void RuqolaMainWindow::readConfig()
0355 {
0356     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0357     KConfigGroup group = KConfigGroup(config, QLatin1String(myRuqolaMainWindowGroupName));
0358     const QSize sizeDialog = group.readEntry("Size", QSize(800, 600));
0359     if (sizeDialog.isValid()) {
0360         resize(sizeDialog);
0361     }
0362 }
0363 
0364 void RuqolaMainWindow::slotClearNotification()
0365 {
0366     mStatusBarTypingMessage->clear();
0367 }
0368 
0369 void RuqolaMainWindow::slotTypingNotificationChanged(const QString &roomId, const QString &notificationStr)
0370 {
0371     if (mMainWidget->roomId() == roomId) {
0372         mStatusBarTypingMessage->setText(notificationStr);
0373     }
0374 }
0375 
0376 void RuqolaMainWindow::setupActions()
0377 {
0378     KActionCollection *ac = actionCollection();
0379 
0380     mShowMenuBarAction = KStandardAction::showMenubar(this, &RuqolaMainWindow::slotToggleMenubar, ac);
0381 
0382     KStandardAction::quit(this, &RuqolaMainWindow::slotClose, ac);
0383     KStandardAction::preferences(this, &RuqolaMainWindow::slotConfigure, ac);
0384     KStandardAction::configureNotifications(this, &RuqolaMainWindow::slotConfigureNotifications, ac);
0385 
0386     auto act = new QAction(i18n("Add Server..."), this);
0387     connect(act, &QAction::triggered, this, &RuqolaMainWindow::slotAddServer);
0388     ac->addAction(QStringLiteral("add_server"), act);
0389 
0390     // Move in specific server widget
0391     mServerInfo = new QAction(i18n("Server Info..."), this);
0392     connect(mServerInfo, &QAction::triggered, this, &RuqolaMainWindow::slotServerInfo);
0393     ac->addAction(QStringLiteral("server_info"), mServerInfo);
0394 
0395     mLogout = new QAction(i18n("Logout Current Server"), this);
0396     connect(mLogout, &QAction::triggered, this, &RuqolaMainWindow::slotLogout);
0397     ac->addAction(QStringLiteral("logout"), mLogout);
0398 
0399     mNextUnreadChannel = new QAction(i18n("Jump to Next Unread Channel"), this);
0400     connect(mNextUnreadChannel, &QAction::triggered, this, &RuqolaMainWindow::slotSelectNextUnreadChannel);
0401     ac->setDefaultShortcut(mNextUnreadChannel, Qt::Key_Control | Qt::Key_PageDown);
0402     ac->addAction(QStringLiteral("next_unread_channel"), mNextUnreadChannel);
0403 
0404     mCreateNewChannel = new QAction(QIcon::fromTheme(QStringLiteral("irc-join-channel")), i18n("Create New Channel..."), this);
0405     connect(mCreateNewChannel, &QAction::triggered, this, &RuqolaMainWindow::slotCreateNewChannel);
0406     ac->addAction(QStringLiteral("create_new_channel"), mCreateNewChannel);
0407 
0408     mCreateDirectMessages = new QAction(QIcon::fromTheme(QStringLiteral("irc-join-channel")), i18n("Create Direct Messages..."), this);
0409     connect(mCreateDirectMessages, &QAction::triggered, this, &RuqolaMainWindow::slotCreateDirectMessages);
0410     ac->addAction(QStringLiteral("create_direct_messages"), mCreateDirectMessages);
0411 
0412     mCreateDiscussion = new QAction(QIcon::fromTheme(QStringLiteral("irc-join-channel")), i18n("Create Discussion..."), this);
0413     connect(mCreateDiscussion, &QAction::triggered, this, &RuqolaMainWindow::slotCreateDiscussion);
0414     ac->addAction(QStringLiteral("create_discussion"), mCreateDiscussion);
0415 
0416     mCreateTeam = new QAction(QIcon::fromTheme(QStringLiteral("irc-join-channel")), i18n("Create Team..."), this);
0417     connect(mCreateTeam, &QAction::triggered, this, &RuqolaMainWindow::slotCreateTeam);
0418     ac->addAction(QStringLiteral("create_team"), mCreateTeam);
0419 
0420     mServerMenu = new ServerMenu(this);
0421     mServerMenu->setActionCollection(ac);
0422     ac->addAction(QStringLiteral("server_menu"), mServerMenu);
0423 
0424     mUnreadOnTop = new QAction(i18n("Unread on Top"), this);
0425     mUnreadOnTop->setCheckable(true);
0426     connect(mUnreadOnTop, &QAction::triggered, this, &RuqolaMainWindow::slotUnreadOnTop);
0427     ac->addAction(QStringLiteral("unread_on_top"), mUnreadOnTop);
0428 
0429     QActionGroup *roomListSortOrder = new QActionGroup(this);
0430     roomListSortOrder->setExclusive(true);
0431 
0432     mRoomListSortByLastMessage = new QAction(i18n("By Last Message"), this);
0433     mRoomListSortByLastMessage->setCheckable(true);
0434     connect(mRoomListSortByLastMessage, &QAction::triggered, this, &RuqolaMainWindow::slotRoomListSortByLastMessage);
0435     roomListSortOrder->addAction(mRoomListSortByLastMessage);
0436     ac->addAction(QStringLiteral("room_list_sort_by_last_message"), mRoomListSortByLastMessage);
0437 
0438     mRoomListSortAlphabetically = new QAction(i18n("Alphabetically"), this);
0439     mRoomListSortAlphabetically->setCheckable(true);
0440     connect(mRoomListSortAlphabetically, &QAction::triggered, this, &RuqolaMainWindow::slotRoomListSortAlphabetically);
0441     roomListSortOrder->addAction(mRoomListSortAlphabetically);
0442     ac->addAction(QStringLiteral("room_list_sort_alphabetically"), mRoomListSortAlphabetically);
0443 
0444     mShowLog = new QAction(QIcon::fromTheme(QStringLiteral("view-history")), i18n("Show Channel Log"), this);
0445     connect(mShowLog, &QAction::triggered, this, &RuqolaMainWindow::slotShowLog);
0446     ac->addAction(QStringLiteral("show_log"), mShowLog);
0447 
0448     mShowServerInfo = new QAction(QIcon::fromTheme(QStringLiteral("data-error")), i18n("Show Server Errors"), this);
0449     connect(mShowServerInfo, &QAction::triggered, this, &RuqolaMainWindow::slotShowServerInfo);
0450     ac->addAction(QStringLiteral("show_server_errors"), mShowServerInfo);
0451 
0452     if (Ruqola::self()->debug()) {
0453         mMenuDebug = new QAction(QStringLiteral("Debug"), this);
0454         ac->addAction(QStringLiteral("debug_menu"), mMenuDebug);
0455         auto menu = new QMenu(this);
0456         mMenuDebug->setMenu(menu);
0457         mShowDatabaseMessages = new QAction(QStringLiteral("Show Database Messages"), this);
0458         connect(mShowDatabaseMessages, &QAction::triggered, this, &RuqolaMainWindow::slotShowDatabaseMessages);
0459         ac->addAction(QStringLiteral("show_database_messages"), mShowDatabaseMessages);
0460         menu->addAction(mShowDatabaseMessages);
0461         mShowPermissions = new QAction(QStringLiteral("Show Permissions"), this);
0462         connect(mShowPermissions, &QAction::triggered, this, &RuqolaMainWindow::slotShowPermissions);
0463         ac->addAction(QStringLiteral("show_permissions"), mShowPermissions);
0464         menu->addAction(mShowPermissions);
0465     }
0466 
0467     mClearAlerts = new QAction(i18n("Mark All Channels as Read"), this);
0468     ac->setDefaultShortcut(mClearAlerts, Qt::SHIFT | Qt::Key_Escape);
0469     connect(mClearAlerts, &QAction::triggered, this, &RuqolaMainWindow::slotClearAccountAlerts);
0470     ac->addAction(QStringLiteral("mark_all_channels_read"), mClearAlerts);
0471 
0472     mRegisterNewUser = new QAction(i18n("Register a New User..."), this);
0473     connect(mRegisterNewUser, &QAction::triggered, this, &RuqolaMainWindow::slotRegisterNewUser);
0474     ac->addAction(QStringLiteral("register_new_user"), mRegisterNewUser);
0475 
0476     mMyAccount = new QAction(i18n("My Account..."), this);
0477     connect(mMyAccount, &QAction::triggered, this, &RuqolaMainWindow::slotConfigureMyAccount);
0478     ac->addAction(QStringLiteral("configure_my_account"), mMyAccount);
0479 
0480     mAdministratorMenu = new KActionMenu(i18n("Administrator"), this);
0481     mAdministrator = new QAction(i18n("Administrator..."), this);
0482     ac->addAction(QStringLiteral("administrator_account_settings"), mAdministrator);
0483     connect(mAdministrator, &QAction::triggered, this, &RuqolaMainWindow::slotAdministrator);
0484     mAdministratorMenu->addAction(mAdministrator);
0485     ac->addAction(QStringLiteral("administrator"), mAdministratorMenu);
0486 
0487     mAdministratorServerSettings = new QAction(i18n("Server Settings..."), this);
0488     connect(mAdministratorServerSettings, &QAction::triggered, this, &RuqolaMainWindow::slotAdministratorServerSettings);
0489     ac->addAction(QStringLiteral("administrator_server_settings"), mAdministratorServerSettings);
0490     mAdministratorMenu->addAction(mAdministratorServerSettings);
0491 
0492     mDirectory = new QAction(i18nc("Action which allows to search room/user/team", "Directory..."), this);
0493     connect(mDirectory, &QAction::triggered, this, &RuqolaMainWindow::slotDirectory);
0494     ac->addAction(QStringLiteral("directory"), mDirectory);
0495 
0496     // Actions to navigate through the different pages
0497     QList<QKeySequence> nextShortcut;
0498     QList<QKeySequence> prevShortcut;
0499 
0500     QString nextIcon, prevIcon;
0501     if (QApplication::isRightToLeft()) {
0502         prevShortcut.append(QKeySequence(QStringLiteral("Alt+Right")));
0503         nextShortcut.append(QKeySequence(QStringLiteral("Alt+Left")));
0504         nextIcon = QStringLiteral("go-previous-view");
0505         prevIcon = QStringLiteral("go-next-view");
0506     } else {
0507         nextShortcut.append(QKeySequence(QStringLiteral("Alt+Right")));
0508         prevShortcut.append(QKeySequence(QStringLiteral("Alt+Left")));
0509         nextIcon = QStringLiteral("go-next-view");
0510         prevIcon = QStringLiteral("go-previous-view");
0511     }
0512 
0513     mNextTab = new QAction(QIcon::fromTheme(nextIcon), i18n("&Next Server"), this);
0514     actionCollection()->setDefaultShortcuts(mNextTab, nextShortcut);
0515     connect(mNextTab, &QAction::triggered, this, &RuqolaMainWindow::showNextView);
0516     actionCollection()->addAction(QStringLiteral("next_tab"), mNextTab);
0517 
0518     mPreviewTab = new QAction(QIcon::fromTheme(prevIcon), i18n("&Previous Server"), this);
0519     actionCollection()->setDefaultShortcuts(mPreviewTab, prevShortcut);
0520     connect(mPreviewTab, &QAction::triggered, this, &RuqolaMainWindow::showPreviousView);
0521     actionCollection()->addAction(QStringLiteral("previous_tab"), mPreviewTab);
0522 
0523     {
0524         auto action = new QWidgetAction(this);
0525         action->setText(i18n("Status"));
0526         auto container = new QWidget(this);
0527         // use the same font as other toolbar buttons
0528         container->setFont(qApp->font("QToolButton"));
0529         action->setDefaultWidget(container);
0530         auto layout = new QHBoxLayout(container);
0531         layout->setContentsMargins({});
0532         auto label = new QLabel(i18n("Status:"), container);
0533         label->setObjectName(QStringLiteral("label"));
0534         layout->addWidget(label);
0535 
0536         mStatusComboBox = new StatusCombobox(container);
0537         mStatusComboBox->setObjectName(QStringLiteral("mStatusComboBox"));
0538         layout->addWidget(mStatusComboBox);
0539         connect(mStatusComboBox, &StatusCombobox::currentIndexChanged, this, &RuqolaMainWindow::slotStatusChanged);
0540         connect(mStatusComboBox, &StatusCombobox::currentIndexChanged, this, &RuqolaMainWindow::slotUpdateStatusMenu);
0541 
0542         mStatus = action;
0543         connect(mStatus, &QAction::triggered, mStatusComboBox, &QComboBox::showPopup);
0544         ac->addAction(QStringLiteral("status"), mStatus);
0545     }
0546 
0547     {
0548         QList<QAction *> listActions;
0549         auto act = new QAction(i18n("Previous Selected Channel"), this);
0550         ac->setDefaultShortcut(act, QKeySequence(Qt::CTRL | Qt::Key_Tab));
0551         ac->addAction(QStringLiteral("previous_channel"), act);
0552         listActions.append(act);
0553 
0554         connect(act, &QAction::triggered, this, &RuqolaMainWindow::undoSwitchChannel);
0555 
0556         act = new QAction(i18n("Next Selected Channel"), this);
0557         ac->addAction(QStringLiteral("next_channel"), act);
0558         QKeyCombination combinationKeys(Qt::CTRL | Qt::SHIFT, Qt::Key_Tab);
0559         ac->setDefaultShortcut(act, combinationKeys);
0560         connect(act, &QAction::triggered, this, &RuqolaMainWindow::redoSwitchChannel);
0561         listActions.append(act);
0562 
0563         mSwitchChannelTreeManager->addActions(listActions);
0564     }
0565 
0566     if (menuBar()) {
0567         mHamburgerMenu = KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection());
0568         mHamburgerMenu->setShowMenuBarAction(mShowMenuBarAction);
0569         mHamburgerMenu->setMenuBar(menuBar());
0570         connect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, [this]() {
0571             updateHamburgerMenu();
0572             // Immediately disconnect. We only need to run this once, but on demand.
0573             // NOTE: The nullptr at the end disconnects all connections between
0574             // q and mHamburgerMenu's aboutToShowMenu signal.
0575             disconnect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, nullptr);
0576         });
0577     }
0578 
0579     auto manager = new KColorSchemeManager(this);
0580     ac->addAction(QStringLiteral("colorscheme_menu"), KColorSchemeMenu::createMenu(manager, this));
0581 
0582     mShowFullScreenAction = KStandardAction::fullScreen(nullptr, nullptr, this, ac);
0583     ac->setDefaultShortcut(mShowFullScreenAction, Qt::Key_F11);
0584     connect(mShowFullScreenAction, &QAction::toggled, this, &RuqolaMainWindow::slotFullScreen);
0585 
0586     mShowNotifyHistory = new QAction(QIcon::fromTheme(QStringLiteral("notifications")), i18n("Show Notify History"), this);
0587     connect(mShowNotifyHistory, &QAction::triggered, this, &RuqolaMainWindow::slotOpenNotificationHistory);
0588     ac->addAction(QStringLiteral("show_notify_history"), mShowNotifyHistory);
0589 
0590     mShowRocketChatServerInfo = new QAction(i18n("Show RocketChat Information"), this);
0591     connect(mShowRocketChatServerInfo, &QAction::triggered, this, &RuqolaMainWindow::slotRocketChatInformation);
0592     ac->addAction(QStringLiteral("show_rocketchat_information"), mShowRocketChatServerInfo);
0593 
0594     mRoomAvatar = new QAction(i18n("Show Room Avatar"), this);
0595     mRoomAvatar->setCheckable(true);
0596     connect(mRoomAvatar, &QAction::triggered, this, &RuqolaMainWindow::slotShowRoomAvatar);
0597     ac->addAction(QStringLiteral("room_avatar"), mRoomAvatar);
0598 
0599     mRoomFavorite = new QAction(i18n("Show Favorite Room"), this);
0600     mRoomFavorite->setCheckable(true);
0601     connect(mRoomFavorite, &QAction::triggered, this, &RuqolaMainWindow::slotShowFavoriteRoom);
0602     ac->addAction(QStringLiteral("room_favorite"), mRoomFavorite);
0603 
0604     auto showWhatsNewAction = new QAction(QIcon::fromTheme(QStringLiteral("ruqola")), i18n("What's new"), this);
0605     ac->addAction(QStringLiteral("whatsnew_ruqola"), showWhatsNewAction);
0606     connect(showWhatsNewAction, &QAction::triggered, this, &RuqolaMainWindow::slotWhatsNew);
0607 
0608     mImportAccountsAction = new QAction(QIcon::fromTheme(QStringLiteral("document-import")), i18n("Import Accounts"), this);
0609     connect(mImportAccountsAction, &QAction::triggered, this, &RuqolaMainWindow::slotImportAccounts);
0610     ac->addAction(QStringLiteral("import_accounts"), mImportAccountsAction);
0611 
0612     mExportAccountsAction = new QAction(QIcon::fromTheme(QStringLiteral("document-export")), i18n("Export Accounts"), this);
0613     connect(mExportAccountsAction, &QAction::triggered, this, &RuqolaMainWindow::slotExportAccounts);
0614     ac->addAction(QStringLiteral("export_accounts"), mExportAccountsAction);
0615 
0616     auto messageStyleAction = new MessageStyleLayoutMenu(this);
0617     ac->addAction(QStringLiteral("message_style"), messageStyleAction);
0618     connect(messageStyleAction, &MessageStyleLayoutMenu::styleChanged, this, &RuqolaMainWindow::slotMessageStyleChanged);
0619 }
0620 
0621 void RuqolaMainWindow::slotMessageStyleChanged()
0622 {
0623     Q_EMIT ColorsAndMessageViewStyle::self().needUpdateMessageStyle();
0624 }
0625 
0626 void RuqolaMainWindow::slotWhatsNew()
0627 {
0628     WhatsNewDialog dlg(this);
0629     dlg.updateInformations();
0630     dlg.exec();
0631 }
0632 
0633 void RuqolaMainWindow::showNextView()
0634 {
0635     mAccountOverviewWidget->showNextView();
0636 }
0637 
0638 void RuqolaMainWindow::showPreviousView()
0639 {
0640     mAccountOverviewWidget->showPreviousView();
0641 }
0642 
0643 void RuqolaMainWindow::slotClearAccountAlerts()
0644 {
0645     if (auto acct = mAccountManager->account()) {
0646         acct->clearAllUnreadMessages();
0647     }
0648 }
0649 
0650 void RuqolaMainWindow::slotCreateTeam()
0651 {
0652     QPointer<CreateNewChannelDialog> dlg = new CreateNewChannelDialog(mCurrentRocketChatAccount, this);
0653     dlg->setWindowTitle(i18nc("@title:window", "Create Team"));
0654     CreateNewChannelWidget::Features flags;
0655     if (mCurrentRocketChatAccount->broadCastEnabled()) {
0656         flags |= CreateNewChannelWidget::Feature::BroadCast;
0657     }
0658     if (mCurrentRocketChatAccount->encryptionEnabled()) {
0659         flags |= CreateNewChannelWidget::Feature::Encrypted;
0660     }
0661     dlg->setFeatures(flags);
0662     if (dlg->exec()) {
0663         RocketChatRestApi::CreateChannelTeamInfo teamInfo = dlg->channelInfo(true);
0664         teamInfo.infoType = RocketChatRestApi::CreateChannelTeamInfo::CreateInfoType::Team;
0665         auto job = new RocketChatRestApi::TeamsCreateJob(this);
0666         job->setTeamsCreateJobInfo(teamInfo);
0667         mCurrentRocketChatAccount->restApi()->initializeRestApiJob(job);
0668         connect(job, &RocketChatRestApi::TeamsCreateJob::teamCreateDone, this, []() {
0669             qCDebug(RUQOLAWIDGETS_LOG) << " teamCreateDone";
0670             // TODO switch to new team ?
0671         });
0672         if (!job->start()) {
0673             qCWarning(RUQOLAWIDGETS_LOG) << "Impossible to start TeamsCreateJob";
0674         }
0675     }
0676     delete dlg;
0677 }
0678 
0679 void RuqolaMainWindow::slotCreateDiscussion()
0680 {
0681     CreateNewDiscussionDialog dlg(mCurrentRocketChatAccount, this);
0682     dlg.exec();
0683 }
0684 
0685 void RuqolaMainWindow::slotCreateDirectMessages()
0686 {
0687     CreateDirectMessagesDialog dlg(mCurrentRocketChatAccount, this);
0688     dlg.exec();
0689 }
0690 
0691 void RuqolaMainWindow::slotCreateNewChannel()
0692 {
0693     QPointer<CreateNewChannelDialog> dlg = new CreateNewChannelDialog(mCurrentRocketChatAccount, this);
0694     CreateNewChannelWidget::Features flags;
0695     if (mCurrentRocketChatAccount->broadCastEnabled()) {
0696         flags |= CreateNewChannelWidget::Feature::BroadCast;
0697     }
0698     if (mCurrentRocketChatAccount->encryptionEnabled()) {
0699         flags |= CreateNewChannelWidget::Feature::Encrypted;
0700     }
0701     dlg->setFeatures(flags);
0702     if (dlg->exec()) {
0703         RocketChatRestApi::CreateChannelTeamInfo info = dlg->channelInfo(false);
0704         info.infoType = RocketChatRestApi::CreateChannelTeamInfo::CreateInfoType::Channel;
0705         mCurrentRocketChatAccount->createNewChannel(info);
0706     }
0707     delete dlg;
0708 }
0709 
0710 void RuqolaMainWindow::slotConfigure()
0711 {
0712     QPointer<ConfigureSettingsDialog> dlg = new ConfigureSettingsDialog(this);
0713     if (dlg->exec()) {
0714         if (RuqolaGlobalConfig::self()->useCustomFont()) {
0715             qApp->setFont(RuqolaGlobalConfig::self()->generalFont());
0716         } else {
0717             qApp->setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
0718         }
0719 
0720         mAccountOverviewWidget->updateButtons();
0721         createSystemTray();
0722         Q_EMIT Ruqola::self()->translatorMenuChanged();
0723     }
0724     delete dlg;
0725 }
0726 
0727 void RuqolaMainWindow::slotAuthentication(AuthenticationManager::AuthMethodType type)
0728 {
0729     qDebug() << "Not implement plugin " << type;
0730 }
0731 
0732 void RuqolaMainWindow::slotAddServer()
0733 {
0734     QPointer<CreateNewServerDialog> dlg = new CreateNewServerDialog(this);
0735     connect(dlg, &CreateNewServerDialog::authentication, this, &RuqolaMainWindow::slotAuthentication);
0736     const QStringList lst = mAccountManager->accountsName();
0737     dlg->setExistingAccountName(lst);
0738     if (dlg->exec()) {
0739         const AccountManager::AccountManagerInfo info = dlg->accountInfo();
0740         mAccountManager->addAccount(std::move(info));
0741     }
0742     delete dlg;
0743 }
0744 
0745 void RuqolaMainWindow::slotServerInfo()
0746 {
0747     ServerInfoDialog dlg(mCurrentRocketChatAccount, this);
0748     dlg.exec();
0749 }
0750 
0751 void RuqolaMainWindow::slotLogout()
0752 {
0753     mCurrentRocketChatAccount->logOut();
0754 }
0755 
0756 void RuqolaMainWindow::slotSelectNextUnreadChannel()
0757 {
0758     mMainWidget->selectNextUnreadChannel();
0759 }
0760 
0761 void RuqolaMainWindow::slotUnreadOnTop(bool checked)
0762 {
0763     mCurrentRocketChatAccount->setSortUnreadOnTop(checked);
0764 }
0765 
0766 void RuqolaMainWindow::slotRoomListSortByLastMessage()
0767 {
0768     mCurrentRocketChatAccount->setRoomListSortOrder(OwnUserPreferences::RoomListSortOrder::ByLastMessage);
0769 }
0770 
0771 void RuqolaMainWindow::slotRoomListSortAlphabetically()
0772 {
0773     mCurrentRocketChatAccount->setRoomListSortOrder(OwnUserPreferences::RoomListSortOrder::Alphabetically);
0774 }
0775 
0776 void RuqolaMainWindow::slotShowDatabaseMessages()
0777 {
0778     // Use only when we want to debug and has database support
0779     ExploreDatabaseDialog dlg(mCurrentRocketChatAccount, this);
0780     dlg.exec();
0781 }
0782 
0783 void RuqolaMainWindow::slotShowPermissions()
0784 {
0785     ExplorePermissionsDialog dlg(this);
0786     dlg.setPermissions(mCurrentRocketChatAccount->permissions());
0787     dlg.setOWnRoles(mCurrentRocketChatAccount->ownUserPermission());
0788     dlg.exec();
0789 }
0790 
0791 void RuqolaMainWindow::slotShowServerInfo()
0792 {
0793     ServerErrorInfoMessageHistoryDialog dlg(this);
0794     dlg.addServerList(Ruqola::self()->accountManager()->accountNamesSorted());
0795     dlg.exec();
0796 }
0797 
0798 void RuqolaMainWindow::slotShowLog()
0799 {
0800     auto *room = mMainWidget->room();
0801     if (room) {
0802         QTemporaryFile tempFile(QDir::tempPath() + QStringLiteral("/XXXXXX.log.txt"));
0803         tempFile.setAutoRemove(false);
0804         if (tempFile.open()) {
0805             LocalMessageLogger logger;
0806             if (logger.saveToFile(tempFile, mCurrentRocketChatAccount->accountName(), room->displayFName())) {
0807                 const QString fileName = tempFile.fileName();
0808                 tempFile.close();
0809                 auto job = new KIO::OpenUrlJob(QUrl::fromLocalFile(fileName), this);
0810                 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0811                 job->setDeleteTemporaryFile(true);
0812                 job->start();
0813             } else {
0814                 KMessageBox::information(this, i18n("Impossible to open log."), i18n("Show Log"));
0815             }
0816         }
0817     }
0818 }
0819 
0820 void RuqolaMainWindow::slotMissingChannelPassword(const RocketChatRestApi::ChannelGroupBaseJob::ChannelGroupInfo &channelInfo)
0821 {
0822     QPointer<ChannelPasswordDialog> dlg = new ChannelPasswordDialog(this);
0823     // TODO add channel name!
0824     if (dlg->exec()) {
0825         // FIXME channelinfo
0826         mCurrentRocketChatAccount->joinRoom(channelInfo.identifier, dlg->password());
0827     }
0828     delete dlg;
0829 }
0830 
0831 void RuqolaMainWindow::slotLoginPageActivated(bool loginPageActivated)
0832 {
0833     mCreateNewChannel->setEnabled(!loginPageActivated && canCreateChannels());
0834     mCreateDirectMessages->setEnabled(!loginPageActivated && canCreateDirectMessages());
0835     mLogout->setEnabled(!loginPageActivated);
0836     mClearAlerts->setEnabled(!loginPageActivated);
0837     mMyAccount->setEnabled(!loginPageActivated);
0838     mStatus->setEnabled(!loginPageActivated);
0839     mCreateDiscussion->setEnabled(!loginPageActivated);
0840     mCreateTeam->setEnabled(!loginPageActivated && canCreateTeams());
0841     mDirectory->setEnabled(!loginPageActivated);
0842     mNextUnreadChannel->setEnabled(!loginPageActivated);
0843     mShowLog->setEnabled(!loginPageActivated);
0844     mShowRocketChatServerInfo->setVisible(!loginPageActivated && hasBannerInfo());
0845     mRoomAvatar->setEnabled(!loginPageActivated);
0846     mUnreadOnTop->setEnabled(!loginPageActivated);
0847     mRoomListSortByLastMessage->setEnabled(!loginPageActivated);
0848     mRoomListSortAlphabetically->setEnabled(!loginPageActivated);
0849     mRoomFavorite->setEnabled(!loginPageActivated);
0850     if (mContextStatusMenu) {
0851         mContextStatusMenu->menuAction()->setVisible(!loginPageActivated);
0852     }
0853     if (mShowDatabaseMessages) {
0854         mShowDatabaseMessages->setEnabled(!loginPageActivated);
0855     }
0856     if (mShowPermissions) {
0857         mShowPermissions->setEnabled(!loginPageActivated);
0858     }
0859 }
0860 
0861 void RuqolaMainWindow::slotConfigureNotifications()
0862 {
0863     KNotifyConfigWidget::configure(this);
0864 }
0865 
0866 void RuqolaMainWindow::slotRegisterNewUser()
0867 {
0868     QPointer<RegisterUserDialog> dlg = new RegisterUserDialog(this);
0869     connect(dlg, &RegisterUserDialog::registerNewAccount, this, [this, dlg]() {
0870         mCurrentRocketChatAccount->registerNewUser(dlg->registerUserInfo());
0871     });
0872     dlg->exec();
0873     delete dlg;
0874 }
0875 
0876 void RuqolaMainWindow::slotRegisterUserSuccessed()
0877 {
0878     KMessageBox::information(
0879         this,
0880         i18n("We have sent you an email to confirm your registration.\nIf you do not receive an email shortly, please come back and try again."),
0881         i18n("Register New User"));
0882 }
0883 
0884 void RuqolaMainWindow::slotConfigureMyAccount()
0885 {
0886     MyAccountConfigureDialog dlg(mCurrentRocketChatAccount, this);
0887     dlg.initialize();
0888     dlg.exec();
0889 }
0890 
0891 void RuqolaMainWindow::slotAdministrator()
0892 {
0893     AdministratorDialog dlg(mCurrentRocketChatAccount, this);
0894     dlg.initialize();
0895     dlg.exec();
0896 }
0897 
0898 void RuqolaMainWindow::slotAdministratorServerSettings()
0899 {
0900     AdministratorSettingsDialog dlg(mCurrentRocketChatAccount, this);
0901     dlg.loadSettings();
0902     dlg.exec();
0903 }
0904 
0905 void RuqolaMainWindow::slotDirectory()
0906 {
0907     auto dlg = new DirectoryDialog(mCurrentRocketChatAccount, this);
0908     dlg->fillTabs();
0909     dlg->show();
0910 }
0911 
0912 bool RuqolaMainWindow::queryClose()
0913 {
0914     if (qApp->isSavingSession() || mReallyClose || !mNotification) {
0915         return true;
0916     }
0917     hide();
0918     return false;
0919 }
0920 
0921 void RuqolaMainWindow::slotClose()
0922 {
0923     mReallyClose = true;
0924     close();
0925 }
0926 
0927 void RuqolaMainWindow::createSystemTray()
0928 {
0929 #if !defined(Q_OS_IOS)
0930     if (!RuqolaGlobalConfig::self()->enableSystemTray()) {
0931         delete mNotification;
0932         mNotification = nullptr;
0933         return;
0934     }
0935     if (!mNotification) {
0936         mNotification = new Notification(this);
0937         auto trayMenu = mNotification->contextMenu();
0938 
0939         mContextStatusMenu = mNotification->contextMenu()->addMenu(i18nc("@item:inmenu Instant message presence status", "Status"));
0940         mContextStatusMenu->menuAction()->setVisible(false);
0941         trayMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Preferences)));
0942         trayMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::ConfigureNotifications)));
0943         // Create systray to show notifications on Desktop
0944         connect(mNotification, &Notification::alert, this, [this]() {
0945             QApplication::alert(this, 0);
0946         });
0947     }
0948 #endif
0949 }
0950 
0951 void RuqolaMainWindow::slotStatusChanged()
0952 {
0953     // const auto currentStatusInfo = mCurrentRocketChatAccount->statusModel()->currentStatusInfo();
0954     User::PresenceStatus status = mStatusComboBox->status();
0955     QString messageStatus; // = currentStatusInfo.statusStr;
0956     if (status == User::PresenceStatus::Unknown) {
0957         QPointer<ModifyStatusDialog> dlg = new ModifyStatusDialog(this);
0958         const auto currentStatusInfo = mCurrentRocketChatAccount->statusModel()->currentStatusInfo();
0959         dlg->setMessageStatus(mCurrentRocketChatAccount->statusModel()->customText());
0960         dlg->setStatus(currentStatusInfo.status);
0961         if (dlg->exec()) {
0962             messageStatus = dlg->messageStatus();
0963             status = dlg->status();
0964             delete dlg;
0965         } else {
0966             mStatusComboBox->setStatus(mCurrentRocketChatAccount->statusModel()->currentUserStatus());
0967             delete dlg;
0968             return;
0969         }
0970     }
0971     mCurrentRocketChatAccount->setDefaultStatus(status, messageStatus);
0972 }
0973 
0974 void RuqolaMainWindow::slotUpdateStatusMenu()
0975 {
0976     if (mContextStatusMenu) {
0977         const User::PresenceStatus status = mStatusComboBox->status();
0978         mContextStatusMenu->setTitle(Utils::displaytextFromPresenceStatus(status));
0979         mContextStatusMenu->setIcon(QIcon::fromTheme(Utils::iconFromPresenceStatus(status)));
0980     }
0981 }
0982 
0983 void RuqolaMainWindow::slotUpdateCustomUserStatus()
0984 {
0985     mStatusProxyModel->sort(0);
0986 
0987     if (mContextStatusMenu) {
0988         // mContextStatusMenu->menuAction()->setVisible(true);
0989         mContextStatusMenu->clear();
0990 
0991         for (int i = 0; i < mStatusProxyModel->rowCount(); i++) {
0992             const QModelIndex index = mStatusProxyModel->index(i, 0);
0993             QAction *action = mContextStatusMenu->addAction(index.data(Qt::DisplayRole).toString());
0994             action->setIcon(index.data(Qt::DecorationRole).value<QIcon>());
0995 
0996             connect(action, &QAction::triggered, this, [this, index] {
0997                 mStatusComboBox->setStatus(index.data(StatusModel::StatusRoles::Status).value<User::PresenceStatus>());
0998             });
0999         }
1000     }
1001 }
1002 
1003 void RuqolaMainWindow::slotMessageUrlNotFound(const QString &str)
1004 {
1005     KMessageBox::information(this, str, i18n("Message"));
1006 }
1007 
1008 void RuqolaMainWindow::slotHistorySwitchChannel(const QString &identifier)
1009 {
1010     Q_EMIT mCurrentRocketChatAccount->selectRoomByRoomIdRequested(identifier);
1011 }
1012 
1013 void RuqolaMainWindow::undoSwitchChannel()
1014 {
1015     mSwitchChannelTreeManager->selectForward();
1016 }
1017 
1018 void RuqolaMainWindow::redoSwitchChannel()
1019 {
1020     mSwitchChannelTreeManager->selectBackward();
1021 }
1022 
1023 void RuqolaMainWindow::slotToggleMenubar(bool dontShowWarning)
1024 {
1025     if (menuBar()) {
1026         if (mShowMenuBarAction->isChecked()) {
1027             menuBar()->show();
1028         } else {
1029             if (!dontShowWarning && (!toolBar()->isVisible() || !toolBar()->actions().contains(mHamburgerMenu))) {
1030                 const QString accel = mShowMenuBarAction->shortcut().toString();
1031                 KMessageBox::information(this,
1032                                          i18n("<qt>This will hide the menu bar completely."
1033                                               " You can show it again by typing %1.</qt>",
1034                                               accel),
1035                                          i18n("Hide menu bar"),
1036                                          QStringLiteral("HideMenuBarWarning"));
1037             }
1038             menuBar()->hide();
1039         }
1040         RuqolaGlobalConfig::self()->setShowMenuBar(mShowMenuBarAction->isChecked());
1041         RuqolaGlobalConfig::self()->save();
1042     }
1043 }
1044 
1045 void RuqolaMainWindow::updateHamburgerMenu()
1046 {
1047     auto menu = new QMenu(this);
1048     menu->addAction(actionCollection()->action(QStringLiteral("add_server")));
1049     menu->addSeparator();
1050     menu->addAction(actionCollection()->action(QStringLiteral("configure_my_account")));
1051     menu->addSeparator();
1052     menu->addAction(actionCollection()->action(QStringLiteral("directory")));
1053     menu->addSeparator();
1054     menu->addAction(actionCollection()->action(QStringLiteral("logout")));
1055     menu->addSeparator();
1056     menu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Quit)));
1057     mHamburgerMenu->setMenu(menu);
1058 }
1059 
1060 void RuqolaMainWindow::slotFullScreen(bool t)
1061 {
1062     KToggleFullScreenAction::setFullScreen(this, t);
1063     QMenuBar *mb = menuBar();
1064     if (t) {
1065         auto b = new QToolButton(mb);
1066         b->setDefaultAction(mShowFullScreenAction);
1067         b->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Ignored));
1068         b->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
1069         mb->setCornerWidget(b, Qt::TopRightCorner);
1070         b->setVisible(true);
1071         b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
1072     } else {
1073         QWidget *w = mb->cornerWidget(Qt::TopRightCorner);
1074         if (w) {
1075             w->deleteLater();
1076         }
1077     }
1078 }
1079 
1080 void RuqolaMainWindow::slotShowNotifyMessage(const QString &accountName, const QString &messageId, const QString &roomId)
1081 {
1082     Ruqola::self()->setCurrentAccount(accountName);
1083     Q_EMIT mCurrentRocketChatAccount->selectRoomByRoomIdRequested(roomId, messageId);
1084 }
1085 
1086 void RuqolaMainWindow::slotOpenNotificationHistory()
1087 {
1088     mNotificationToolButton->hide();
1089     NotificationHistoryDialog dlg(this);
1090     dlg.addServerList(Ruqola::self()->accountManager()->accountNamesSorted());
1091     connect(&dlg, &NotificationHistoryDialog::showNotifyMessage, this, &RuqolaMainWindow::slotShowNotifyMessage);
1092     dlg.exec();
1093 }
1094 
1095 void RuqolaMainWindow::slotRocketChatInformation()
1096 {
1097     BannerInfoDialog dlg(mCurrentRocketChatAccount, this);
1098     dlg.exec();
1099 }
1100 
1101 void RuqolaMainWindow::slotShowRoomAvatar(bool checked)
1102 {
1103     mCurrentRocketChatAccount->setShowRoomAvatar(checked);
1104 }
1105 
1106 void RuqolaMainWindow::slotShowFavoriteRoom(bool checked)
1107 {
1108     mCurrentRocketChatAccount->setShowFavoriteRoom(checked);
1109 }
1110 
1111 void RuqolaMainWindow::slotImportAccounts()
1112 {
1113     ImportDataWizard dlg(this);
1114     dlg.exec();
1115 }
1116 
1117 void RuqolaMainWindow::slotExportAccounts()
1118 {
1119     ExportDataWizard dlg(this);
1120     dlg.exec();
1121 }
1122 
1123 #include "moc_ruqolamainwindow.cpp"