diff options
author | Tobias Markmann <tm@ayena.de> | 2014-11-25 14:07:29 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2014-12-14 14:44:00 (GMT) |
commit | b4a54583c4d575fe152122c21da616c3c942bbfd (patch) | |
tree | 7e558fd9cb75291f4d5eec90da9d8dd5650ceea2 /Swift/QtUI/QtChatTabs.cpp | |
parent | 92672e17a52d0c86e693183627c8c6b8fa44fb86 (diff) | |
download | swift-b4a54583c4d575fe152122c21da616c3c942bbfd.zip swift-b4a54583c4d575fe152122c21da616c3c942bbfd.tar.bz2 |
Add support for new trellis layout for chat windows.
This includes dynamic customizable grid layouting of chat tabs including:
- arrengement of tabs via menu, keyboard shortcuts or drag'n'drop
- change of grid size via mouse or keyboard
- save/restore of grid size and positions of chats inside the grid
Test-Information:
Tested on OS X 10.9.8.
Change-Id: I43f94293a1c672971640c3000abfc6530f2ea7a8
Diffstat (limited to 'Swift/QtUI/QtChatTabs.cpp')
-rw-r--r-- | Swift/QtUI/QtChatTabs.cpp | 201 |
1 files changed, 152 insertions, 49 deletions
diff --git a/Swift/QtUI/QtChatTabs.cpp b/Swift/QtUI/QtChatTabs.cpp index cf335e1..d04977e 100644 --- a/Swift/QtUI/QtChatTabs.cpp +++ b/Swift/QtUI/QtChatTabs.cpp @@ -1,72 +1,141 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "QtChatTabs.h" +#include <Swift/QtUI/QtChatTabs.h> #include <algorithm> #include <vector> +#include <Swiften/Base/Log.h> + #include <Swift/Controllers/ChatMessageSummarizer.h> +#include <Swift/Controllers/SettingConstants.h> +#include <Swift/Controllers/Settings/SettingsProvider.h> #include <Swift/QtUI/QtSwiftUtil.h> +#include <Swift/QtUI/QtTabWidget.h> +#include <Swift/QtUI/QtTabbable.h> +#include <Swift/QtUI/Trellis/QtDynamicGridLayout.h> +#include <Swift/QtUI/Trellis/QtGridSelectionDialog.h> +#include <QAction> +#include <QApplication> #include <QCloseEvent> +#include <QCursor> #include <QDesktopWidget> -#include <QtGlobal> -#include <QTabWidget> #include <QLayout> +#include <QMenu> #include <QTabBar> -#include <QApplication> -#include <qdebug.h> +#include <QTabWidget> +#include <QtGlobal> namespace Swift { -QtChatTabs::QtChatTabs(bool singleWindow) : QWidget(), singleWindow_(singleWindow) { +QtChatTabs::QtChatTabs(bool singleWindow, SettingsProvider* settingsProvider, bool trellisMode) : QWidget(), singleWindow_(singleWindow), settingsProvider_(settingsProvider), trellisMode_(trellisMode), dynamicGrid_(NULL), gridSelectionDialog_(NULL) { #ifndef Q_OS_MAC setWindowIcon(QIcon(":/logo-chat-16.png")); #else setAttribute(Qt::WA_ShowWithoutActivating); #endif + dynamicGrid_ = new QtDynamicGridLayout(this, trellisMode); + connect(dynamicGrid_, SIGNAL(tabCloseRequested(int)), this, SLOT(handleTabCloseRequested(int))); - tabs_ = new QtTabWidget(this); - tabs_->setUsesScrollButtons(true); - tabs_->setElideMode(Qt::ElideRight); -#if QT_VERSION >= 0x040500 - /*For Macs, change the tab rendering.*/ - tabs_->setDocumentMode(true); - /*Closable tabs are only in Qt4.5 and later*/ - tabs_->setTabsClosable(true); - tabs_->setMovable(true); - connect(tabs_, SIGNAL(tabCloseRequested(int)), this, SLOT(handleTabCloseRequested(int))); -#else -#warning Qt 4.5 or later is needed. Trying anyway, some things will be disabled. -#endif QVBoxLayout *layout = new QVBoxLayout; layout->setSpacing(0); - layout->setContentsMargins(0, 3, 0, 0); - layout->addWidget(tabs_); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(dynamicGrid_); setLayout(layout); + + if (trellisMode) { + // restore size + std::string gridSizeString = settingsProvider->getSetting(SettingConstants::TRELLIS_GRID_SIZE); + if (!gridSizeString.empty()) { + QByteArray gridSizeData = QByteArray::fromBase64(P2QSTRING(gridSizeString).toUtf8()); + QDataStream dataStreamGridSize(&gridSizeData, QIODevice::ReadWrite); + QSize gridSize(1,1); + dataStreamGridSize >> gridSize; + dynamicGrid_->setDimensions(gridSize); + } + + // restore positions + std::string tabPositionsString = settingsProvider->getSetting(SettingConstants::TRELLIS_GRID_POSITIONS); + if (!tabPositionsString.empty()) { + QByteArray tabPositionsData = QByteArray::fromBase64(P2QSTRING(tabPositionsString).toUtf8()); + QDataStream inTabPositions(&tabPositionsData, QIODevice::ReadWrite); + QHash<QString, QPoint> tabPositions; + inTabPositions >> tabPositions; + dynamicGrid_->setTabPositions(tabPositions); + } + } + + gridSelectionDialog_ = new QtGridSelectionDialog(); +} + +QtChatTabs::~QtChatTabs() { + if (trellisMode_) { + storeTabPositions(); + } + delete gridSelectionDialog_; } void QtChatTabs::closeEvent(QCloseEvent* event) { //Hide first to prevent flickering as each tab is removed. hide(); - for (int i = tabs_->count() - 1; i >= 0; i--) { - tabs_->widget(i)->close(); + if (trellisMode_) { + storeTabPositions(); + } + + for (int i = dynamicGrid_->count() - 1; i >= 0; i--) { + dynamicGrid_->widget(i)->close(); } event->accept(); } QtTabbable* QtChatTabs::getCurrentTab() { - return qobject_cast<QtTabbable*>(tabs_->currentWidget()); + return qobject_cast<QtTabbable*>(dynamicGrid_->currentWidget()); +} + +void QtChatTabs::setViewMenu(QMenu* viewMenu) { + if (trellisMode_) { + viewMenu->addSeparator(); + QAction* action = new QAction(tr("Change &layout"), this); + action->setShortcutContext(Qt::ApplicationShortcut); + action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_L)); + connect(action, SIGNAL(triggered()), this, SLOT(handleOpenLayoutChangeDialog())); + viewMenu->addAction(action); + + action = new QAction(tr("Move Tab right"), this); + action->setShortcutContext(Qt::ApplicationShortcut); + action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Right)); + connect(action, SIGNAL(triggered()), dynamicGrid_, SLOT(moveCurrentTabRight())); + viewMenu->addAction(action); + + action = new QAction(tr("Move Tab left"), this); + action->setShortcutContext(Qt::ApplicationShortcut); + action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Left)); + connect(action, SIGNAL(triggered()), dynamicGrid_, SLOT(moveCurrentTabLeft())); + viewMenu->addAction(action); + + action = new QAction(tr("Move Tab to next group"), this); + action->setShortcutContext(Qt::ApplicationShortcut); + action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Right)); + connect(action, SIGNAL(triggered()), dynamicGrid_, SLOT(moveCurrentTabToNextGroup())); + viewMenu->addAction(action); + + action = new QAction(tr("Move Tab to previous group"), this); + action->setShortcutContext(Qt::ApplicationShortcut); + action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Left)); + connect(action, SIGNAL(triggered()), dynamicGrid_, SLOT(moveCurrentTabToPreviousGroup())); + viewMenu->addAction(action); + } } void QtChatTabs::addTab(QtTabbable* tab) { QSizePolicy policy = sizePolicy(); /* Chat windows like to grow - don't let them */ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - tabs_->addTab(tab, tab->windowTitle()); + dynamicGrid_->addTab(tab, tab->windowTitle()); connect(tab, SIGNAL(titleUpdated()), this, SLOT(handleTabTitleUpdated()), Qt::UniqueConnection); connect(tab, SIGNAL(countUpdated()), this, SLOT(handleTabTitleUpdated()), Qt::UniqueConnection); connect(tab, SIGNAL(windowClosing()), this, SLOT(handleTabClosing()), Qt::UniqueConnection); @@ -85,7 +154,7 @@ void QtChatTabs::handleWidgetShown() { return; } checkForFirstShow(); - if (tabs_->indexOf(widget) >= 0) { + if (dynamicGrid_->indexOf(widget) >= 0) { handleTabTitleUpdated(widget); return; } @@ -101,7 +170,7 @@ void QtChatTabs::handleWantsToActivate() { setWindowState(windowState() | Qt::WindowActive); show(); widget->show(); - tabs_->setCurrentWidget(widget); + dynamicGrid_->setCurrentWidget(widget); handleTabTitleUpdated(widget); widget->setFocus(); raise(); @@ -111,9 +180,9 @@ void QtChatTabs::handleWantsToActivate() { void QtChatTabs::handleTabClosing() { QWidget* widget = qobject_cast<QWidget*>(sender()); int index; - if (widget && ((index = tabs_->indexOf(widget)) >= 0)) { - tabs_->removeTab(index); - if (tabs_->count() == 0) { + if (widget && ((index = dynamicGrid_->indexOf(widget)) >= 0)) { + dynamicGrid_->removeTab(index); + if (dynamicGrid_->count() == 0) { if (!singleWindow_) { hide(); } @@ -123,19 +192,19 @@ void QtChatTabs::handleTabClosing() { } } else { - handleTabTitleUpdated(tabs_->currentWidget()); + handleTabTitleUpdated(dynamicGrid_->currentWidget()); } } } void QtChatTabs::handleRequestedPreviousTab() { - int newIndex = tabs_->currentIndex() - 1; - tabs_->setCurrentIndex(newIndex >= 0 ? newIndex : tabs_->count() - 1); + int newIndex = dynamicGrid_->currentIndex() - 1; + dynamicGrid_->setCurrentIndex(newIndex >= 0 ? newIndex : dynamicGrid_->count() - 1); } void QtChatTabs::handleRequestedNextTab() { - int newIndex = tabs_->currentIndex() + 1; - tabs_->setCurrentIndex(newIndex < tabs_->count() ? newIndex : 0); + int newIndex = dynamicGrid_->currentIndex() + 1; + dynamicGrid_->setCurrentIndex(newIndex < dynamicGrid_->count() ? newIndex : 0); } void QtChatTabs::handleRequestedActiveTab() { @@ -143,16 +212,16 @@ void QtChatTabs::handleRequestedActiveTab() { bool finished = false; for (int j = 0; j < 2; j++) { bool looped = false; - for (int i = tabs_->currentIndex() + 1; !finished && i != tabs_->currentIndex(); i++) { - if (i >= tabs_->count()) { + for (int i = dynamicGrid_->currentIndex() + 1; !finished && i != dynamicGrid_->currentIndex(); i++) { + if (i >= dynamicGrid_->count()) { if (looped) { break; } looped = true; i = 0; } - if (qobject_cast<QtTabbable*>(tabs_->widget(i))->getWidgetAlertState() == types[j]) { - tabs_->setCurrentIndex(i); + if (qobject_cast<QtTabbable*>(dynamicGrid_->widget(i))->getWidgetAlertState() == types[j]) { + dynamicGrid_->setCurrentIndex(i); finished = true; break; } @@ -162,7 +231,13 @@ void QtChatTabs::handleRequestedActiveTab() { void QtChatTabs::handleTabCloseRequested(int index) { - QWidget* widget = tabs_->widget(index); + if (trellisMode_) { + storeTabPositions(); + } + + assert(index < dynamicGrid_->count()); + QWidget* widget = dynamicGrid_->widget(index); + assert(widget); widget->close(); } @@ -176,7 +251,7 @@ void QtChatTabs::handleTabTitleUpdated(QWidget* widget) { return; } QtTabbable* tabbable = qobject_cast<QtTabbable*>(widget); - int index = tabs_->indexOf(widget); + int index = dynamicGrid_->indexOf(widget); if (index < 0) { return; } @@ -202,11 +277,14 @@ void QtChatTabs::handleTabTitleUpdated(QWidget* widget) { accelsTaken[i] = (i == 0); //A is used for 'switch to active tab' i++; } - int other = tabs_->tabBar()->count(); + + int other = dynamicGrid_->count(); while (other >= 0) { other--; if (other != index) { - QString t = tabs_->tabBar()->tabText(other).toLower(); + int tabIndex = -1; + QtTabWidget* tabWidget = dynamicGrid_->indexToTabWidget(other, tabIndex); + QString t = tabWidget->tabBar()->tabText(tabIndex).toLower(); int r = t.indexOf('&'); if (r >= 0 && t[r+1] >= 'a' && t[r+1] <= 'z') { accelsTaken[t[r+1].unicode()-'a'] = true; @@ -235,24 +313,26 @@ void QtChatTabs::handleTabTitleUpdated(QWidget* widget) { // doesn't work on Arabic/Indic keyboards (where Latin letters // aren't available), but I don't care to deal with those. - tabs_->setTabText(index, tabbable->getCount() > 0 ? QString("(%1) %2").arg(tabbable->getCount()).arg(tabText) : tabText); + int tabIndex = -1; + QtTabWidget* tabWidget = dynamicGrid_->indexToTabWidget(index, tabIndex); + tabWidget->setTabText(tabIndex, tabbable->getCount() > 0 ? QString("(%1) %2").arg(tabbable->getCount()).arg(tabText) : tabText); QColor tabTextColor; switch (tabbable->getWidgetAlertState()) { case QtTabbable::WaitingActivity : tabTextColor = QColor(217, 20, 43); break; case QtTabbable::ImpendingActivity : tabTextColor = QColor(27, 171, 32); break; case QtTabbable::NoActivity : tabTextColor = QColor(); break; } - tabs_->tabBar()->setTabTextColor(index, tabTextColor); + tabWidget->tabBar()->setTabTextColor(tabIndex, tabTextColor); std::vector<std::pair<std::string, int> > unreads; - for (int i = 0; i < tabs_->count(); i++) { - QtTabbable* tab = qobject_cast<QtTabbable*>(tabs_->widget(i)); + for (int i = 0; i < dynamicGrid_->count(); i++) { + QtTabbable* tab = qobject_cast<QtTabbable*>(dynamicGrid_->widget(i)); if (tab) { unreads.push_back(std::pair<std::string, int>(Q2PSTRING(tab->windowTitle()), tab->getCount())); } } - std::string current(Q2PSTRING(qobject_cast<QtTabbable*>(tabs_->currentWidget())->windowTitle())); + std::string current(Q2PSTRING(qobject_cast<QtTabbable*>(dynamicGrid_->currentWidget())->windowTitle())); ChatMessageSummarizer summary; QString title = summary.getSummary(current, unreads).c_str(); setWindowTitle(title); @@ -265,6 +345,29 @@ void QtChatTabs::flash() { #endif } +void QtChatTabs::handleOpenLayoutChangeDialog() { + disconnect(gridSelectionDialog_, SIGNAL(currentGridSizeChanged(QSize)), dynamicGrid_, SLOT(setDimensions(QSize))); + gridSelectionDialog_->setCurrentGridSize(dynamicGrid_->getDimension()); + gridSelectionDialog_->move(QCursor::pos()); + connect(gridSelectionDialog_, SIGNAL(currentGridSizeChanged(QSize)), dynamicGrid_, SLOT(setDimensions(QSize))); + gridSelectionDialog_->show(); +} + +void QtChatTabs::storeTabPositions() { + // save size + QByteArray gridSizeData; + QDataStream dataStreamGridSize(&gridSizeData, QIODevice::ReadWrite); + dataStreamGridSize << dynamicGrid_->getDimension(); + settingsProvider_->storeSetting(SettingConstants::TRELLIS_GRID_SIZE, Q2PSTRING(QString(gridSizeData.toBase64()))); + + // save positions + QByteArray tabPositionsData; + QDataStream dataStreamTabPositions(&tabPositionsData, QIODevice::ReadWrite); + dynamicGrid_->updateTabPositions(); + dataStreamTabPositions << dynamicGrid_->getTabPositions(); + settingsProvider_->storeSetting(SettingConstants::TRELLIS_GRID_POSITIONS, Q2PSTRING(QString(tabPositionsData.toBase64()))); +} + void QtChatTabs::resizeEvent(QResizeEvent*) { emit geometryChanged(); } |