From 6a2e6d58233cbf40b34f962f2b2f9b1589969e13 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 17 Mar 2015 16:00:02 +0100 Subject: Fix keyboard shortcuts for --no-tabs mode This commit enables the following shortcuts for --no-tabs mode: - CTRL + Tab or CTRL/CMD + PageDown to switch to the next chat window - CTRL + Shift + Tab or CTRL/CMD + PageUp to switch to the previous chat window - CTRL/CMD + W to close the current chat window - ALT + A to switch to the next chat window with active messages Test-Information: Verified that the new shortcuts work as expected and verified that standard mode and netbook mode still work as usual. Change-Id: I3831b6c02f5d664cc8b21d7571e20aed00de89b4 diff --git a/Swift/QtUI/QtChatTabs.h b/Swift/QtUI/QtChatTabs.h index bee03ec..71d4ddc 100644 --- a/Swift/QtUI/QtChatTabs.h +++ b/Swift/QtUI/QtChatTabs.h @@ -10,6 +10,8 @@ #include #include +#include + class QTabWidget; class QMenu; @@ -21,13 +23,13 @@ namespace Swift { class QtDynamicGridLayout; class QtGridSelectionDialog; - class QtChatTabs : public QWidget { + class QtChatTabs : public QWidget, public QtChatTabsBase { Q_OBJECT public: QtChatTabs(bool singleWindow, SettingsProvider* settingsProvider, bool trellisMode); virtual ~QtChatTabs(); - void addTab(QtTabbable* tab); + virtual void addTab(QtTabbable* tab); void minimise(); QtTabbable* getCurrentTab(); void setViewMenu(QMenu* viewMenu); diff --git a/Swift/QtUI/QtChatTabsBase.cpp b/Swift/QtUI/QtChatTabsBase.cpp new file mode 100644 index 0000000..140ff08 --- /dev/null +++ b/Swift/QtUI/QtChatTabsBase.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include + +namespace Swift { + +QtChatTabsBase::QtChatTabsBase() { + +} + +QtChatTabsBase::~QtChatTabsBase() { + +} + +} diff --git a/Swift/QtUI/QtChatTabsBase.h b/Swift/QtUI/QtChatTabsBase.h new file mode 100644 index 0000000..753b706 --- /dev/null +++ b/Swift/QtUI/QtChatTabsBase.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +namespace Swift { + +class QtTabbable; + +class QtChatTabsBase { + public: + QtChatTabsBase(); + virtual ~QtChatTabsBase(); + + virtual void addTab(QtTabbable* tab) = 0; +}; + +} diff --git a/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.cpp b/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.cpp new file mode 100644 index 0000000..7f44177 --- /dev/null +++ b/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include + +#include + +#include +#include + +#include +#include + +#include + +namespace Swift { + +QtChatTabsShortcutOnlySubstitute::QtChatTabsShortcutOnlySubstitute() : QWidget() { + +} + +QtChatTabsShortcutOnlySubstitute::~QtChatTabsShortcutOnlySubstitute() { + +} + +void QtChatTabsShortcutOnlySubstitute::addTab(QtTabbable* tab) { + connect(tab, SIGNAL(requestNextTab()), this, SLOT(handleRequestedNextTab()), Qt::UniqueConnection); + connect(tab, SIGNAL(requestActiveTab()), this, SLOT(handleRequestedActiveTab()), Qt::UniqueConnection); + connect(tab, SIGNAL(requestPreviousTab()), this, SLOT(handleRequestedPreviousTab()), Qt::UniqueConnection); + + connect(new QShortcut(QKeySequence(tr("CTRL+W", "Close chat tab.")), tab), SIGNAL(activated()), this, SLOT(handleCloseTabShortcut())); + connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_PageUp), tab), SIGNAL(activated()), tab, SIGNAL(requestPreviousTab())); + connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_PageDown), tab), SIGNAL(activated()), tab, SIGNAL(requestNextTab())); + connect(new QShortcut(QKeySequence(Qt::ALT + Qt::Key_A), tab), SIGNAL(activated()), tab, SIGNAL(requestActiveTab())); +} + +void QtChatTabsShortcutOnlySubstitute::handleCloseTabShortcut() { + QtTabbable* senderTab = dynamic_cast(sender()->parent()); + SWIFT_LOG_ASSERT(senderTab, debug) << "No window to close." << std::endl; + if (senderTab) { + senderTab->close(); + } +} + +void QtChatTabsShortcutOnlySubstitute::handleRequestedNextTab() { + QtTabbable* senderTab = dynamic_cast(sender()); + + QList tabs = tabbableWindows(); + + int currentIndex = tabs.indexOf(senderTab); + assert(currentIndex >= 0); + + QtTabbable* nextTab = tabs.at((currentIndex + 1) % tabs.size()); + nextTab->activateWindow(); +} + +void QtChatTabsShortcutOnlySubstitute::handleRequestedActiveTab() { + QtTabbable* senderTab = dynamic_cast(sender()); + + QtTabbable::AlertType types[] = {QtTabbable::WaitingActivity, QtTabbable::ImpendingActivity}; + + QList tabs = tabbableWindows(); + + for (int j = 0; j < 2; j++) { + int startIndex = tabs.indexOf(senderTab); + int currentIndex = startIndex; + + do { + currentIndex = (currentIndex + 1) % tabs.size(); + QtTabbable* currentTab = tabs.at(currentIndex); + if (currentTab->getWidgetAlertState() == types[j]) { + currentTab->activateWindow(); + return; + } + } while (startIndex != currentIndex); + } +} + +void QtChatTabsShortcutOnlySubstitute::handleRequestedPreviousTab() { + QtTabbable* senderTab = dynamic_cast(sender()); + + QList tabs = tabbableWindows(); + + int currentIndex = tabs.indexOf(senderTab); + assert(currentIndex >= 0); + + QtTabbable* previousTab = tabs.at((currentIndex + tabs.size() - 1) % tabs.size()); + previousTab->activateWindow(); +} + +QList QtChatTabsShortcutOnlySubstitute::tabbableWindows() const { + QList windows = qApp->topLevelWidgets(); + + QList tabbables; + foreach(QWidget* topLevelWidget, windows) { + QtTabbable* tabbable = dynamic_cast(topLevelWidget); + if (tabbable) { + tabbables << tabbable; + } + } + + return tabbables; +} + +} + diff --git a/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h b/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h new file mode 100644 index 0000000..069bb0b --- /dev/null +++ b/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include +#include + +#include + +class QShortcut; + +namespace Swift { + +class QtChatTabsShortcutOnlySubstitute : public QWidget, public QtChatTabsBase { + Q_OBJECT + + public: + QtChatTabsShortcutOnlySubstitute(); + virtual ~QtChatTabsShortcutOnlySubstitute(); + + virtual void addTab(QtTabbable* tab); + + private slots: + void handleCloseTabShortcut(); + void handleRequestedNextTab(); + void handleRequestedActiveTab(); + void handleRequestedPreviousTab(); + + private: + QList tabbableWindows() const; + + private: + QList shortcuts_; +}; + +} diff --git a/Swift/QtUI/QtChatWindowFactory.cpp b/Swift/QtUI/QtChatWindowFactory.cpp index 1774653..b9ba89d 100644 --- a/Swift/QtUI/QtChatWindowFactory.cpp +++ b/Swift/QtUI/QtChatWindowFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -21,19 +22,21 @@ namespace Swift { static const QString SPLITTER_STATE = "mucSplitterState"; static const QString CHAT_TABS_GEOMETRY = "chatTabsGeometry"; -QtChatWindowFactory::QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath, const std::map& emoticons) : themePath_(themePath), emoticons_(emoticons) { +QtChatWindowFactory::QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabsBase* tabs, const QString& themePath, const std::map& emoticons) : themePath_(themePath), emoticons_(emoticons) { qtOnlySettings_ = qtSettings; settings_ = settings; tabs_ = tabs; theme_ = NULL; + QtChatTabs* fullTabs = dynamic_cast(tabs_); if (splitter) { - splitter->addWidget(tabs_); - } else if (tabs_) { + assert(fullTabs && "Netbook mode and no-tabs interface is not supported!"); + splitter->addWidget(fullTabs); + } else if (fullTabs) { QVariant chatTabsGeometryVariant = qtOnlySettings_->getQSettings()->value(CHAT_TABS_GEOMETRY); if (chatTabsGeometryVariant.isValid()) { - tabs_->restoreGeometry(chatTabsGeometryVariant.toByteArray()); + fullTabs->restoreGeometry(chatTabsGeometryVariant.toByteArray()); } - connect(tabs_, SIGNAL(geometryChanged()), this, SLOT(handleWindowGeometryChanged())); + connect(fullTabs, SIGNAL(geometryChanged()), this, SLOT(handleWindowGeometryChanged())); } } diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h index c38202f..6b1f0a1 100644 --- a/Swift/QtUI/QtChatWindowFactory.h +++ b/Swift/QtUI/QtChatWindowFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -19,7 +19,7 @@ #include namespace Swift { - class QtChatTabs; + class QtChatTabsBase; class QtChatTheme; class UIEventStream; class QtUIPreferences; @@ -27,7 +27,7 @@ namespace Swift { class QtChatWindowFactory : public QObject, public ChatWindowFactory { Q_OBJECT public: - QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath, const std::map& emoticons); + QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabsBase* tabs, const QString& themePath, const std::map& emoticons); ~QtChatWindowFactory(); ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream); signals: @@ -39,7 +39,7 @@ namespace Swift { QString themePath_; SettingsProvider* settings_; QtSettingsProvider* qtOnlySettings_; - QtChatTabs* tabs_; + QtChatTabsBase* tabs_; QtChatTheme* theme_; std::map emoticons_; }; diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp index bce3ca4..20d7bc9 100644 --- a/Swift/QtUI/QtSwift.cpp +++ b/Swift/QtUI/QtSwift.cpp @@ -38,7 +38,9 @@ #include #include +#include #include +#include #include #include #include @@ -165,7 +167,13 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa } bool enableAdHocCommandOnJID = options.count("enable-jid-adhocs") > 0; - tabs_ = options.count("no-tabs") && !splitter_ ? NULL : new QtChatTabs(splitter_ != NULL, settingsHierachy_, options.count("trellis")); + tabs_ = NULL; + if (options.count("no-tabs") && !splitter_) { + tabs_ = new QtChatTabsShortcutOnlySubstitute(); + } + else { + tabs_ = new QtChatTabs(splitter_ != NULL, settingsHierachy_, options.count("trellis")); + } bool startMinimized = options.count("start-minimized") > 0; applicationPathProvider_ = new PlatformApplicationPathProvider(SWIFT_APPLICATION_NAME); storagesFactory_ = new FileStoragesFactory(applicationPathProvider_->getDataDir(), networkFactories_.getCryptoProvider()); diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h index cbe9c62..a971324 100644 --- a/Swift/QtUI/QtSwift.h +++ b/Swift/QtUI/QtSwift.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -41,7 +41,7 @@ namespace Swift { class CapsStorage; class MainController; class QtSystemTray; - class QtChatTabs; + class QtChatTabsBase; class QtChatWindowFactory; class QtSoundPlayer; class QtMUCSearchWindowFactory; @@ -77,7 +77,7 @@ namespace Swift { QtSoundPlayer* soundPlayer_; Dock* dock_; URIHandler* uriHandler_; - QtChatTabs* tabs_; + QtChatTabsBase* tabs_; ApplicationPathProvider* applicationPathProvider_; StoragesFactory* storagesFactory_; CertificateStorageFactory* certificateStorageFactory_; diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp index c7b64b3..8dece86 100644 --- a/Swift/QtUI/QtUIFactory.cpp +++ b/Swift/QtUI/QtUIFactory.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -36,14 +37,15 @@ namespace Swift { -QtUIFactory::QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QtSingleWindow* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, TimerFactory* timerFactory, StatusCache* statusCache, bool startMinimized, bool emoticonsExist, bool enableAdHocCommandOnJID) : settings(settings), qtOnlySettings(qtOnlySettings), tabs(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), timerFactory_(timerFactory), lastMainWindow(NULL), loginWindow(NULL), statusCache(statusCache), startMinimized(startMinimized), emoticonsExist_(emoticonsExist), enableAdHocCommandOnJID_(enableAdHocCommandOnJID) { +QtUIFactory::QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabsBase* tabs, QtSingleWindow* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, TimerFactory* timerFactory, StatusCache* statusCache, bool startMinimized, bool emoticonsExist, bool enableAdHocCommandOnJID) : settings(settings), qtOnlySettings(qtOnlySettings), tabsBase(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), timerFactory_(timerFactory), lastMainWindow(NULL), loginWindow(NULL), statusCache(statusCache), startMinimized(startMinimized), emoticonsExist_(emoticonsExist), enableAdHocCommandOnJID_(enableAdHocCommandOnJID) { chatFontSize = settings->getSetting(QtUISettingConstants::CHATWINDOW_FONT_SIZE); historyFontSize_ = settings->getSetting(QtUISettingConstants::HISTORYWINDOW_FONT_SIZE); + this->tabs = dynamic_cast(tabsBase); } XMLConsoleWidget* QtUIFactory::createXMLConsoleWidget() { QtXMLConsoleWidget* widget = new QtXMLConsoleWidget(); - tabs->addTab(widget); + tabsBase->addTab(widget); showTabs(); widget->show(); return widget; @@ -51,8 +53,7 @@ XMLConsoleWidget* QtUIFactory::createXMLConsoleWidget() { HistoryWindow* QtUIFactory::createHistoryWindow(UIEventStream* uiEventStream) { QtHistoryWindow* window = new QtHistoryWindow(settings, uiEventStream); - tabs->addTab(window); - + tabsBase->addTab(window); showTabs(); connect(window, SIGNAL(fontResized(int)), this, SLOT(handleHistoryWindowFontResized(int))); @@ -68,7 +69,7 @@ void QtUIFactory::handleHistoryWindowFontResized(int size) { FileTransferListWidget* QtUIFactory::createFileTransferListWidget() { QtFileTransferListWidget* widget = new QtFileTransferListWidget(); - tabs->addTab(widget); + tabsBase->addTab(widget); showTabs(); widget->show(); return widget; diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h index 05b4f6a..1d935bc 100644 --- a/Swift/QtUI/QtUIFactory.h +++ b/Swift/QtUI/QtUIFactory.h @@ -16,6 +16,7 @@ class QSplitter; namespace Swift { class QtSettingsProvider; class SettingsProviderHierachy; + class QtChatTabsBase; class QtChatTabs; class QtSystemTray; class QtLoginWindow; @@ -32,7 +33,7 @@ namespace Swift { class QtUIFactory : public QObject, public UIFactory { Q_OBJECT public: - QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QtSingleWindow* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, TimerFactory* timerFactory, StatusCache* statusCache, bool startMinimized, bool emoticonsExist, bool enableAdHocCommandOnJID); + QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabsBase* tabs, QtSingleWindow* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, TimerFactory* timerFactory, StatusCache* statusCache, bool startMinimized, bool emoticonsExist, bool enableAdHocCommandOnJID); virtual XMLConsoleWidget* createXMLConsoleWidget(); virtual HistoryWindow* createHistoryWindow(UIEventStream*); @@ -63,6 +64,7 @@ namespace Swift { private: SettingsProviderHierachy* settings; QtSettingsProvider* qtOnlySettings; + QtChatTabsBase* tabsBase; QtChatTabs* tabs; QtSingleWindow* netbookSplitter; QtSystemTray* systemTray; diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 36f7cc9..f3251d2 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -108,6 +108,8 @@ sources = [ "QtPlainChatView.cpp", "QtChatTheme.cpp", "QtChatTabs.cpp", + "QtChatTabsBase.cpp", + "QtChatTabsShortcutOnlySubstitute.cpp", "QtSoundPlayer.cpp", "QtSystemTray.cpp", "QtCachedImageScaler.cpp", -- cgit v0.10.2-6-g49f6