/*
* Copyright (c) 2010 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt 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)"));
}
}