/* * Copyright (c) 2010 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include "QtStatusWidget.h" #include <algorithm> #include <boost/lambda/lambda.hpp> #include <boost/lambda/bind.hpp> #include <QBoxLayout> #include <QComboBox> #include <QLabel> #include <QFrame> #include <QPoint> #include <QStackedWidget> #include <QApplication> #include <QDesktopWidget> #include <qdebug.h> #include <QListWidget> #include <QListWidgetItem> #include <QMovie> #include "Swift/QtUI/QtElidingLabel.h" #include "Swift/QtUI/QtLineEdit.h" #include "Swift/QtUI/QtSwiftUtil.h" #include <Swift/Controllers/StatusUtil.h> #include <Swift/Controllers/StatusCache.h> namespace lambda = boost::lambda; namespace Swift { QtStatusWidget::QtStatusWidget(StatusCache* statusCache, QWidget *parent) : QWidget(parent), statusCache_(statusCache), editCursor_(Qt::IBeamCursor), viewCursor_(Qt::PointingHandCursor) { allTypes_.push_back(StatusShow::Online); allTypes_.push_back(StatusShow::FFC); allTypes_.push_back(StatusShow::Away); allTypes_.push_back(StatusShow::XA); allTypes_.push_back(StatusShow::DND); allTypes_.push_back(StatusShow::None); isClicking_ = false; connecting_ = false; setMaximumHeight(24); connectingMovie_ = new QMovie(":/icons/connecting.mng"); QHBoxLayout* mainLayout = new QHBoxLayout(this); mainLayout->setSpacing(0); mainLayout->setContentsMargins(0,0,0,0); stack_ = new QStackedWidget(this); stack_->setLineWidth(2); stack_->setFrameShape(QFrame::StyledPanel); mainLayout->addWidget(stack_); QWidget* page1 = new QWidget(this); stack_->addWidget(page1); QHBoxLayout* page1Layout = new QHBoxLayout(page1); page1Layout->setSpacing(0); page1Layout->setContentsMargins(0,0,0,0); page1->setCursor(viewCursor_); statusIcon_ = new QLabel(this); statusIcon_->setMinimumSize(16, 16); statusIcon_->setMaximumSize(16, 16); page1Layout->addWidget(statusIcon_); statusTextLabel_ = new QtElidingLabel(this); QFont font = statusTextLabel_->font(); font.setItalic(true); statusTextLabel_->setFont(font); page1Layout->addWidget(statusTextLabel_); icons_[StatusShow::Online] = QIcon(":/icons/online.png"); icons_[StatusShow::Away] = QIcon(":/icons/away.png"); icons_[StatusShow::DND] = QIcon(":/icons/dnd.png"); icons_[StatusShow::None] = QIcon(":/icons/offline.png"); setStatusType(StatusShow::None); QWidget* page2 = new QWidget(this); QHBoxLayout* page2Layout = new QHBoxLayout(page2); page2Layout->setSpacing(0); page2Layout->setContentsMargins(0,0,0,0); stack_->addWidget(page2); statusEdit_ = new QtLineEdit(this); page2Layout->addWidget(statusEdit_); connect(statusEdit_, SIGNAL(returnPressed()), this, SLOT(handleEditComplete())); connect(statusEdit_, SIGNAL(escapePressed()), this, SLOT(handleEditCancelled())); connect(statusEdit_, SIGNAL(textChanged(const QString&)), this, SLOT(generateList())); setStatusText(""); menu_ = new QListWidget(); menu_->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint ); menu_->setAlternatingRowColors(true); menu_->setFocusProxy(statusEdit_); menu_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); menu_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QSizePolicy policy(menu_->sizePolicy()); policy.setVerticalPolicy(QSizePolicy::Expanding); menu_->setSizePolicy(policy); connect(menu_, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(handleItemClicked(QListWidgetItem*))); viewMode(); } QtStatusWidget::~QtStatusWidget() { delete menu_; delete connectingMovie_; } void QtStatusWidget::handleApplicationFocusChanged(QWidget* /*old*/, QWidget* /*now*/) { QWidget* now = qApp->focusWidget(); if (!editing_ || stack_->currentIndex() == 0) { return; } if (!now || (now != menu_ && now != statusEdit_ && !now->isAncestorOf(statusEdit_) && !now->isAncestorOf(menu_) && !statusEdit_->isAncestorOf(now) && !menu_->isAncestorOf(now))) { handleEditCancelled(); } } void QtStatusWidget::mousePressEvent(QMouseEvent*) { if (stack_->currentIndex() == 0) { handleClicked(); } } void QtStatusWidget::generateList() { if (!editing_) { return; } QString text = statusEdit_->text(); newStatusText_ = text; menu_->clear(); foreach (StatusShow::Type type, icons_.keys()) { QListWidgetItem* item = new QListWidgetItem(text == "" ? getNoMessage() : text, menu_); item->setIcon(icons_[type]); item->setToolTip(P2QSTRING(statusShowTypeToFriendlyName(type)) + ": " + item->text()); item->setStatusTip(item->toolTip()); item->setData(Qt::UserRole, QVariant(type)); } std::vector<StatusCache::PreviousStatus> previousStatuses = statusCache_->getMatches(Q2PSTRING(text), 8); foreach (StatusCache::PreviousStatus savedStatus, previousStatuses) { if (savedStatus.first.empty() || std::find_if(allTypes_.begin(), allTypes_.end(), savedStatus.second == lambda::_1 && savedStatus.first == lambda::bind(&statusShowTypeToFriendlyName, lambda::_1)) != allTypes_.end()) { continue; } QListWidgetItem* item = new QListWidgetItem(P2QSTRING(savedStatus.first), menu_); item->setIcon(icons_[savedStatus.second]); item->setToolTip(item->text()); item->setStatusTip(item->toolTip()); item->setData(Qt::UserRole, QVariant(savedStatus.second)); } foreach (StatusShow::Type type, icons_.keys()) { if (Q2PSTRING(text) == statusShowTypeToFriendlyName(type)) { continue; } QListWidgetItem* item = new QListWidgetItem(P2QSTRING(statusShowTypeToFriendlyName(type)), menu_); item->setIcon(icons_[type]); item->setToolTip(item->text()); item->setStatusTip(item->toolTip()); item->setData(Qt::UserRole, QVariant(type)); } resizeMenu(); } void QtStatusWidget::resizeMenu() { int height = menu_->sizeHintForRow(0) * menu_->count(); int marginLeft; int marginTop; int marginRight; int marginBottom; menu_->getContentsMargins(&marginLeft, &marginTop, &marginRight, &marginBottom); height += marginTop + marginBottom; menu_->setGeometry(menu_->x(), menu_->y(), menu_->width(), height); } void QtStatusWidget::handleClicked() { editing_ = true; QDesktopWidget* desktop = QApplication::desktop(); int screen = desktop->screenNumber(this); QPoint point = mapToGlobal(QPoint(0, height())); QRect geometry = desktop->availableGeometry(screen); int x = point.x(); int y = point.y(); int width = 200; int height = 80; int screenWidth = geometry.x() + geometry.width(); if (x + width > screenWidth) { x = screenWidth - width; } //foreach (StatusShow::Type type, allTypes_) { // if (statusEdit_->text() == P2QSTRING(statusShowTypeToFriendlyName(type))) { statusEdit_->setText(""); // } //} generateList(); height = menu_->sizeHintForRow(0) * menu_->count(); int marginLeft; int marginTop; int marginRight; int marginBottom; menu_->getContentsMargins(&marginLeft, &marginTop, &marginRight, &marginBottom); height += marginTop + marginBottom; width += marginLeft + marginRight; menu_->setGeometry(x, y, width, height); menu_->move(x, y); menu_->setMaximumWidth(width); menu_->show(); activateWindow(); statusEdit_->selectAll(); stack_->setCurrentIndex(1); statusEdit_->setFocus(); connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(handleApplicationFocusChanged(QWidget*, QWidget*)), Qt::QueuedConnection); } void QtStatusWidget::viewMode() { disconnect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(handleApplicationFocusChanged(QWidget*, QWidget*))); editing_ = false; menu_->hide(); stack_->setCurrentIndex(0); } void QtStatusWidget::handleEditComplete() { editing_ = false; statusText_ = newStatusText_; viewMode(); emit onChangeStatusRequest(selectedStatusType_, statusText_); statusCache_->addRecent(Q2PSTRING(statusText_), selectedStatusType_); } void QtStatusWidget::handleEditCancelled() { editing_ = false; setStatusText(statusText_); viewMode(); } StatusShow::Type QtStatusWidget::getSelectedStatusShow() { return selectedStatusType_; } void QtStatusWidget::handleItemClicked(QListWidgetItem* item) { editing_ = false; selectedStatusType_ = static_cast<StatusShow::Type>(item->data(Qt::UserRole).toInt()); QString message = item->data(Qt::DisplayRole).toString(); newStatusText_ = message == getNoMessage() ? "" : message; statusEdit_->setText(newStatusText_); handleEditComplete(); } void QtStatusWidget::setNewToolTip() { if (connecting_) { statusTextLabel_->setToolTip(tr("Connecting")); } else { statusTextLabel_->setToolTip(P2QSTRING(statusShowTypeToFriendlyName(selectedStatusType_)) + ": " + statusTextLabel_->text()); } } void QtStatusWidget::setStatusText(const QString& text) { connectingMovie_->stop(); statusText_ = text; statusEdit_->setText(text); QString escapedText(text.isEmpty() ? getNoMessage() : text); statusTextLabel_->setText(escapedText); setNewToolTip(); } void QtStatusWidget::setConnecting() { connecting_ = true; statusIcon_->setMovie(connectingMovie_); connectingMovie_->start(); setNewToolTip(); } void QtStatusWidget::setStatusType(StatusShow::Type type) { connecting_ = false; selectedStatusType_ = icons_.contains(type) ? type : StatusShow::Online; statusIcon_->setPixmap(icons_[selectedStatusType_].pixmap(16, 16)); setNewToolTip(); } QString QtStatusWidget::getNoMessage() { return QString(tr("(No message)")); } }