/* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "QtChatTabs.h" #include <algorithm> #include <QCloseEvent> #include <QDesktopWidget> #include <QtGlobal> #include <QTabWidget> #include <QLayout> #include <QTabBar> #include <QApplication> #include <qdebug.h> namespace Swift { QtChatTabs::QtChatTabs() : QWidget() { #ifndef Q_WS_MAC setWindowIcon(QIcon(":/logo-chat-16.png")); #endif 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); 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_); setLayout(layout); //resize(400, 300); } 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(); } event->accept(); } QtTabbable* QtChatTabs::getCurrentTab() { return qobject_cast<QtTabbable*>(tabs_->currentWidget()); } 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()); 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); connect(tab, SIGNAL(windowOpening()), this, SLOT(handleWidgetShown()), Qt::UniqueConnection); connect(tab, SIGNAL(wantsToActivate()), this, SLOT(handleWantsToActivate()), Qt::UniqueConnection); 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(tab, SIGNAL(requestFlash()), this, SLOT(flash()), Qt::UniqueConnection); setSizePolicy(policy); } void QtChatTabs::handleWidgetShown() { QtTabbable* widget = qobject_cast<QtTabbable*>(sender()); if (!widget) { return; } checkForFirstShow(); if (tabs_->indexOf(widget) >= 0) { return; } addTab(widget); show(); } void QtChatTabs::handleWantsToActivate() { QtTabbable* widget = qobject_cast<QtTabbable*>(sender()); Q_ASSERT(widget); //Un-minimize and bring to front. setWindowState(windowState() & ~Qt::WindowMinimized); setWindowState(windowState() | Qt::WindowActive); show(); widget->show(); tabs_->setCurrentWidget(widget); widget->setFocus(); raise(); activateWindow(); } void QtChatTabs::handleTabClosing() { QWidget* widget = qobject_cast<QWidget*>(sender()); if (!widget) { return; } int index = tabs_->indexOf(widget); if (index < 0) { return; } tabs_->removeTab(index); if (tabs_->count() == 0) { hide(); } handleTabTitleUpdated(tabs_->currentWidget()); } void QtChatTabs::handleRequestedPreviousTab() { int newIndex = tabs_->currentIndex() - 1; tabs_->setCurrentIndex(newIndex >= 0 ? newIndex : tabs_->count() - 1); } void QtChatTabs::handleRequestedNextTab() { int newIndex = tabs_->currentIndex() + 1; tabs_->setCurrentIndex(newIndex < tabs_->count() ? newIndex : 0); } void QtChatTabs::handleRequestedActiveTab() { QtTabbable::AlertType types[] = {QtTabbable::WaitingActivity, QtTabbable::ImpendingActivity}; 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()) { if (looped) { break; } looped = true; i = 0; } if (qobject_cast<QtTabbable*>(tabs_->widget(i))->getWidgetAlertState() == types[j]) { tabs_->setCurrentIndex(i); finished = true; break; } } } } void QtChatTabs::handleTabCloseRequested(int index) { QWidget* widget = tabs_->widget(index); widget->close(); } void QtChatTabs::handleTabTitleUpdated() { QWidget* widget = qobject_cast<QWidget*>(sender()); handleTabTitleUpdated(widget); } void QtChatTabs::handleTabTitleUpdated(QWidget* widget) { if (!widget) { return; } QtTabbable* tabbable = qobject_cast<QtTabbable*>(widget); int index = tabs_->indexOf(widget); if (index < 0) { return; } tabs_->setTabText(index, tabbable->getCount() > 0 ? QString("(%1) %2").arg(tabbable->getCount()).arg(tabbable->windowTitle()) : tabbable->windowTitle()); QColor tabTextColor; switch (tabbable->getWidgetAlertState()) { case QtTabbable::WaitingActivity : tabTextColor = QColor(217, 20, 43); break; case QtTabbable::ImpendingActivity : tabTextColor = QColor(27, 171, 32); break; default : tabTextColor = QColor(); } tabs_->tabBar()->setTabTextColor(index, tabTextColor); int unread = 0; for (int i = 0; i < tabs_->count(); i++) { QtTabbable* tab = qobject_cast<QtTabbable*>(tabs_->widget(i)); if (tab) { unread += tab->getCount(); } } QtTabbable* current = qobject_cast<QtTabbable*>(tabs_->currentWidget()); setWindowTitle(unread > 0 ? QString("(%1) %2").arg(unread).arg(current->windowTitle()) : current->windowTitle()); } void QtChatTabs::flash() { #ifndef SWIFTEN_PLATFORM_MACOSX QApplication::alert(this, 3000); #endif } void QtChatTabs::resizeEvent(QResizeEvent*) { emit geometryChanged(); } void QtChatTabs::moveEvent(QMoveEvent*) { emit geometryChanged(); } void QtChatTabs::checkForFirstShow() { if (!isVisible()) { showMinimized(); } } }