File indexing completed on 2024-04-28 16:12:55

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