diff options
Diffstat (limited to 'Swift/QtUI/Roster')
-rw-r--r-- | Swift/QtUI/Roster/DelegateCommons.cpp | 179 | ||||
-rw-r--r-- | Swift/QtUI/Roster/DelegateCommons.h | 48 | ||||
-rw-r--r-- | Swift/QtUI/Roster/GroupItemDelegate.cpp | 168 | ||||
-rw-r--r-- | Swift/QtUI/Roster/GroupItemDelegate.h | 32 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtFilterWidget.cpp | 218 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtFilterWidget.h | 60 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtOccupantListWidget.cpp | 80 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtOccupantListWidget.h | 28 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtRosterWidget.cpp | 227 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtRosterWidget.h | 24 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtTreeWidget.cpp | 322 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtTreeWidget.h | 102 | ||||
-rw-r--r-- | Swift/QtUI/Roster/RosterDelegate.cpp | 86 | ||||
-rw-r--r-- | Swift/QtUI/Roster/RosterDelegate.h | 44 | ||||
-rw-r--r-- | Swift/QtUI/Roster/RosterModel.cpp | 343 | ||||
-rw-r--r-- | Swift/QtUI/Roster/RosterModel.h | 102 | ||||
-rw-r--r-- | Swift/QtUI/Roster/RosterTooltip.cpp | 275 | ||||
-rw-r--r-- | Swift/QtUI/Roster/RosterTooltip.h | 10 | ||||
-rw-r--r-- | Swift/QtUI/Roster/main.cpp | 97 |
19 files changed, 1236 insertions, 1209 deletions
diff --git a/Swift/QtUI/Roster/DelegateCommons.cpp b/Swift/QtUI/Roster/DelegateCommons.cpp index 73cfbb5..e4a2f46 100644 --- a/Swift/QtUI/Roster/DelegateCommons.cpp +++ b/Swift/QtUI/Roster/DelegateCommons.cpp @@ -1,108 +1,111 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ -#include "DelegateCommons.h" +#include <Swift/QtUI/Roster/DelegateCommons.h> -#include <QtScaledAvatarCache.h> +#include <QColor> #include <QFileInfo> -namespace Swift { +#include <Swift/QtUI/QtScaledAvatarCache.h> +namespace Swift { void DelegateCommons::drawElidedText(QPainter* painter, const QRect& region, const QString& text, int flags) { - QString adjustedText(painter->fontMetrics().elidedText(text, Qt::ElideRight, region.width(), Qt::TextShowMnemonic)); - painter->setClipRect(region); - painter->drawText(region, flags, adjustedText.simplified()); - painter->setClipping(false); + QString adjustedText(painter->fontMetrics().elidedText(text, Qt::ElideRight, region.width(), Qt::TextShowMnemonic)); + painter->setClipRect(region); + painter->drawText(region, flags, adjustedText.simplified()); + painter->setClipping(false); } void DelegateCommons::paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QColor& nameColor, const QString& avatarPath, const QIcon& presenceIcon, const QString& name, const QString& statusText, bool isIdle, int unreadCount, bool compact) const { - painter->save(); - QRect fullRegion(option.rect); - if ( option.state & QStyle::State_Selected ) { - painter->fillRect(fullRegion, option.palette.highlight()); - painter->setPen(option.palette.highlightedText().color()); - } else { - painter->setPen(QPen(nameColor)); - } - - QRect presenceIconRegion(QPoint(farLeftMargin, fullRegion.top()), QSize(presenceIconWidth, fullRegion.height() - verticalMargin)); - - QRect idleIconRegion(QPoint(farLeftMargin, fullRegion.top()), QSize(presenceIconWidth*2, fullRegion.height() - verticalMargin)); - int calculatedAvatarSize = presenceIconRegion.height(); - //This overlaps the presenceIcon, so must be painted first - QRect avatarRegion(QPoint(presenceIconRegion.right() - presenceIconWidth / 2, presenceIconRegion.top()), QSize(calculatedAvatarSize, calculatedAvatarSize)); - - QPixmap avatarPixmap; - if (!compact && !avatarPath.isEmpty()) { - QString scaledAvatarPath = QtScaledAvatarCache(avatarRegion.height()).getScaledAvatarPath(avatarPath); - if (QFileInfo(scaledAvatarPath).exists()) { - avatarPixmap.load(scaledAvatarPath); - } - } - if (!compact && avatarPixmap.isNull()) { - avatarPixmap = QPixmap(":/icons/avatar.png").scaled(avatarRegion.height(), avatarRegion.width(), Qt::KeepAspectRatio, Qt::SmoothTransformation); - } - - if (!compact) { - painter->drawPixmap(avatarRegion.topLeft() + QPoint(((avatarRegion.width() - avatarPixmap.width()) / 2), (avatarRegion.height() - avatarPixmap.height()) / 2), avatarPixmap); - } - - //Paint the presence icon over the top of the avatar - presenceIcon.paint(painter, presenceIconRegion, Qt::AlignBottom | Qt::AlignHCenter); - - if (isIdle) { - idleIcon.paint(painter, idleIconRegion, Qt::AlignBottom | Qt::AlignHCenter); - } - - QFontMetrics nameMetrics(nameFont); - painter->setFont(nameFont); - int extraFontWidth = nameMetrics.width("H"); - int leftOffset = (compact ? presenceIconRegion : avatarRegion).right() + horizontalMargin * 2 + extraFontWidth / 2; - QRect textRegion(fullRegion.adjusted(leftOffset, 0, 0/*-leftOffset*/, 0)); - - int nameHeight = nameMetrics.height() + verticalMargin; - QRect nameRegion(textRegion.adjusted(0, verticalMargin, 0, 0)); - - DelegateCommons::drawElidedText(painter, nameRegion, name); - - if (!compact) { - painter->setFont(detailFont); - painter->setPen(QPen(QColor(160,160,160))); - - QRect statusTextRegion(textRegion.adjusted(0, nameHeight, 0, 0)); - DelegateCommons::drawElidedText(painter, statusTextRegion, statusText); - } - - if (unreadCount > 0) { - QRect unreadRect(fullRegion.right() - unreadCountSize - horizontalMargin, fullRegion.top() + (fullRegion.height() - unreadCountSize) / 2, unreadCountSize, unreadCountSize); - QPen pen(QColor("black")); - pen.setWidth(1); - painter->setRenderHint(QPainter::Antialiasing, true); - painter->setPen(pen); - painter->setBrush(QBrush(QColor("red"), Qt::SolidPattern)); - //painter->setBackgroundMode(Qt::OpaqueMode); - painter->drawEllipse(unreadRect); - painter->setBackgroundMode(Qt::TransparentMode); - painter->setPen(QColor("white")); - drawElidedText(painter, unreadRect, QString("%1").arg(unreadCount), Qt::AlignCenter); - } - - painter->restore(); + painter->save(); + QRect fullRegion(option.rect); + if ( option.state & QStyle::State_Selected ) { + painter->fillRect(fullRegion, option.palette.highlight()); + painter->setPen(option.palette.highlightedText().color()); + } else { + painter->setPen(QPen(nameColor)); + } + auto secondLineColor = painter->pen().color(); + secondLineColor.setAlphaF(0.7); + + QRect presenceIconRegion(QPoint(farLeftMargin, fullRegion.top()), QSize(presenceIconWidth, fullRegion.height() - verticalMargin)); + + QRect idleIconRegion(QPoint(farLeftMargin, fullRegion.top()), QSize(presenceIconWidth*2, fullRegion.height() - verticalMargin)); + int calculatedAvatarSize = presenceIconRegion.height(); + //This overlaps the presenceIcon, so must be painted first + QRect avatarRegion(QPoint(presenceIconRegion.right() - presenceIconWidth / 2, presenceIconRegion.top()), QSize(calculatedAvatarSize, calculatedAvatarSize)); + + QPixmap avatarPixmap; + if (!compact && !avatarPath.isEmpty()) { + QString scaledAvatarPath = QtScaledAvatarCache(avatarRegion.height()).getScaledAvatarPath(avatarPath); + if (QFileInfo(scaledAvatarPath).exists()) { + avatarPixmap.load(scaledAvatarPath); + } + } + if (!compact && avatarPixmap.isNull()) { + avatarPixmap = QPixmap(":/icons/avatar.svg").scaled(avatarRegion.height(), avatarRegion.width(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + + if (!compact) { + painter->drawPixmap(avatarRegion.topLeft() + QPoint(((avatarRegion.width() - avatarPixmap.width()) / 2), (avatarRegion.height() - avatarPixmap.height()) / 2), avatarPixmap); + } + + //Paint the presence icon over the top of the avatar + presenceIcon.paint(painter, presenceIconRegion, Qt::AlignBottom | Qt::AlignHCenter); + + if (isIdle) { + idleIcon.paint(painter, idleIconRegion, Qt::AlignBottom | Qt::AlignHCenter); + } + + QFontMetrics nameMetrics(nameFont); + painter->setFont(nameFont); + int extraFontWidth = nameMetrics.width("H"); + int leftOffset = (compact ? presenceIconRegion : avatarRegion).right() + horizontalMargin * 2 + extraFontWidth / 2; + QRect textRegion(fullRegion.adjusted(leftOffset, 0, 0/*-leftOffset*/, 0)); + + int nameHeight = nameMetrics.height() + verticalMargin; + QRect nameRegion(textRegion.adjusted(0, verticalMargin, 0, 0)); + + DelegateCommons::drawElidedText(painter, nameRegion, name); + + if (!compact) { + painter->setFont(detailFont); + painter->setPen(QPen(secondLineColor)); + + QRect statusTextRegion(textRegion.adjusted(0, nameHeight, 0, 0)); + DelegateCommons::drawElidedText(painter, statusTextRegion, statusText); + } + + if (unreadCount > 0) { + QRect unreadRect(fullRegion.right() - unreadCountSize - horizontalMargin, fullRegion.top() + (fullRegion.height() - unreadCountSize) / 2, unreadCountSize, unreadCountSize); + QPen pen(QColor("black")); + pen.setWidth(1); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->setPen(pen); + painter->setBrush(QBrush(QColor("red"), Qt::SolidPattern)); + //painter->setBackgroundMode(Qt::OpaqueMode); + painter->drawEllipse(unreadRect); + painter->setBackgroundMode(Qt::TransparentMode); + painter->setPen(QColor("white")); + drawElidedText(painter, unreadRect, QString("%1").arg(unreadCount), Qt::AlignCenter); + } + + painter->restore(); } QSize DelegateCommons::contactSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/, bool compact ) const { - int heightByAvatar = (compact ? presenceIconHeight : avatarSize) + verticalMargin * 2; - QFontMetrics nameMetrics(nameFont); - QFontMetrics statusMetrics(detailFont); - int sizeByText = 2 * verticalMargin + nameMetrics.height() + (compact ? 0 : statusMetrics.height()); - //Doesn't work, yay! FIXME: why? - //QSize size = (option.state & QStyle::State_Selected) ? QSize(150, 80) : QSize(150, avatarSize_ + margin_ * 2); - //qDebug() << "Returning size" << size; - return QSize(150, sizeByText > heightByAvatar ? sizeByText : heightByAvatar); + int heightByAvatar = (compact ? presenceIconHeight : avatarSize) + verticalMargin * 2; + QFontMetrics nameMetrics(nameFont); + QFontMetrics statusMetrics(detailFont); + int sizeByText = 2 * verticalMargin + nameMetrics.height() + (compact ? 0 : statusMetrics.height()); + //Doesn't work, yay! FIXME: why? + //QSize size = (option.state & QStyle::State_Selected) ? QSize(150, 80) : QSize(150, avatarSize_ + margin_ * 2); + //qDebug() << "Returning size" << size; + return QSize(150, sizeByText > heightByAvatar ? sizeByText : heightByAvatar); } const int DelegateCommons::horizontalMargin = 2; diff --git a/Swift/QtUI/Roster/DelegateCommons.h b/Swift/QtUI/Roster/DelegateCommons.h index 084d41f..74b08f2 100644 --- a/Swift/QtUI/Roster/DelegateCommons.h +++ b/Swift/QtUI/Roster/DelegateCommons.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,36 +8,36 @@ #include <QApplication> #include <QFont> +#include <QIcon> #include <QPainter> #include <QRect> #include <QString> -#include <QIcon> #include <QStyleOptionViewItem> namespace Swift { - class DelegateCommons { - public: - DelegateCommons() : nameFont(QApplication::font()), detailFont(QApplication::font()), idleIcon(QIcon(":/icons/zzz.png")) { - detailFontSizeDrop = nameFont.pointSize() >= 10 ? 2 : 0; - detailFont.setStyle(QFont::StyleItalic); - detailFont.setPointSize(nameFont.pointSize() - detailFontSizeDrop); - } + class DelegateCommons { + public: + DelegateCommons() : nameFont(QApplication::font()), detailFont(QApplication::font()), idleIcon(QIcon(":/icons/zzz.png")) { + detailFontSizeDrop = nameFont.pointSize() >= 10 ? 2 : 0; + detailFont.setStyle(QFont::StyleItalic); + detailFont.setPointSize(nameFont.pointSize() - detailFontSizeDrop); + } - static void drawElidedText(QPainter* painter, const QRect& region, const QString& text, int flags = Qt::AlignTop); + static void drawElidedText(QPainter* painter, const QRect& region, const QString& text, int flags = Qt::AlignTop); - QSize contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index, bool compact) const; - void paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QColor& nameColor, const QString& avatarPath, const QIcon& presenceIcon, const QString& name, const QString& statusText, bool isIdle, int unreadCount, bool compact) const; + QSize contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index, bool compact) const; + void paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QColor& nameColor, const QString& avatarPath, const QIcon& presenceIcon, const QString& name, const QString& statusText, bool isIdle, int unreadCount, bool compact) const; - int detailFontSizeDrop; - QFont nameFont; - QFont detailFont; - static const int horizontalMargin; - static const int verticalMargin; - static const int farLeftMargin; - static const int avatarSize; - static const int presenceIconHeight; - static const int presenceIconWidth; - static const int unreadCountSize; - QIcon idleIcon; - }; + int detailFontSizeDrop; + QFont nameFont; + QFont detailFont; + static const int horizontalMargin; + static const int verticalMargin; + static const int farLeftMargin; + static const int avatarSize; + static const int presenceIconHeight; + static const int presenceIconWidth; + static const int unreadCountSize; + QIcon idleIcon; + }; } diff --git a/Swift/QtUI/Roster/GroupItemDelegate.cpp b/Swift/QtUI/Roster/GroupItemDelegate.cpp index a9942f8..0356aa0 100644 --- a/Swift/QtUI/Roster/GroupItemDelegate.cpp +++ b/Swift/QtUI/Roster/GroupItemDelegate.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ -#include "GroupItemDelegate.h" +#include <Swift/QtUI/Roster/GroupItemDelegate.h> #include <QPainter> #include <QPen> @@ -13,100 +13,100 @@ namespace Swift { GroupItemDelegate::GroupItemDelegate() : groupFont_(QApplication::font()) { - groupFont_.setPointSize(common_.nameFont.pointSize() - common_.detailFontSizeDrop); - groupFont_.setWeight(QFont::Bold); + groupFont_.setPointSize(common_.nameFont.pointSize() - common_.detailFontSizeDrop); + groupFont_.setWeight(QFont::Bold); } QSize GroupItemDelegate::sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const { - QFontMetrics groupMetrics(groupFont_); - return QSize(150, groupMetrics.height() + common_.verticalMargin + 2); + QFontMetrics groupMetrics(groupFont_); + return QSize(150, groupMetrics.height() + common_.verticalMargin + 2); } void GroupItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QString& name, int rowCount, bool expanded) const { - painter->save(); - painter->setPen(QPen(QColor(189, 189, 189))); - //FIXME: It looks like Qt is passing us a rectangle that's too small - //This deliberately draws outside the lines, and we need to find a better solution. - int correctionAmount = groupCornerRadius_ > 0 ? 0 : 1; - QRect region(QPoint(option.rect.left() - correctionAmount, option.rect.top()), QSize(option.rect.width() + correctionAmount, option.rect.height() - common_.verticalMargin)); - QLinearGradient fillGradient(region.topLeft(), region.bottomLeft()); - fillGradient.setColorAt(0, QColor(244, 244, 244)); - fillGradient.setColorAt(0.1, QColor(231, 231, 231)); - fillGradient.setColorAt(1, QColor(209, 209, 209)); - - QBrush backgroundBrush = QBrush(fillGradient); - QPainterPath fillPath; - fillPath.addRoundedRect(region, groupCornerRadius_, groupCornerRadius_); - QPainterPath linePath; - linePath.addRoundedRect(region, groupCornerRadius_, groupCornerRadius_); - painter->fillPath(fillPath, backgroundBrush); - painter->drawPath(linePath); - - int triangleHorizontalOffset = 1; - int triangleWidth = 9; - int triangleHeight = 5; - paintExpansionTriangle(painter, region.adjusted(common_.horizontalMargin + triangleHorizontalOffset + 1, 0, 0, 0), triangleWidth, triangleHeight, expanded); - - int textLeftOffset = 3 * common_.horizontalMargin + 1 + triangleWidth + triangleHorizontalOffset; - QFontMetrics fontMetrics(groupFont_); - int textTopOffset = (region.height() - fontMetrics.height()) / 2; - painter->setFont(groupFont_); - int contactCountWidth = 0; - QRect textRect = region.adjusted(textLeftOffset, textTopOffset, -1 * textLeftOffset, -1 * textTopOffset); - - if (!expanded) { - QFontMetrics groupMetrics(groupFont_); - int contactCount = rowCount; - QString countString = QString("%1").arg(contactCount); - contactCountWidth = groupMetrics.width(countString) + 2 * common_.horizontalMargin; - int offsetAmount = textRect.width() - contactCountWidth + common_.horizontalMargin; - QRect countRect = textRect.adjusted(offsetAmount, 0, 0/*-1 * offsetAmount*/, 0); - paintShadowText(painter, countRect, countString); - } - QRect nameTextRect = expanded ? textRect : textRect.adjusted(0, 0, -contactCountWidth, 0); - QString elidedName = fontMetrics.elidedText(name, Qt::ElideRight, nameTextRect.width(), Qt::TextShowMnemonic); - paintShadowText(painter, nameTextRect, elidedName); - painter->restore(); + painter->save(); + painter->setPen(QPen(QColor(189, 189, 189))); + //FIXME: It looks like Qt is passing us a rectangle that's too small + //This deliberately draws outside the lines, and we need to find a better solution. + int correctionAmount = groupCornerRadius_ > 0 ? 0 : 1; + QRect region(QPoint(option.rect.left() - correctionAmount, option.rect.top()), QSize(option.rect.width() + correctionAmount, option.rect.height() - common_.verticalMargin)); + QLinearGradient fillGradient(region.topLeft(), region.bottomLeft()); + fillGradient.setColorAt(0, QColor(244, 244, 244)); + fillGradient.setColorAt(0.1, QColor(231, 231, 231)); + fillGradient.setColorAt(1, QColor(209, 209, 209)); + + QBrush backgroundBrush = QBrush(fillGradient); + QPainterPath fillPath; + fillPath.addRoundedRect(region, groupCornerRadius_, groupCornerRadius_); + QPainterPath linePath; + linePath.addRoundedRect(region, groupCornerRadius_, groupCornerRadius_); + painter->fillPath(fillPath, backgroundBrush); + painter->drawPath(linePath); + + int triangleHorizontalOffset = 1; + int triangleWidth = 9; + int triangleHeight = 5; + paintExpansionTriangle(painter, region.adjusted(common_.horizontalMargin + triangleHorizontalOffset + 1, 0, 0, 0), triangleWidth, triangleHeight, expanded); + + int textLeftOffset = 3 * common_.horizontalMargin + 1 + triangleWidth + triangleHorizontalOffset; + QFontMetrics fontMetrics(groupFont_); + int textTopOffset = (region.height() - fontMetrics.height()) / 2; + painter->setFont(groupFont_); + int contactCountWidth = 0; + QRect textRect = region.adjusted(textLeftOffset, textTopOffset, -1 * textLeftOffset, -1 * textTopOffset); + + if (!expanded) { + QFontMetrics groupMetrics(groupFont_); + int contactCount = rowCount; + QString countString = QString("%1").arg(contactCount); + contactCountWidth = groupMetrics.width(countString) + 2 * common_.horizontalMargin; + int offsetAmount = textRect.width() - contactCountWidth + common_.horizontalMargin; + QRect countRect = textRect.adjusted(offsetAmount, 0, 0/*-1 * offsetAmount*/, 0); + paintShadowText(painter, countRect, countString); + } + QRect nameTextRect = expanded ? textRect : textRect.adjusted(0, 0, -contactCountWidth, 0); + QString elidedName = fontMetrics.elidedText(name, Qt::ElideRight, nameTextRect.width(), Qt::TextShowMnemonic); + paintShadowText(painter, nameTextRect, elidedName); + painter->restore(); } void GroupItemDelegate::paintExpansionTriangle(QPainter* painter, const QRect& region, int width, int height, bool expanded) const { - // height is the height of the downward pointing triangle - QPolygonF triangle; - if (expanded) { - QPointF triangleTopLeft(region.left(), region.top() + region.height() / 2 - height / 2); - triangle << triangleTopLeft; - triangle << triangleTopLeft + QPointF(width, 0); - triangle << triangleTopLeft + QPointF(width / 2, height); - // The expanded triangle should be a little lower, because its pointy shape makes it feel - // as if it's too high. - triangle.translate(QPointF(0,1)); - } - else { - QPointF triangleTopLeft(region.left() + ((width - height) / 2), region.top() + region.height() / 2 - width / 2); - triangle << triangleTopLeft; - triangle << triangleTopLeft + QPointF(height, width / 2); - triangle << triangleTopLeft + QPointF(0, width); - } - //qDebug() << "Painting triangle: " << triangle; - - QPolygonF triangleShadow(triangle); - triangleShadow.translate(QPointF(0, -1)); - - QPainterPath trianglePath; - QPainterPath triangleShadowPath; - QBrush triangleBrush(QColor(110, 110, 110)); - QBrush triangleShadowBrush(QColor(47, 47, 47)); - trianglePath.addPolygon(triangle); - triangleShadowPath.addPolygon(triangleShadow); - painter->fillPath(triangleShadowPath, triangleShadowBrush); - painter->fillPath(trianglePath, triangleBrush); + // height is the height of the downward pointing triangle + QPolygonF triangle; + if (expanded) { + QPointF triangleTopLeft(region.left(), region.top() + region.height() / 2 - height / 2); + triangle << triangleTopLeft; + triangle << triangleTopLeft + QPointF(width, 0); + triangle << triangleTopLeft + QPointF(width / 2, height); + // The expanded triangle should be a little lower, because its pointy shape makes it feel + // as if it's too high. + triangle.translate(QPointF(0,1)); + } + else { + QPointF triangleTopLeft(region.left() + ((width - height) / 2), region.top() + region.height() / 2 - width / 2); + triangle << triangleTopLeft; + triangle << triangleTopLeft + QPointF(height, width / 2); + triangle << triangleTopLeft + QPointF(0, width); + } + //qDebug() << "Painting triangle: " << triangle; + + QPolygonF triangleShadow(triangle); + triangleShadow.translate(QPointF(0, -1)); + + QPainterPath trianglePath; + QPainterPath triangleShadowPath; + QBrush triangleBrush(QColor(110, 110, 110)); + QBrush triangleShadowBrush(QColor(47, 47, 47)); + trianglePath.addPolygon(triangle); + triangleShadowPath.addPolygon(triangleShadow); + painter->fillPath(triangleShadowPath, triangleShadowBrush); + painter->fillPath(trianglePath, triangleBrush); } void GroupItemDelegate::paintShadowText(QPainter* painter, const QRect& region, const QString& text) const { - painter->setPen(QPen(QColor(254, 254, 254))); - painter->drawText(region.adjusted(0, 1, 0, 0), Qt::AlignTop, text); - painter->setPen(QPen(QColor(115, 115, 115))); - painter->drawText(region, Qt::AlignTop, text); + painter->setPen(QPen(QColor(254, 254, 254))); + painter->drawText(region.adjusted(0, 1, 0, 0), Qt::AlignTop, text); + painter->setPen(QPen(QColor(115, 115, 115))); + painter->drawText(region, Qt::AlignTop, text); } const int GroupItemDelegate::groupCornerRadius_ = 0; diff --git a/Swift/QtUI/Roster/GroupItemDelegate.h b/Swift/QtUI/Roster/GroupItemDelegate.h index 859f3ec..f989ed0 100644 --- a/Swift/QtUI/Roster/GroupItemDelegate.h +++ b/Swift/QtUI/Roster/GroupItemDelegate.h @@ -1,29 +1,29 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once -#include <QStyledItemDelegate> #include <QColor> #include <QFont> +#include <QStyledItemDelegate> -#include "DelegateCommons.h" +#include <Swift/QtUI/Roster/DelegateCommons.h> namespace Swift { - class QtTreeWidgetItem; - class GroupItemDelegate { - public: - GroupItemDelegate(); - QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; - void paint(QPainter* painter, const QStyleOptionViewItem& option, const QString& name, int rowCount, bool expanded) const; - private: - void paintShadowText(QPainter* painter, const QRect& region, const QString& text) const; - void paintExpansionTriangle(QPainter* painter, const QRect& region, int width, int height, bool expanded) const; - QFont groupFont_; - static const int groupCornerRadius_; - DelegateCommons common_; - }; + class QtTreeWidgetItem; + class GroupItemDelegate { + public: + GroupItemDelegate(); + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QString& name, int rowCount, bool expanded) const; + private: + void paintShadowText(QPainter* painter, const QRect& region, const QString& text) const; + void paintExpansionTriangle(QPainter* painter, const QRect& region, int width, int height, bool expanded) const; + QFont groupFont_; + static const int groupCornerRadius_; + DelegateCommons common_; + }; } diff --git a/Swift/QtUI/Roster/QtFilterWidget.cpp b/Swift/QtUI/Roster/QtFilterWidget.cpp index acfd50f..2e1ead9 100644 --- a/Swift/QtUI/Roster/QtFilterWidget.cpp +++ b/Swift/QtUI/Roster/QtFilterWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Isode Limited. + * Copyright (c) 2014-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -10,6 +10,8 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +#include <Swift/QtUI/Roster/QtFilterWidget.h> + #include <QEvent> #include <QKeyEvent> #include <QLayout> @@ -18,31 +20,31 @@ #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> + #include <Swift/QtUI/QtClosableLineEdit.h> #include <Swift/QtUI/QtSwiftUtil.h> -#include <Swift/QtUI/Roster/QtFilterWidget.h> namespace Swift { -QtFilterWidget::QtFilterWidget(QWidget* parent, QtTreeWidget* treeView, UIEventStream* eventStream, QBoxLayout* layout) : QWidget(parent), treeView_(treeView), eventStream_(eventStream), fuzzyRosterFilter_(0), isModifierSinglePressed_(false) { - int targetIndex = layout->indexOf(treeView); +QtFilterWidget::QtFilterWidget(QWidget* parent, QtTreeWidget* treeView, UIEventStream* eventStream, QBoxLayout* layout) : QWidget(parent), treeView_(treeView), eventStream_(eventStream), fuzzyRosterFilter_(nullptr), isModifierSinglePressed_(false) { + int targetIndex = layout->indexOf(treeView); - QVBoxLayout* vboxLayout = new QVBoxLayout(this); - vboxLayout->setSpacing(0); - vboxLayout->setContentsMargins(0,0,0,0); + QVBoxLayout* vboxLayout = new QVBoxLayout(this); + vboxLayout->setSpacing(0); + vboxLayout->setContentsMargins(0,0,0,0); - filterLineEdit_ = new QtClosableLineEdit(this); - filterLineEdit_->hide(); - vboxLayout->addWidget(filterLineEdit_); + filterLineEdit_ = new QtClosableLineEdit(this); + filterLineEdit_->hide(); + vboxLayout->addWidget(filterLineEdit_); - vboxLayout->addWidget(treeView); - setLayout(vboxLayout); - layout->insertWidget(targetIndex, this); + vboxLayout->addWidget(treeView); + setLayout(vboxLayout); + layout->insertWidget(targetIndex, this); - filterLineEdit_->installEventFilter(this); - treeView->installEventFilter(this); + filterLineEdit_->installEventFilter(this); + treeView->installEventFilter(this); - sourceModel_ = treeView_->model(); + sourceModel_ = treeView_->model(); } QtFilterWidget::~QtFilterWidget() { @@ -50,118 +52,118 @@ QtFilterWidget::~QtFilterWidget() { } bool QtFilterWidget::eventFilter(QObject*, QEvent* event) { - if (event->type() == QEvent::KeyPress || - event->type() == QEvent::KeyRelease || - // InputMethodQuery got introduced in Qt 5. + if (event->type() == QEvent::KeyPress || + event->type() == QEvent::KeyRelease || + // InputMethodQuery got introduced in Qt 5. #if QT_VERSION >= 0x050000 - event->type() == QEvent::InputMethodQuery || + event->type() == QEvent::InputMethodQuery || #endif - event->type() == QEvent::InputMethod) { - event->ignore(); - QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event); - if (keyEvent) { - if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) { - return false; - } else if ((keyEvent->key() == Qt::Key_Left || keyEvent->key() == Qt::Key_Right) && filterLineEdit_->text().isEmpty()) { - return false; - } else if (keyEvent->key() == Qt::Key_Alt && event->type() == QEvent::KeyPress) { - isModifierSinglePressed_ = true; - } else if ((keyEvent->key() == Qt::Key_Alt && event->type() == QEvent::KeyRelease && isModifierSinglePressed_) - || (keyEvent->key() == Qt::Key_Menu)) { - QPoint itemOffset(2,2); - QPoint contextMenuPosition = treeView_->visualRect(treeView_->currentIndex()).topLeft() + itemOffset;; - QApplication::postEvent(treeView_, new QContextMenuEvent(QContextMenuEvent::Keyboard, contextMenuPosition, treeView_->mapToGlobal(contextMenuPosition))); - return true; - } else if (keyEvent->key() == Qt::Key_Return) { - JID target = treeView_->selectedJID(); - if (target.isValid()) { - eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(target))); - } - filterLineEdit_->setText(""); - updateRosterFilters(); - } else if (keyEvent->key() == Qt::Key_Escape) { - filterLineEdit_->setText(""); - } else { - isModifierSinglePressed_ = false; - } - } - - filterLineEdit_->event(event); - - if (event->type() == QEvent::KeyRelease) { - updateRosterFilters(); - } - return true; - } - return false; + event->type() == QEvent::InputMethod) { + event->ignore(); + QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event); + if (keyEvent) { + if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) { + return false; + } else if ((keyEvent->key() == Qt::Key_Left || keyEvent->key() == Qt::Key_Right) && filterLineEdit_->text().isEmpty()) { + return false; + } else if (keyEvent->key() == Qt::Key_Alt && event->type() == QEvent::KeyPress) { + isModifierSinglePressed_ = true; + } else if ((keyEvent->key() == Qt::Key_Alt && event->type() == QEvent::KeyRelease && isModifierSinglePressed_) + || (keyEvent->key() == Qt::Key_Menu)) { + QPoint itemOffset(2,2); + QPoint contextMenuPosition = treeView_->visualRect(treeView_->currentIndex()).topLeft() + itemOffset;; + QApplication::postEvent(treeView_, new QContextMenuEvent(QContextMenuEvent::Keyboard, contextMenuPosition, treeView_->mapToGlobal(contextMenuPosition))); + return true; + } else if (keyEvent->key() == Qt::Key_Return) { + JID target = treeView_->selectedJID(); + if (target.isValid()) { + eventStream_->send(std::make_shared<RequestChatUIEvent>(target)); + } + filterLineEdit_->setText(""); + updateRosterFilters(); + } else if (keyEvent->key() == Qt::Key_Escape) { + filterLineEdit_->setText(""); + } else { + isModifierSinglePressed_ = false; + } + } + + filterLineEdit_->event(event); + + if (event->type() == QEvent::KeyRelease) { + updateRosterFilters(); + } + return true; + } + return false; } void QtFilterWidget::popAllFilters() { - std::vector<RosterFilter*> filters = treeView_->getRoster()->getFilters(); - foreach(RosterFilter* filter, filters) { - filters_.push_back(filter); - treeView_->getRoster()->removeFilter(filter); - } - treeView_->getRoster()->onFilterAdded.connect(boost::bind(&QtFilterWidget::handleFilterAdded, this, _1)); - treeView_->getRoster()->onFilterRemoved.connect(boost::bind(&QtFilterWidget::handleFilterRemoved, this, _1)); + std::vector<RosterFilter*> filters = treeView_->getRoster()->getFilters(); + for (auto filter : filters) { + filters_.push_back(filter); + treeView_->getRoster()->removeFilter(filter); + } + treeView_->getRoster()->onFilterAdded.connect(boost::bind(&QtFilterWidget::handleFilterAdded, this, _1)); + treeView_->getRoster()->onFilterRemoved.connect(boost::bind(&QtFilterWidget::handleFilterRemoved, this, _1)); } void QtFilterWidget::pushAllFilters() { - treeView_->getRoster()->onFilterAdded.disconnect(boost::bind(&QtFilterWidget::handleFilterAdded, this, _1)); - treeView_->getRoster()->onFilterRemoved.disconnect(boost::bind(&QtFilterWidget::handleFilterRemoved, this, _1)); - foreach(RosterFilter* filter, filters_) { - treeView_->getRoster()->addFilter(filter); - } - filters_.clear(); + treeView_->getRoster()->onFilterAdded.disconnect(boost::bind(&QtFilterWidget::handleFilterAdded, this, _1)); + treeView_->getRoster()->onFilterRemoved.disconnect(boost::bind(&QtFilterWidget::handleFilterRemoved, this, _1)); + for (auto filter : filters_) { + treeView_->getRoster()->addFilter(filter); + } + filters_.clear(); } void QtFilterWidget::updateRosterFilters() { - if (fuzzyRosterFilter_) { - if (filterLineEdit_->text().isEmpty()) { - // remove currently installed search filter and put old filters back - treeView_->getRoster()->removeFilter(fuzzyRosterFilter_); - delete fuzzyRosterFilter_; - fuzzyRosterFilter_ = NULL; - pushAllFilters(); - } else { - // remove currently intsalled search filter and put new search filter in place - updateSearchFilter(); - } - } else { - if (!filterLineEdit_->text().isEmpty()) { - // remove currently installed filters and put a search filter in place - popAllFilters(); - updateSearchFilter(); - } - } - filterLineEdit_->setVisible(!filterLineEdit_->text().isEmpty()); + if (fuzzyRosterFilter_) { + if (filterLineEdit_->text().isEmpty()) { + // remove currently installed search filter and put old filters back + treeView_->getRoster()->removeFilter(fuzzyRosterFilter_); + delete fuzzyRosterFilter_; + fuzzyRosterFilter_ = nullptr; + pushAllFilters(); + } else { + // remove currently intsalled search filter and put new search filter in place + updateSearchFilter(); + } + } else { + if (!filterLineEdit_->text().isEmpty()) { + // remove currently installed filters and put a search filter in place + popAllFilters(); + updateSearchFilter(); + } + } + filterLineEdit_->setVisible(!filterLineEdit_->text().isEmpty()); } void QtFilterWidget::updateSearchFilter() { - if (fuzzyRosterFilter_) { - treeView_->getRoster()->removeFilter(fuzzyRosterFilter_); - delete fuzzyRosterFilter_; - fuzzyRosterFilter_ = NULL; - } - fuzzyRosterFilter_ = new FuzzyRosterFilter(Q2PSTRING(filterLineEdit_->text())); - treeView_->getRoster()->addFilter(fuzzyRosterFilter_); - treeView_->setCurrentIndex(sourceModel_->index(0, 0, sourceModel_->index(0,0))); + if (fuzzyRosterFilter_) { + treeView_->getRoster()->removeFilter(fuzzyRosterFilter_); + delete fuzzyRosterFilter_; + fuzzyRosterFilter_ = nullptr; + } + fuzzyRosterFilter_ = new FuzzyRosterFilter(Q2PSTRING(filterLineEdit_->text())); + treeView_->getRoster()->addFilter(fuzzyRosterFilter_); + treeView_->setCurrentIndex(sourceModel_->index(0, 0, sourceModel_->index(0,0))); } void QtFilterWidget::handleFilterAdded(RosterFilter* filter) { - if (filter != fuzzyRosterFilter_) { - filterLineEdit_->setText(""); - updateRosterFilters(); - } + if (filter != fuzzyRosterFilter_) { + filterLineEdit_->setText(""); + updateRosterFilters(); + } } void QtFilterWidget::handleFilterRemoved(RosterFilter* filter) { - /* make sure we don't end up adding this one back in later */ - filters_.erase(std::remove(filters_.begin(), filters_.end(), filter), filters_.end()); - if (filter != fuzzyRosterFilter_) { - filterLineEdit_->setText(""); - updateRosterFilters(); - } + /* make sure we don't end up adding this one back in later */ + filters_.erase(std::remove(filters_.begin(), filters_.end(), filter), filters_.end()); + if (filter != fuzzyRosterFilter_) { + filterLineEdit_->setText(""); + updateRosterFilters(); + } } } diff --git a/Swift/QtUI/Roster/QtFilterWidget.h b/Swift/QtUI/Roster/QtFilterWidget.h index d0307ea..ea3c325 100644 --- a/Swift/QtUI/Roster/QtFilterWidget.h +++ b/Swift/QtUI/Roster/QtFilterWidget.h @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #pragma once #include <vector> @@ -11,8 +17,8 @@ #include <QBoxLayout> #include <QWidget> -#include <Swift/Controllers/Roster/RosterFilter.h> #include <Swift/Controllers/Roster/FuzzyRosterFilter.h> +#include <Swift/Controllers/Roster/RosterFilter.h> #include <Swift/QtUI/Roster/QtTreeWidget.h> @@ -20,32 +26,32 @@ namespace Swift { class UIEventStream; class QtClosableLineEdit; class QtFilterWidget : public QWidget { - Q_OBJECT - public: - QtFilterWidget(QWidget* parent, QtTreeWidget* treeView, UIEventStream* eventStream, QBoxLayout* layout = 0); - virtual ~QtFilterWidget(); - - protected: - bool eventFilter(QObject*, QEvent* event); - - private: - void popAllFilters(); - void pushAllFilters(); - - void updateRosterFilters(); - void updateSearchFilter(); - - void handleFilterAdded(RosterFilter* filter); - void handleFilterRemoved(RosterFilter* filter); - - private: - QtClosableLineEdit* filterLineEdit_; - QtTreeWidget* treeView_; - UIEventStream* eventStream_; - std::vector<RosterFilter*> filters_; - QAbstractItemModel* sourceModel_; - FuzzyRosterFilter* fuzzyRosterFilter_; - bool isModifierSinglePressed_; + Q_OBJECT + public: + QtFilterWidget(QWidget* parent, QtTreeWidget* treeView, UIEventStream* eventStream, QBoxLayout* layout = nullptr); + virtual ~QtFilterWidget(); + + protected: + bool eventFilter(QObject*, QEvent* event); + + private: + void popAllFilters(); + void pushAllFilters(); + + void updateRosterFilters(); + void updateSearchFilter(); + + void handleFilterAdded(RosterFilter* filter); + void handleFilterRemoved(RosterFilter* filter); + + private: + QtClosableLineEdit* filterLineEdit_; + QtTreeWidget* treeView_; + UIEventStream* eventStream_; + std::vector<RosterFilter*> filters_; + QAbstractItemModel* sourceModel_; + FuzzyRosterFilter* fuzzyRosterFilter_; + bool isModifierSinglePressed_; }; } diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp index 4d7a543..a12863d 100644 --- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp +++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 Isode Limited. + * Copyright (c) 2011-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -7,10 +7,10 @@ #include <Swift/QtUI/Roster/QtOccupantListWidget.h> -#include <QContextMenuEvent> -#include <QMenu> #include <QAction> +#include <QContextMenuEvent> #include <QInputDialog> +#include <QMenu> #include <Swift/Controllers/Roster/ContactRosterItem.h> #include <Swift/Controllers/Roster/GroupRosterItem.h> @@ -29,47 +29,47 @@ QtOccupantListWidget::~QtOccupantListWidget() { } void QtOccupantListWidget::setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions) { - availableOccupantActions_ = actions; + availableOccupantActions_ = actions; } void QtOccupantListWidget::contextMenuEvent(QContextMenuEvent* event) { - QModelIndex index = indexAt(event->pos()); - if (!index.isValid()) { - return; - } + QModelIndex index = indexAt(event->pos()); + if (!index.isValid()) { + return; + } - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - if (contact) { - onSomethingSelectedChanged(contact); - QMenu contextMenu; - if (availableOccupantActions_.empty()) { - QAction* noAction = contextMenu.addAction(tr("No actions for this user")); - noAction->setEnabled(false); - contextMenu.exec(event->globalPos()); - } - else { - std::map<QAction*, ChatWindow::OccupantAction> actions; - foreach (ChatWindow::OccupantAction availableAction, availableOccupantActions_) { - QString text = "Error: missing string"; - switch (availableAction) { - case ChatWindow::Kick: text = tr("Kick user"); break; - case ChatWindow::Ban: text = tr("Kick and ban user"); break; - case ChatWindow::MakeModerator: text = tr("Make moderator"); break; - case ChatWindow::MakeParticipant: text = tr("Make participant"); break; - case ChatWindow::MakeVisitor: text = tr("Remove voice"); break; - case ChatWindow::AddContact: text = tr("Add to contacts"); break; - case ChatWindow::ShowProfile: text = tr("Show profile"); break; - } - QAction* action = contextMenu.addAction(text); - actions[action] = availableAction; - } - QAction* result = contextMenu.exec(event->globalPos()); - if (result) { - onOccupantActionSelected(actions[result], contact); - } - } - } + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (contact) { + onSomethingSelectedChanged(contact); + QMenu contextMenu; + if (availableOccupantActions_.empty()) { + QAction* noAction = contextMenu.addAction(tr("No actions for this user")); + noAction->setEnabled(false); + contextMenu.exec(event->globalPos()); + } + else { + std::map<QAction*, ChatWindow::OccupantAction> actions; + for (const auto& availableAction : availableOccupantActions_) { + QString text = "Error: missing string"; + switch (availableAction) { + case ChatWindow::Kick: text = tr("Kick user"); break; + case ChatWindow::Ban: text = tr("Kick and ban user"); break; + case ChatWindow::MakeModerator: text = tr("Make moderator"); break; + case ChatWindow::MakeParticipant: text = tr("Make participant"); break; + case ChatWindow::MakeVisitor: text = tr("Remove voice"); break; + case ChatWindow::AddContact: text = tr("Add to contacts"); break; + case ChatWindow::ShowProfile: text = tr("Show profile"); break; + } + QAction* action = contextMenu.addAction(text); + actions[action] = availableAction; + } + QAction* result = contextMenu.exec(event->globalPos()); + if (result) { + onOccupantActionSelected(actions[result], contact); + } + } + } } } diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.h b/Swift/QtUI/Roster/QtOccupantListWidget.h index 645c21a..0f80943 100644 --- a/Swift/QtUI/Roster/QtOccupantListWidget.h +++ b/Swift/QtUI/Roster/QtOccupantListWidget.h @@ -1,31 +1,31 @@ /* - * Copyright (c) 2011-2014 Isode Limited. + * Copyright (c) 2011-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once -#include <Swift/QtUI/Roster/QtTreeWidget.h> - -#include <Swiften/Base/boost_bsignals.h> +#include <boost/signals2.hpp> #include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/QtUI/Roster/QtTreeWidget.h> + namespace Swift { class SettingsProvider; class QtOccupantListWidget : public QtTreeWidget { - Q_OBJECT - public: - QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget privateMessageTarget, QWidget* parent = NULL); - virtual ~QtOccupantListWidget(); - void setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions); - boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected; - protected: - void contextMenuEvent(QContextMenuEvent* event); - private: - std::vector<ChatWindow::OccupantAction> availableOccupantActions_; + Q_OBJECT + public: + QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget privateMessageTarget, QWidget* parent = nullptr); + virtual ~QtOccupantListWidget(); + void setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions); + boost::signals2::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected; + protected: + void contextMenuEvent(QContextMenuEvent* event); + private: + std::vector<ChatWindow::OccupantAction> availableOccupantActions_; }; } diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp index bef8635..935d6f6 100644 --- a/Swift/QtUI/Roster/QtRosterWidget.cpp +++ b/Swift/QtUI/Roster/QtRosterWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 Isode Limited. + * Copyright (c) 2011-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -7,23 +7,24 @@ #include <Swift/QtUI/Roster/QtRosterWidget.h> #include <QContextMenuEvent> +#include <QFileDialog> +#include <QInputDialog> #include <QMenu> #include <QMessageBox> -#include <QInputDialog> -#include <QFileDialog> #include <QPushButton> -#include <Swift/Controllers/UIEvents/RequestContactEditorUIEvent.h> +#include <Swift/Controllers/Roster/ContactRosterItem.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> #include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h> #include <Swift/Controllers/UIEvents/RenameGroupUIEvent.h> -#include <Swift/Controllers/UIEvents/SendFileUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestContactEditorUIEvent.h> #include <Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h> +#include <Swift/Controllers/UIEvents/SendFileUIEvent.h> #include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h> -#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h> -#include <Swift/QtUI/QtContactEditWindow.h> -#include <Swift/Controllers/Roster/ContactRosterItem.h> -#include <Swift/Controllers/Roster/GroupRosterItem.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> + +#include <Swift/QtUI/QtContactEditWindow.h> #include <Swift/QtUI/QtSwiftUtil.h> namespace Swift { @@ -37,125 +38,125 @@ QtRosterWidget::~QtRosterWidget() { } void QtRosterWidget::handleEditUserActionTriggered(bool /*checked*/) { - QModelIndexList selectedIndexList = getSelectedIndexes(); - if (selectedIndexList.empty()) { - return; - } - QModelIndex index = selectedIndexList[0]; - if (!index.isValid()) { - return; - } - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { - eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID())); - } + QModelIndexList selectedIndexList = getSelectedIndexes(); + if (selectedIndexList.empty()) { + return; + } + QModelIndex index = selectedIndexList[0]; + if (!index.isValid()) { + return; + } + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { + eventStream_->send(std::make_shared<RequestContactEditorUIEvent>(contact->getJID())); + } } void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) { - QModelIndex index = indexAt(event->pos()); - if (!index.isValid()) { - return; - } - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - QMenu contextMenu; - if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { - QAction* editContact = contextMenu.addAction(tr("Edit…")); - editContact->setEnabled(isOnline()); - QAction* removeContact = contextMenu.addAction(tr("Remove")); - removeContact->setEnabled(isOnline()); - QAction* showProfileForContact = contextMenu.addAction(tr("Show Profile")); - - QAction* unblockContact = NULL; - if (contact->blockState() == ContactRosterItem::IsBlocked || - contact->blockState() == ContactRosterItem::IsDomainBlocked) { - unblockContact = contextMenu.addAction(tr("Unblock")); - unblockContact->setEnabled(isOnline()); - } - - QAction* blockContact = NULL; - if (contact->blockState() == ContactRosterItem::IsUnblocked) { - blockContact = contextMenu.addAction(tr("Block")); - blockContact->setEnabled(isOnline()); - } + QModelIndex index = indexAt(event->pos()); + if (!index.isValid()) { + return; + } + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + QMenu contextMenu; + if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { + QAction* editContact = contextMenu.addAction(tr("Edit…")); + editContact->setEnabled(isOnline()); + QAction* removeContact = contextMenu.addAction(tr("Remove")); + removeContact->setEnabled(isOnline()); + QAction* showProfileForContact = contextMenu.addAction(tr("Show Profile")); + + QAction* unblockContact = nullptr; + if (contact->blockState() == ContactRosterItem::IsBlocked || + contact->blockState() == ContactRosterItem::IsDomainBlocked) { + unblockContact = contextMenu.addAction(tr("Unblock")); + unblockContact->setEnabled(isOnline()); + } + + QAction* blockContact = nullptr; + if (contact->blockState() == ContactRosterItem::IsUnblocked) { + blockContact = contextMenu.addAction(tr("Block")); + blockContact->setEnabled(isOnline()); + } #ifdef SWIFT_EXPERIMENTAL_FT - QAction* sendFile = NULL; - if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { - sendFile = contextMenu.addAction(tr("Send File")); - sendFile->setEnabled(isOnline()); - } + QAction* sendFile = nullptr; + if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { + sendFile = contextMenu.addAction(tr("Send File")); + sendFile->setEnabled(isOnline()); + } #endif #ifdef SWIFT_EXPERIMENTAL_WB - QAction* startWhiteboardChat = NULL; - if (contact->supportsFeature(ContactRosterItem::WhiteboardFeature)) { - startWhiteboardChat = contextMenu.addAction(tr("Start Whiteboard Chat")); - startWhiteboardChat->setEnabled(isOnline()); - } + QAction* startWhiteboardChat = nullptr; + if (contact->supportsFeature(ContactRosterItem::WhiteboardFeature)) { + startWhiteboardChat = contextMenu.addAction(tr("Start Whiteboard Chat")); + startWhiteboardChat->setEnabled(isOnline()); + } #endif - QAction* result = contextMenu.exec(event->globalPos()); - if (result == editContact) { - eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID())); - } - else if (result == removeContact) { - if (QtContactEditWindow::confirmContactDeletion(contact->getJID())) { - eventStream_->send(boost::make_shared<RemoveRosterItemUIEvent>(contact->getJID())); - } - } - else if (result == showProfileForContact) { - eventStream_->send(boost::make_shared<ShowProfileForRosterItemUIEvent>(contact->getJID())); - } - else if (unblockContact && result == unblockContact) { - if (contact->blockState() == ContactRosterItem::IsDomainBlocked) { - QMessageBox messageBox(QMessageBox::Question, tr("Swift"), tr("%2 is currently blocked because of a block on all users of the %1 service.\n %2 cannot be unblocked individually; do you want to unblock all %1 users?").arg(P2QSTRING(contact->getJID().getDomain()), P2QSTRING(contact->getJID().toString())), QMessageBox::NoButton, this); - QPushButton* unblockDomainButton = messageBox.addButton(tr("Unblock %1 domain").arg(P2QSTRING(contact->getJID().getDomain())), QMessageBox::AcceptRole); - messageBox.addButton(QMessageBox::Abort); - - messageBox.exec(); - if (messageBox.clickedButton() == unblockDomainButton) { - eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, contact->getJID().getDomain())); - } - } else { - eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, contact->getJID())); - } - } - else if (blockContact && result == blockContact) { - eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Blocked, contact->getJID())); - } + QAction* result = contextMenu.exec(event->globalPos()); + if (result == editContact) { + eventStream_->send(std::make_shared<RequestContactEditorUIEvent>(contact->getJID())); + } + else if (result == removeContact) { + if (QtContactEditWindow::confirmContactDeletion(contact->getJID())) { + eventStream_->send(std::make_shared<RemoveRosterItemUIEvent>(contact->getJID())); + } + } + else if (result == showProfileForContact) { + eventStream_->send(std::make_shared<ShowProfileForRosterItemUIEvent>(contact->getJID())); + } + else if (unblockContact && result == unblockContact) { + if (contact->blockState() == ContactRosterItem::IsDomainBlocked) { + QMessageBox messageBox(QMessageBox::Question, tr("Swift"), tr("%2 is currently blocked because of a block on all users of the %1 service.\n %2 cannot be unblocked individually; do you want to unblock all %1 users?").arg(P2QSTRING(contact->getJID().getDomain()), P2QSTRING(contact->getJID().toString())), QMessageBox::NoButton, this); + QPushButton* unblockDomainButton = messageBox.addButton(tr("Unblock %1 domain").arg(P2QSTRING(contact->getJID().getDomain())), QMessageBox::AcceptRole); + messageBox.addButton(QMessageBox::Abort); + + messageBox.exec(); + if (messageBox.clickedButton() == unblockDomainButton) { + eventStream_->send(std::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, contact->getJID().getDomain())); + } + } else { + eventStream_->send(std::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, contact->getJID())); + } + } + else if (blockContact && result == blockContact) { + eventStream_->send(std::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Blocked, contact->getJID())); + } #ifdef SWIFT_EXPERIMENTAL_FT - else if (sendFile && result == sendFile) { - QString fileName = QFileDialog::getOpenFileName(this, tr("Send File"), "", tr("All Files (*);;")); - if (!fileName.isEmpty()) { - eventStream_->send(boost::make_shared<SendFileUIEvent>(contact->getJID(), Q2PSTRING(fileName))); - } - } + else if (sendFile && result == sendFile) { + QString fileName = QFileDialog::getOpenFileName(this, tr("Send File"), "", tr("All Files (*);;")); + if (!fileName.isEmpty()) { + eventStream_->send(std::make_shared<SendFileUIEvent>(contact->getJID(), Q2PSTRING(fileName))); + } + } #endif #ifdef SWIFT_EXPERIMENTAL_WB - else if (startWhiteboardChat && result == startWhiteboardChat) { - eventStream_->send(boost::make_shared<RequestWhiteboardUIEvent>(contact->getJID())); - } + else if (startWhiteboardChat && result == startWhiteboardChat) { + eventStream_->send(std::make_shared<RequestWhiteboardUIEvent>(contact->getJID())); + } #endif - } - else if (GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item)) { - QAction* renameGroupAction = contextMenu.addAction(tr("Rename")); - if (P2QSTRING(group->getDisplayName()) == tr("Contacts")) { - renameGroupAction->setEnabled(false); - } - else { - renameGroupAction->setEnabled(isOnline()); - } - QAction* result = contextMenu.exec(event->globalPos()); - if (result == renameGroupAction) { - renameGroup(group); - } - } + } + else if (GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item)) { + QAction* renameGroupAction = contextMenu.addAction(tr("Rename")); + if (P2QSTRING(group->getDisplayName()) == tr("Contacts")) { + renameGroupAction->setEnabled(false); + } + else { + renameGroupAction->setEnabled(isOnline()); + } + QAction* result = contextMenu.exec(event->globalPos()); + if (result == renameGroupAction) { + renameGroup(group); + } + } } void QtRosterWidget::renameGroup(GroupRosterItem* group) { - bool ok; - QString newName = QInputDialog::getText(NULL, tr("Rename group"), tr("Enter a new name for group '%1':").arg(P2QSTRING(group->getDisplayName())), QLineEdit::Normal, P2QSTRING(group->getDisplayName()), &ok); - if (ok) { - eventStream_->send(boost::make_shared<RenameGroupUIEvent>(group->getDisplayName(), Q2PSTRING(newName))); - } + bool ok; + QString newName = QInputDialog::getText(nullptr, tr("Rename group"), tr("Enter a new name for group '%1':").arg(P2QSTRING(group->getDisplayName())), QLineEdit::Normal, P2QSTRING(group->getDisplayName()), &ok); + if (ok) { + eventStream_->send(std::make_shared<RenameGroupUIEvent>(group->getDisplayName(), Q2PSTRING(newName))); + } } } diff --git a/Swift/QtUI/Roster/QtRosterWidget.h b/Swift/QtUI/Roster/QtRosterWidget.h index d785af2..2cf8315 100644 --- a/Swift/QtUI/Roster/QtRosterWidget.h +++ b/Swift/QtUI/Roster/QtRosterWidget.h @@ -1,27 +1,27 @@ /* - * Copyright (c) 2011 Isode Limited. + * Copyright (c) 2011-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once -#include "Swift/QtUI/Roster/QtTreeWidget.h" +#include <Swift/QtUI/Roster/QtTreeWidget.h> namespace Swift { class QtUIPreferences; class QtRosterWidget : public QtTreeWidget { - Q_OBJECT - public: - QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0); - virtual ~QtRosterWidget(); - public slots: - void handleEditUserActionTriggered(bool checked); - protected: - void contextMenuEvent(QContextMenuEvent* event); - private: - void renameGroup(GroupRosterItem* group); + Q_OBJECT + public: + QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = nullptr); + virtual ~QtRosterWidget(); + public slots: + void handleEditUserActionTriggered(bool checked); + protected: + void contextMenuEvent(QContextMenuEvent* event); + private: + void renameGroup(GroupRosterItem* group); }; } diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp index 06a76c3..1264a09 100644 --- a/Swift/QtUI/Roster/QtTreeWidget.cpp +++ b/Swift/QtUI/Roster/QtTreeWidget.cpp @@ -1,263 +1,267 @@ /* - * Copyright (c) 2010-2014 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swift/QtUI/Roster/QtTreeWidget.h> -#include <boost/smart_ptr/make_shared.hpp> +#include <memory> + #include <boost/bind.hpp> -#include <QUrl> +#include <QFont> +#include <QLabel> #include <QMimeData> #include <QObject> -#include <QLabel> #include <QTimer> #include <QToolTip> +#include <QUrl> #include <Swiften/Base/Platform.h> #include <Swift/Controllers/Roster/ContactRosterItem.h> #include <Swift/Controllers/Roster/GroupRosterItem.h> -#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/Settings/SettingsProvider.h> #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> #include <Swift/Controllers/UIEvents/SendFileUIEvent.h> -#include <Swift/Controllers/Settings/SettingsProvider.h> - +#include <Swift/Controllers/UIEvents/UIEventStream.h> + +#include <Swift/QtUI/QtSwiftUtil.h> #include <Swift/QtUI/QtUISettingConstants.h> #include <Swift/QtUI/Roster/RosterModel.h> -#include <QtSwiftUtil.h> namespace Swift { -QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent) : QTreeView(parent), tooltipShown_(false), messageTarget_(messageTarget) { - eventStream_ = eventStream; - settings_ = settings; - model_ = new RosterModel(this, settings_->getSetting(QtUISettingConstants::USE_SCREENREADER)); - setModel(model_); - delegate_ = new RosterDelegate(this, settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER)); - setItemDelegate(delegate_); - setHeaderHidden(true); +QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent) : QTreeView(parent), eventStream_(eventStream), settings_(settings), messageTarget_(messageTarget) { + model_ = new RosterModel(this, settings_->getSetting(QtUISettingConstants::USE_SCREENREADER)); + setModel(model_); + delegate_ = new RosterDelegate(this, settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER)); + setItemDelegate(delegate_); + setHeaderHidden(true); #ifdef SWIFT_PLATFORM_MACOSX - setAlternatingRowColors(true); + setAlternatingRowColors(true); #endif - setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - expandAll(); - setAnimated(true); - setIndentation(0); + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + expandAll(); + setAnimated(true); + setIndentation(0); #ifdef SWIFT_EXPERIMENTAL_FT - setAcceptDrops(true); + setAcceptDrops(true); #endif - setDragEnabled(true); - setRootIsDecorated(true); - connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&))); - connect(model_, SIGNAL(itemExpanded(const QModelIndex&, bool)), this, SLOT(handleModelItemExpanded(const QModelIndex&, bool))); - connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(handleExpanded(const QModelIndex&))); - connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(handleCollapsed(const QModelIndex&))); - connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleClicked(const QModelIndex&))); - - settings_->onSettingChanged.connect(boost::bind(&QtTreeWidget::handleSettingChanged, this, _1)); + setDragEnabled(true); + setRootIsDecorated(true); + connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&))); + connect(model_, SIGNAL(itemExpanded(const QModelIndex&, bool)), this, SLOT(handleModelItemExpanded(const QModelIndex&, bool))); + connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(handleExpanded(const QModelIndex&))); + connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(handleCollapsed(const QModelIndex&))); + connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleClicked(const QModelIndex&))); + + settings_->onSettingChanged.connect(boost::bind(&QtTreeWidget::handleSettingChanged, this, _1)); + + QFont lato = font(); + lato.setFamily("Lato"); + setFont(lato); } QtTreeWidget::~QtTreeWidget() { - settings_->onSettingChanged.disconnect(boost::bind(&QtTreeWidget::handleSettingChanged, this, _1)); - delete model_; - delete delegate_; + settings_->onSettingChanged.disconnect(boost::bind(&QtTreeWidget::handleSettingChanged, this, _1)); + delete model_; + delete delegate_; } void QtTreeWidget::handleSettingChanged(const std::string& setting) { - if (setting == QtUISettingConstants::COMPACT_ROSTER.getKey()) { - delegate_->setCompact(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER)); - repaint(); - } + if (setting == QtUISettingConstants::COMPACT_ROSTER.getKey()) { + delegate_->setCompact(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER)); + repaint(); + } } void QtTreeWidget::handleRefreshTooltip() { - if (tooltipShown_) { - QPoint position = QCursor::pos(); - QModelIndex index = indexAt(mapFromGlobal(position)); - QToolTip::showText(position, model_->data(index, Qt::ToolTipRole).toString()); - } + if (tooltipShown_) { + QPoint position = QCursor::pos(); + QModelIndex index = indexAt(mapFromGlobal(position)); + QToolTip::showText(position, model_->data(index, Qt::ToolTipRole).toString()); + } } void QtTreeWidget::setRosterModel(Roster* roster) { - roster_ = roster; - model_->setRoster(roster); - expandAll(); + roster_ = roster; + model_->setRoster(roster); + expandAll(); } void QtTreeWidget::refreshTooltip() { - // Qt needs some time to emit the events we need to detect tooltip's visibility correctly; 20 ms should be enough - QTimer::singleShot(20, this, SLOT(handleRefreshTooltip())); + // Qt needs some time to emit the events we need to detect tooltip's visibility correctly; 20 ms should be enough + QTimer::singleShot(20, this, SLOT(handleRefreshTooltip())); } QtTreeWidgetItem* QtTreeWidget::getRoot() { - return treeRoot_; + return treeRoot_; } void QtTreeWidget::handleClicked(const QModelIndex& index) { - GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer())); - if (item) { - setExpanded(index, !isExpanded(index)); - } - currentChanged(index, QModelIndex()); + GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer())); + if (item) { + setExpanded(index, !isExpanded(index)); + } + currentChanged(index, QModelIndex()); } QModelIndexList QtTreeWidget::getSelectedIndexes() const { - // Not using selectedIndexes(), because this seems to cause a crash in Qt (4.7.0) in the - // QModelIndexList destructor. - // This is a workaround posted in http://www.qtcentre.org/threads/16933 (although this case - // was resolved by linking against the debug libs, ours isn't, and we're not alone) - QItemSelection ranges = selectionModel()->selection(); - QModelIndexList selectedIndexList; - for (int i = 0; i < ranges.count(); ++i) { - QModelIndex parent = ranges.at(i).parent(); - int right = ranges.at(i).model()->columnCount(parent) - 1; - if (ranges.at(i).left() == 0 && ranges.at(i).right() == right) { - for (int r = ranges.at(i).top(); r <= ranges.at(i).bottom(); ++r) { - selectedIndexList.append(ranges.at(i).model()->index(r, 0, parent)); - } - } - } - return selectedIndexList; + // Not using selectedIndexes(), because this seems to cause a crash in Qt (4.7.0) in the + // QModelIndexList destructor. + // This is a workaround posted in http://www.qtcentre.org/threads/16933 (although this case + // was resolved by linking against the debug libs, ours isn't, and we're not alone) + QItemSelection ranges = selectionModel()->selection(); + QModelIndexList selectedIndexList; + for (int i = 0; i < ranges.count(); ++i) { + QModelIndex parent = ranges.at(i).parent(); + int right = ranges.at(i).model()->columnCount(parent) - 1; + if (ranges.at(i).left() == 0 && ranges.at(i).right() == right) { + for (int r = ranges.at(i).top(); r <= ranges.at(i).bottom(); ++r) { + selectedIndexList.append(ranges.at(i).model()->index(r, 0, parent)); + } + } + } + return selectedIndexList; } void QtTreeWidget::currentChanged(const QModelIndex& current, const QModelIndex& previous) { - RosterItem* item = NULL; - QModelIndexList selectedIndexList = getSelectedIndexes(); - if (selectedIndexList.empty() || !selectedIndexList[0].isValid()) { - /* I didn't quite understand why using current didn't seem to work here.*/ - } - else if (current.isValid()) { - item = static_cast<RosterItem*>(current.internalPointer()); - item = dynamic_cast<ContactRosterItem*>(item); - } - onSomethingSelectedChanged(item); - QTreeView::currentChanged(current, previous); + RosterItem* item = nullptr; + QModelIndexList selectedIndexList = getSelectedIndexes(); + if (selectedIndexList.empty() || !selectedIndexList[0].isValid()) { + /* I didn't quite understand why using current didn't seem to work here.*/ + } + else if (current.isValid()) { + item = static_cast<RosterItem*>(current.internalPointer()); + item = dynamic_cast<ContactRosterItem*>(item); + } + onSomethingSelectedChanged(item); + QTreeView::currentChanged(current, previous); } void QtTreeWidget::handleItemActivated(const QModelIndex& index) { - JID target = jidFromIndex(index); - if (target.isValid()) { - eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(target))); - } + JID target = jidFromIndex(index); + if (target.isValid()) { + eventStream_->send(std::make_shared<RequestChatUIEvent>(target)); + } } void QtTreeWidget::dragEnterEvent(QDragEnterEvent *event) { - if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) { - event->acceptProposedAction(); - } + if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) { + event->acceptProposedAction(); + } } void QtTreeWidget::dropEvent(QDropEvent *event) { - QModelIndex index = indexAt(event->pos()); - if (index.isValid()) { - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { - if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { - QString filename = event->mimeData()->urls().at(0).toLocalFile(); - if (!filename.isEmpty()) { - eventStream_->send(boost::make_shared<SendFileUIEvent>(contact->getJID(), Q2PSTRING(filename))); - } - } - } - } + QModelIndex index = indexAt(event->pos()); + if (index.isValid()) { + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { + if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { + QString filename = event->mimeData()->urls().at(0).toLocalFile(); + if (!filename.isEmpty()) { + eventStream_->send(std::make_shared<SendFileUIEvent>(contact->getJID(), Q2PSTRING(filename))); + } + } + } + } } void QtTreeWidget::dragMoveEvent(QDragMoveEvent* event) { - QModelIndex index = indexAt(event->pos()); - if (index.isValid()) { - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { - if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { - event->accept(); - return; - } - } - } - QTreeView::dragMoveEvent(event); + QModelIndex index = indexAt(event->pos()); + if (index.isValid()) { + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { + if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { + event->accept(); + return; + } + } + } + QTreeView::dragMoveEvent(event); } bool QtTreeWidget::event(QEvent* event) { - QChildEvent* childEvent = NULL; - if ((childEvent = dynamic_cast<QChildEvent*>(event))) { - if (childEvent->polished()) { - if (dynamic_cast<QLabel*>(childEvent->child())) { - tooltipShown_ = true; - } - } - else if (childEvent->removed()) { - if (childEvent->child()->objectName() == "qtooltip_label") { - tooltipShown_ = false; - } - } - } - return QAbstractItemView::event(event); + QChildEvent* childEvent = nullptr; + if ((childEvent = dynamic_cast<QChildEvent*>(event))) { + if (childEvent->polished()) { + if (dynamic_cast<QLabel*>(childEvent->child())) { + tooltipShown_ = true; + } + } + else if (childEvent->removed()) { + if (childEvent->child()->objectName() == "qtooltip_label") { + tooltipShown_ = false; + } + } + } + return QAbstractItemView::event(event); } void QtTreeWidget::handleExpanded(const QModelIndex& index) { - GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer())); - if (item) { - item->setExpanded(true); - } + GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer())); + if (item) { + item->setExpanded(true); + } } void QtTreeWidget::handleCollapsed(const QModelIndex& index) { - GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer())); - if (item) { - item->setExpanded(false); - } + GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer())); + if (item) { + item->setExpanded(false); + } } void QtTreeWidget::handleModelItemExpanded(const QModelIndex& index, bool shouldExpand) { - if (!index.isValid()) { - return; - } - bool alreadyRight = this->isExpanded(index) == shouldExpand; - if (alreadyRight) { - return; - } - setExpanded(index, shouldExpand); + if (!index.isValid()) { + return; + } + bool alreadyRight = this->isExpanded(index) == shouldExpand; + if (alreadyRight) { + return; + } + setExpanded(index, shouldExpand); } void QtTreeWidget::drawBranches(QPainter*, const QRect&, const QModelIndex&) const { } void QtTreeWidget::show() { - QWidget::show(); + QWidget::show(); } void QtTreeWidget::setMessageTarget(MessageTarget messageTarget) { - messageTarget_ = messageTarget; + messageTarget_ = messageTarget; } JID QtTreeWidget::jidFromIndex(const QModelIndex& index) const { - JID target; - if (messageTarget_ == MessageDisplayJID) { - target = JID(Q2PSTRING(index.data(DisplayJIDRole).toString())); - target = target.toBare(); - } - if (!target.isValid()) { - target = JID(Q2PSTRING(index.data(JIDRole).toString())); - } - return target; + JID target; + if (messageTarget_ == MessageDisplayJID) { + target = JID(Q2PSTRING(index.data(DisplayJIDRole).toString())); + target = target.toBare(); + } + if (!target.isValid()) { + target = JID(Q2PSTRING(index.data(JIDRole).toString())); + } + return target; } JID QtTreeWidget::selectedJID() const { - QModelIndexList list = selectedIndexes(); - if (list.size() != 1) { - return JID(); - } - return jidFromIndex(list[0]); + QModelIndexList list = selectedIndexes(); + if (list.size() != 1) { + return JID(); + } + return jidFromIndex(list[0]); } void QtTreeWidget::setOnline(bool isOnline) { - isOnline_ = isOnline; + isOnline_ = isOnline; } bool QtTreeWidget::isOnline() const { - return isOnline_; + return isOnline_; } } diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h index ff45547..331458a 100644 --- a/Swift/QtUI/Roster/QtTreeWidget.h +++ b/Swift/QtUI/Roster/QtTreeWidget.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -7,74 +7,74 @@ #pragma once #include <QDragEnterEvent> -#include <QDropEvent> #include <QDragMoveEvent> +#include <QDropEvent> #include <QModelIndex> #include <QTreeView> - -#include <Swift/QtUI/Roster/RosterDelegate.h> -#include <Swift/QtUI/Roster/RosterModel.h> #include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/QtUI/Roster/RosterDelegate.h> +#include <Swift/QtUI/Roster/RosterModel.h> + namespace Swift { class UIEventStream; class SettingsProvider; class QtTreeWidget : public QTreeView { - Q_OBJECT - public: - enum MessageTarget {MessageDefaultJID, MessageDisplayJID}; + Q_OBJECT + public: + enum MessageTarget {MessageDefaultJID, MessageDisplayJID}; - QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent = 0); - ~QtTreeWidget(); - void show(); - QtTreeWidgetItem* getRoot(); - void setRosterModel(Roster* roster); - Roster* getRoster() {return roster_;} - void refreshTooltip(); - void setMessageTarget(MessageTarget messageTarget); - JID jidFromIndex(const QModelIndex& index) const; - JID selectedJID() const; - void setOnline(bool isOnline); + QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent = nullptr); + ~QtTreeWidget(); + void show(); + QtTreeWidgetItem* getRoot(); + void setRosterModel(Roster* roster); + Roster* getRoster() {return roster_;} + void refreshTooltip(); + void setMessageTarget(MessageTarget messageTarget); + JID jidFromIndex(const QModelIndex& index) const; + JID selectedJID() const; + void setOnline(bool isOnline); - public: - boost::signal<void (RosterItem*)> onSomethingSelectedChanged; + public: + boost::signals2::signal<void (RosterItem*)> onSomethingSelectedChanged; - private slots: - void handleItemActivated(const QModelIndex&); - void handleModelItemExpanded(const QModelIndex&, bool expanded); - void handleExpanded(const QModelIndex&); - void handleCollapsed(const QModelIndex&); - void handleClicked(const QModelIndex&); - void handleSettingChanged(const std::string& setting); - void handleRefreshTooltip(); + private slots: + void handleItemActivated(const QModelIndex&); + void handleModelItemExpanded(const QModelIndex&, bool expanded); + void handleExpanded(const QModelIndex&); + void handleCollapsed(const QModelIndex&); + void handleClicked(const QModelIndex&); + void handleSettingChanged(const std::string& setting); + void handleRefreshTooltip(); - protected: - void dragEnterEvent(QDragEnterEvent* event); - void dropEvent(QDropEvent* event); - void dragMoveEvent(QDragMoveEvent* event); - bool event(QEvent* event); - QModelIndexList getSelectedIndexes() const; - bool isOnline() const; + protected: + void dragEnterEvent(QDragEnterEvent* event); + void dropEvent(QDropEvent* event); + void dragMoveEvent(QDragMoveEvent* event); + bool event(QEvent* event); + QModelIndexList getSelectedIndexes() const; + bool isOnline() const; - private: - void drawBranches(QPainter*, const QRect&, const QModelIndex&) const; + private: + void drawBranches(QPainter*, const QRect&, const QModelIndex&) const; - protected slots: - virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); - protected: - UIEventStream* eventStream_; + protected slots: + virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); + protected: + UIEventStream* eventStream_; - private: - RosterModel* model_; - Roster* roster_; - RosterDelegate* delegate_; - QtTreeWidgetItem* treeRoot_; - SettingsProvider* settings_; - bool tooltipShown_; - MessageTarget messageTarget_; - bool isOnline_; + private: + RosterModel* model_; + Roster* roster_ = nullptr; + RosterDelegate* delegate_; + QtTreeWidgetItem* treeRoot_ = nullptr; + SettingsProvider* settings_; + bool tooltipShown_ = false; + MessageTarget messageTarget_; + bool isOnline_ = false; }; } diff --git a/Swift/QtUI/Roster/RosterDelegate.cpp b/Swift/QtUI/Roster/RosterDelegate.cpp index c5bb290..061982e 100644 --- a/Swift/QtUI/Roster/RosterDelegate.cpp +++ b/Swift/QtUI/Roster/RosterDelegate.cpp @@ -1,83 +1,83 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ -#include "RosterDelegate.h" +#include <Swift/QtUI/Roster/RosterDelegate.h> #include <QApplication> -#include <QPainter> -#include <QColor> +#include <QBitmap> #include <QBrush> +#include <QColor> +#include <QDebug> #include <QFontMetrics> +#include <QPainter> #include <QPainterPath> #include <QPolygon> -#include <qdebug.h> -#include <QBitmap> -#include "Swift/Controllers/Roster/ContactRosterItem.h" -#include "Swift/Controllers/Roster/GroupRosterItem.h" +#include <Swift/Controllers/Roster/ContactRosterItem.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> -#include "QtTreeWidget.h" -#include "RosterModel.h" +#include <Swift/QtUI/Roster/QtTreeWidget.h> +#include <Swift/QtUI/Roster/RosterModel.h> namespace Swift { RosterDelegate::RosterDelegate(QtTreeWidget* tree, bool compact) : compact_(compact) { - tree_ = tree; - groupDelegate_ = new GroupItemDelegate(); + tree_ = tree; + groupDelegate_ = new GroupItemDelegate(); } RosterDelegate::~RosterDelegate() { - delete groupDelegate_; + delete groupDelegate_; } void RosterDelegate::setCompact(bool compact) { - compact_ = compact; - emit sizeHintChanged(QModelIndex()); + compact_ = compact; + emit sizeHintChanged(QModelIndex()); } - + QSize RosterDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const { - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - if (dynamic_cast<GroupRosterItem*>(item)) { - return groupDelegate_->sizeHint(option, index); - } - return contactSizeHint(option, index); + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + if (dynamic_cast<GroupRosterItem*>(item)) { + return groupDelegate_->sizeHint(option, index); + } + return contactSizeHint(option, index); } QSize RosterDelegate::contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const { - return common_.contactSizeHint(option, index, compact_); + return common_.contactSizeHint(option, index, compact_); } void RosterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - if (dynamic_cast<GroupRosterItem*>(item)) { - paintGroup(painter, option, index); - } else { - paintContact(painter, option, index); - } + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + if (dynamic_cast<GroupRosterItem*>(item)) { + paintGroup(painter, option, index); + } else { + paintContact(painter, option, index); + } } void RosterDelegate::paintGroup(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - if (index.isValid()) { - groupDelegate_->paint(painter, option, index.data(Qt::DisplayRole).toString(), index.data(ChildCountRole).toInt(), tree_->isExpanded(index)); - } + if (index.isValid()) { + groupDelegate_->paint(painter, option, index.data(Qt::DisplayRole).toString(), index.data(ChildCountRole).toInt(), tree_->isExpanded(index)); + } } void RosterDelegate::paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - QColor nameColor = index.data(Qt::TextColorRole).value<QColor>(); - QString avatarPath; - if (index.data(AvatarRole).isValid() && !index.data(AvatarRole).value<QString>().isNull()) { - avatarPath = index.data(AvatarRole).value<QString>(); - } - QIcon presenceIcon = index.data(PresenceIconRole).isValid() && !index.data(PresenceIconRole).value<QIcon>().isNull() - ? index.data(PresenceIconRole).value<QIcon>() - : QIcon(":/icons/offline.png"); - bool isIdle = index.data(IdleRole).isValid() ? index.data(IdleRole).toBool() : false; - QString name = index.data(Qt::DisplayRole).toString(); - QString statusText = index.data(StatusTextRole).toString(); - common_.paintContact(painter, option, nameColor, avatarPath, presenceIcon, name, statusText, isIdle, 0, compact_); + QColor nameColor = index.data(Qt::TextColorRole).value<QColor>(); + QString avatarPath; + if (index.data(AvatarRole).isValid() && !index.data(AvatarRole).value<QString>().isNull()) { + avatarPath = index.data(AvatarRole).value<QString>(); + } + QIcon presenceIcon = index.data(PresenceIconRole).isValid() && !index.data(PresenceIconRole).value<QIcon>().isNull() + ? index.data(PresenceIconRole).value<QIcon>() + : QIcon(":/icons/offline.png"); + bool isIdle = index.data(IdleRole).isValid() ? index.data(IdleRole).toBool() : false; + QString name = index.data(Qt::DisplayRole).toString(); + QString statusText = index.data(StatusTextRole).toString(); + common_.paintContact(painter, option, nameColor, avatarPath, presenceIcon, name, statusText, isIdle, 0, compact_); } } diff --git a/Swift/QtUI/Roster/RosterDelegate.h b/Swift/QtUI/Roster/RosterDelegate.h index aedb6d6..34c1569 100644 --- a/Swift/QtUI/Roster/RosterDelegate.h +++ b/Swift/QtUI/Roster/RosterDelegate.h @@ -1,35 +1,35 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once -#include <QStyledItemDelegate> #include <QColor> #include <QFont> +#include <QStyledItemDelegate> -#include "GroupItemDelegate.h" -#include "DelegateCommons.h" +#include <Swift/QtUI/Roster/DelegateCommons.h> +#include <Swift/QtUI/Roster/GroupItemDelegate.h> namespace Swift { - class QtTreeWidget; - class RosterDelegate : public QStyledItemDelegate { - public: - RosterDelegate(QtTreeWidget* tree, bool compact); - ~RosterDelegate(); - QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; - void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; - public slots: - void setCompact(bool compact); - private: - QSize contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; - void paintGroup(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; - void paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; - bool compact_; - DelegateCommons common_; - GroupItemDelegate* groupDelegate_; - QtTreeWidget* tree_; - }; + class QtTreeWidget; + class RosterDelegate : public QStyledItemDelegate { + public: + RosterDelegate(QtTreeWidget* tree, bool compact); + ~RosterDelegate(); + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + public slots: + void setCompact(bool compact); + private: + QSize contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + void paintGroup(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + void paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + bool compact_; + DelegateCommons common_; + GroupItemDelegate* groupDelegate_; + QtTreeWidget* tree_; + }; } diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp index b7a1d0a..ef4d778 100644 --- a/Swift/QtUI/Roster/RosterModel.cpp +++ b/Swift/QtUI/Roster/RosterModel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,268 +11,269 @@ #include <QColor> #include <QIcon> #include <QMimeData> + #include <qdebug.h> -#include <Swiften/Elements/StatusShow.h> #include <Swiften/Base/Path.h> +#include <Swiften/Elements/StatusShow.h> #include <Swift/Controllers/Roster/ContactRosterItem.h> #include <Swift/Controllers/Roster/GroupRosterItem.h> #include <Swift/Controllers/StatusUtil.h> -#include <Swift/QtUI/Roster/QtTreeWidget.h> -#include <Swift/QtUI/Roster/RosterTooltip.h> #include <Swift/QtUI/QtResourceHelper.h> #include <Swift/QtUI/QtSwiftUtil.h> +#include <Swift/QtUI/Roster/QtTreeWidget.h> +#include <Swift/QtUI/Roster/RosterTooltip.h> namespace Swift { -RosterModel::RosterModel(QtTreeWidget* view, bool screenReaderMode) : roster_(NULL), view_(view), screenReader_(screenReaderMode) { - const int tooltipAvatarSize = 96; // maximal suggested size according to XEP-0153 - cachedImageScaler_ = new QtScaledAvatarCache(tooltipAvatarSize); +RosterModel::RosterModel(QtTreeWidget* view, bool screenReaderMode) : roster_(nullptr), view_(view), screenReader_(screenReaderMode) { + const int tooltipAvatarSize = 96; // maximal suggested size according to XEP-0153 + cachedImageScaler_ = new QtScaledAvatarCache(tooltipAvatarSize); } RosterModel::~RosterModel() { - delete cachedImageScaler_; + delete cachedImageScaler_; } void RosterModel::setRoster(Roster* roster) { - roster_ = roster; - if (roster_) { - roster->onChildrenChanged.connect(boost::bind(&RosterModel::handleChildrenChanged, this, _1)); - roster->onDataChanged.connect(boost::bind(&RosterModel::handleDataChanged, this, _1)); - } - reLayout(); + roster_ = roster; + if (roster_) { + roster->onChildrenChanged.connect(boost::bind(&RosterModel::handleChildrenChanged, this, _1)); + roster->onDataChanged.connect(boost::bind(&RosterModel::handleDataChanged, this, _1)); + } + reLayout(); } void RosterModel::reLayout() { - //emit layoutChanged(); - beginResetModel(); - endResetModel(); // TODO: Not sure if this isn't too early? - if (!roster_) { - return; - } - foreach (RosterItem* item, roster_->getRoot()->getDisplayedChildren()) { - GroupRosterItem* child = dynamic_cast<GroupRosterItem*>(item); - if (!child) continue; - emit itemExpanded(index(child), child->isExpanded()); - } + //emit layoutChanged(); + beginResetModel(); + endResetModel(); // TODO: Not sure if this isn't too early? + if (!roster_) { + return; + } + for (auto item : roster_->getRoot()->getDisplayedChildren()) { + GroupRosterItem* child = dynamic_cast<GroupRosterItem*>(item); + if (!child) continue; + emit itemExpanded(index(child), child->isExpanded()); + } } void RosterModel::handleChildrenChanged(GroupRosterItem* /*group*/) { - reLayout(); + reLayout(); } void RosterModel::handleDataChanged(RosterItem* item) { - Q_ASSERT(item); - QModelIndex modelIndex = index(item); - if (modelIndex.isValid()) { - emit dataChanged(modelIndex, modelIndex); - view_->refreshTooltip(); - } + Q_ASSERT(item); + QModelIndex modelIndex = index(item); + if (modelIndex.isValid()) { + emit dataChanged(modelIndex, modelIndex); + view_->refreshTooltip(); + } } Qt::ItemFlags RosterModel::flags(const QModelIndex& index) const { - Qt::ItemFlags flags = QAbstractItemModel::flags(index); - if (dynamic_cast<GroupRosterItem*>(getItem(index)) == NULL) { - flags |= Qt::ItemIsDragEnabled; - } - return flags; + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + if (dynamic_cast<GroupRosterItem*>(getItem(index)) == nullptr) { + flags |= Qt::ItemIsDragEnabled; + } + return flags; } int RosterModel::columnCount(const QModelIndex& /*parent*/) const { - return 1; + return 1; } RosterItem* RosterModel::getItem(const QModelIndex& index) const { - return index.isValid() ? static_cast<RosterItem*>(index.internalPointer()) : NULL; + return index.isValid() ? static_cast<RosterItem*>(index.internalPointer()) : nullptr; } QVariant RosterModel::data(const QModelIndex& index, int role) const { - RosterItem* item = getItem(index); - if (!item) return QVariant(); - - switch (role) { - case Qt::DisplayRole: return getScreenReaderTextOr(item, P2QSTRING(item->getDisplayName())); - case Qt::TextColorRole: return getTextColor(item); - case Qt::BackgroundColorRole: return getBackgroundColor(item); - case Qt::ToolTipRole: return getToolTip(item); - case StatusTextRole: return getStatusText(item); - case AvatarRole: return getAvatar(item); - case PresenceIconRole: return getPresenceIcon(item); - case ChildCountRole: return getChildCount(item); - case IdleRole: return getIsIdle(item); - case JIDRole: return getJID(item); - case DisplayJIDRole: return getDisplayJID(item); - default: return QVariant(); - } + RosterItem* item = getItem(index); + if (!item) return QVariant(); + + switch (role) { + case Qt::DisplayRole: return getScreenReaderTextOr(item, P2QSTRING(item->getDisplayName())); + case Qt::TextColorRole: return getTextColor(item); + case Qt::BackgroundColorRole: return getBackgroundColor(item); + case Qt::ToolTipRole: return getToolTip(item); + case StatusTextRole: return getStatusText(item); + case AvatarRole: return getAvatar(item); + case PresenceIconRole: return getPresenceIcon(item); + case ChildCountRole: return getChildCount(item); + case IdleRole: return getIsIdle(item); + case JIDRole: return getJID(item); + case DisplayJIDRole: return getDisplayJID(item); + default: return QVariant(); + } } QString RosterModel::getScreenReaderTextOr(RosterItem* item, const QString& alternative) const { - QString name = P2QSTRING(item->getDisplayName()); - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - if (contact && screenReader_) { - name += ": " + P2QSTRING(statusShowTypeToFriendlyName(contact->getStatusShow())); - if (!contact->getStatusText().empty()) { - name += " (" + P2QSTRING(contact->getStatusText()) + ")"; - } - return name; - } - else { - return alternative; - } + QString name = P2QSTRING(item->getDisplayName()); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (contact && screenReader_) { + name += ": " + P2QSTRING(statusShowTypeToFriendlyName(contact->getStatusShow())); + if (!contact->getStatusText().empty()) { + name += " (" + P2QSTRING(contact->getStatusText()) + ")"; + } + return name; + } + else { + return alternative; + } } int RosterModel::getChildCount(RosterItem* item) const { - GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); - return group ? group->getDisplayedChildren().size() : 0; + GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); + return group ? group->getDisplayedChildren().size() : 0; } bool RosterModel::getIsIdle(RosterItem* item) const { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - return contact ? !contact->getIdleText().empty() : false; + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + return contact ? !contact->getIdleText().empty() : false; } QColor RosterModel::intToColor(int color) const { - return QColor( - ((color & 0xFF0000)>>16), - ((color & 0xFF00)>>8), - (color & 0xFF)); + return QColor( + ((color & 0xFF0000)>>16), + ((color & 0xFF00)>>8), + (color & 0xFF)); } QColor RosterModel::getTextColor(RosterItem* item) const { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - int color = 0; - if (contact) { - switch (contact->getStatusShow()) { - case StatusShow::Online: color = 0x000000; break; - case StatusShow::Away: color = 0x336699; break; - case StatusShow::XA: color = 0x336699; break; - case StatusShow::FFC: color = 0x000000; break; - case StatusShow::DND: color = 0x990000; break; - case StatusShow::None: color = 0x7F7F7F;break; - } - } - return intToColor(color); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + int color = 0; + if (contact) { + switch (contact->getStatusShow()) { + case StatusShow::Online: color = 0x595959; break; + case StatusShow::Away: color = 0x336699; break; + case StatusShow::XA: color = 0x336699; break; + case StatusShow::FFC: color = 0x595959; break; + case StatusShow::DND: color = 0x990000; break; + case StatusShow::None: color = 0x7F7F7F;break; + } + } + return intToColor(color); } QColor RosterModel::getBackgroundColor(RosterItem* item) const { - return dynamic_cast<ContactRosterItem*>(item) ? intToColor(0xFFFFFF) : intToColor(0x969696); + return dynamic_cast<ContactRosterItem*>(item) ? intToColor(0xFFFFFF) : intToColor(0x969696); } QString RosterModel::getToolTip(RosterItem* item) const { - QString tip(P2QSTRING(item->getDisplayName())); - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - if (contact) { - return RosterTooltip::buildDetailedTooltip(contact, cachedImageScaler_); - } - return tip; + QString tip(P2QSTRING(item->getDisplayName())); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (contact) { + return RosterTooltip::buildDetailedTooltip(contact, cachedImageScaler_); + } + return tip; } QString RosterModel::getAvatar(RosterItem* item) const { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - if (!contact) { - return ""; - } - return P2QSTRING(pathToString(contact->getAvatarPath())); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (!contact) { + return ""; + } + return P2QSTRING(pathToString(contact->getAvatarPath())); } QString RosterModel::getStatusText(RosterItem* item) const { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - if (!contact) return ""; - return P2QSTRING(contact->getStatusText()); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (!contact) return ""; + return P2QSTRING(contact->getStatusText()); } QString RosterModel::getJID(RosterItem* item) const { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - return contact ? P2QSTRING(contact->getJID().toString()) : QString(); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + return contact ? P2QSTRING(contact->getJID().toString()) : QString(); } QString RosterModel::getDisplayJID(RosterItem* item) const { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - QString result = contact ? P2QSTRING(contact->getDisplayJID().toString()) : QString(); - if (result.isEmpty()) { - result = getJID(item); - } - return result; + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + QString result = contact ? P2QSTRING(contact->getDisplayJID().toString()) : QString(); + if (result.isEmpty()) { + result = getJID(item); + } + return result; } QIcon RosterModel::getPresenceIcon(RosterItem* item) const { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); - if (!contact) return QIcon(); - if (contact->blockState() == ContactRosterItem::IsBlocked || - contact->blockState() == ContactRosterItem::IsDomainBlocked) { - return QIcon(":/icons/stop.png"); - } - - return QIcon(statusShowTypeToIconPath(contact->getStatusShow())); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (!contact) return QIcon(); + if (contact->blockState() == ContactRosterItem::IsBlocked || + contact->blockState() == ContactRosterItem::IsDomainBlocked) { + return QIcon(":/icons/stop.png"); + } + + return QIcon(statusShowTypeToIconPath(contact->getStatusShow())); } QModelIndex RosterModel::index(int row, int column, const QModelIndex& parent) const { - if (!roster_) { - return QModelIndex(); - } - GroupRosterItem* parentItem; - if (!parent.isValid()) { - //top level - parentItem = roster_->getRoot(); - } else { - parentItem = dynamic_cast<GroupRosterItem*>(getItem(parent)); - if (!parentItem) return QModelIndex(); - } - return static_cast<size_t>(row) < parentItem->getDisplayedChildren().size() ? createIndex(row, column, parentItem->getDisplayedChildren()[row]) : QModelIndex(); + if (!roster_) { + return QModelIndex(); + } + GroupRosterItem* parentItem; + if (!parent.isValid()) { + //top level + parentItem = roster_->getRoot(); + } else { + parentItem = dynamic_cast<GroupRosterItem*>(getItem(parent)); + if (!parentItem) return QModelIndex(); + } + return static_cast<size_t>(row) < parentItem->getDisplayedChildren().size() ? createIndex(row, column, parentItem->getDisplayedChildren()[row]) : QModelIndex(); } QModelIndex RosterModel::index(RosterItem* item) const { - GroupRosterItem* parent = item->getParent(); - /* Recursive check that it's ok to create such an item - Assuming there are more contacts in a group than groups in a - group, this could save a decent chunk of search time at startup.*/ - if (parent == NULL || roster_ == NULL || (parent != roster_->getRoot() && !index(parent).isValid())) { - return QModelIndex(); - } - for (size_t i = 0; i < parent->getDisplayedChildren().size(); i++) { - if (parent->getDisplayedChildren()[i] == item) { - return createIndex(i, 0, item); - } - } - return QModelIndex(); + GroupRosterItem* parent = item->getParent(); + /* Recursive check that it's ok to create such an item + Assuming there are more contacts in a group than groups in a + group, this could save a decent chunk of search time at startup.*/ + if (parent == nullptr || roster_ == nullptr || (parent != roster_->getRoot() && !index(parent).isValid())) { + return QModelIndex(); + } + for (size_t i = 0; i < parent->getDisplayedChildren().size(); i++) { + if (parent->getDisplayedChildren()[i] == item) { + return createIndex(i, 0, item); + } + } + return QModelIndex(); } QModelIndex RosterModel::parent(const QModelIndex& child) const { - if (!roster_ || !child.isValid()) { - return QModelIndex(); - } - - GroupRosterItem* parent = getItem(child)->getParent(); - return (parent != roster_->getRoot()) ? index(parent) : QModelIndex(); + if (!roster_ || !child.isValid()) { + return QModelIndex(); + } + + GroupRosterItem* parent = getItem(child)->getParent(); + return (parent != roster_->getRoot()) ? index(parent) : QModelIndex(); } int RosterModel::rowCount(const QModelIndex& parent) const { - if (!roster_) return 0; - RosterItem* item = parent.isValid() ? static_cast<RosterItem*>(parent.internalPointer()) : roster_->getRoot(); - Q_ASSERT(item); - GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); - int count = group ? group->getDisplayedChildren().size() : 0; -// qDebug() << "rowCount = " << count << " where parent.isValid() == " << parent.isValid() << ", group == " << (group ? P2QSTRING(group->getDisplayName()) : "*contact*"); - return count; + if (!roster_) return 0; + RosterItem* item = parent.isValid() ? static_cast<RosterItem*>(parent.internalPointer()) : roster_->getRoot(); + Q_ASSERT(item); + GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); + int count = group ? group->getDisplayedChildren().size() : 0; +// qDebug() << "rowCount = " << count << " where parent.isValid() == " << parent.isValid() << ", group == " << (group ? P2QSTRING(group->getDisplayName()) : "*contact*"); + return count; } QMimeData* RosterModel::mimeData(const QModelIndexList& indexes) const { - QMimeData* data = QAbstractItemModel::mimeData(indexes); - - ContactRosterItem *item = dynamic_cast<ContactRosterItem*>(getItem(indexes.first())); - if (item == NULL) { - return data; - } - - /* only a single JID in this list */ - QByteArray itemData; - QDataStream dataStream(&itemData, QIODevice::WriteOnly); - dataStream << P2QSTRING(item->getJID().toString()); - data->setData("application/vnd.swift.contact-jid-list", itemData); - return data; + QMimeData* data = QAbstractItemModel::mimeData(indexes); + + ContactRosterItem *item = dynamic_cast<ContactRosterItem*>(getItem(indexes.first())); + if (item == nullptr) { + return data; + } + + /* only a single JID in this list */ + QByteArray itemData; + QDataStream dataStream(&itemData, QIODevice::WriteOnly); + dataStream << P2QSTRING(item->getJID().toString()); + data->setData("application/vnd.swift.contact-jid-list", itemData); + return data; } } diff --git a/Swift/QtUI/Roster/RosterModel.h b/Swift/QtUI/Roster/RosterModel.h index 47ed614..af0d43a 100644 --- a/Swift/QtUI/Roster/RosterModel.h +++ b/Swift/QtUI/Roster/RosterModel.h @@ -14,58 +14,58 @@ #include <Swift/QtUI/QtScaledAvatarCache.h> namespace Swift { - enum RosterRoles { - StatusTextRole = Qt::UserRole, - AvatarRole = Qt::UserRole + 1, - PresenceIconRole = Qt::UserRole + 2, - StatusShowTypeRole = Qt::UserRole + 3, - ChildCountRole = Qt::UserRole + 4, - IdleRole = Qt::UserRole + 5, - JIDRole = Qt::UserRole + 6, - DisplayJIDRole = Qt::UserRole + 7 - }; + enum RosterRoles { + StatusTextRole = Qt::UserRole, + AvatarRole = Qt::UserRole + 1, + PresenceIconRole = Qt::UserRole + 2, + StatusShowTypeRole = Qt::UserRole + 3, + ChildCountRole = Qt::UserRole + 4, + IdleRole = Qt::UserRole + 5, + JIDRole = Qt::UserRole + 6, + DisplayJIDRole = Qt::UserRole + 7 + }; - class QtTreeWidget; + class QtTreeWidget; - class RosterModel : public QAbstractItemModel { - Q_OBJECT - public: - RosterModel(QtTreeWidget* view, bool screenReaderMode); - ~RosterModel(); - void setRoster(Roster* swiftRoster); - Qt::ItemFlags flags(const QModelIndex& index) const; - int columnCount(const QModelIndex& parent = QModelIndex()) const; - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; - QModelIndex index(RosterItem* item) const; - QModelIndex parent(const QModelIndex& index) const; - int rowCount(const QModelIndex& parent = QModelIndex()) const; - QMimeData* mimeData(const QModelIndexList& indexes) const; + class RosterModel : public QAbstractItemModel { + Q_OBJECT + public: + RosterModel(QtTreeWidget* view, bool screenReaderMode); + ~RosterModel(); + void setRoster(Roster* swiftRoster); + Qt::ItemFlags flags(const QModelIndex& index) const; + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; + QModelIndex index(RosterItem* item) const; + QModelIndex parent(const QModelIndex& index) const; + int rowCount(const QModelIndex& parent = QModelIndex()) const; + QMimeData* mimeData(const QModelIndexList& indexes) const; - signals: - void itemExpanded(const QModelIndex& item, bool expanded); - private: - void handleDataChanged(RosterItem* item); - void handleChildrenChanged(GroupRosterItem* item); - RosterItem* getItem(const QModelIndex& index) const; - QColor intToColor(int color) const; - QColor getTextColor(RosterItem* item) const; - QColor getBackgroundColor(RosterItem* item) const; - QString getToolTip(RosterItem* item) const; - QString getAvatar(RosterItem* item) const; - QString getStatusText(RosterItem* item) const; - QString getJID(RosterItem* item) const; - QString getDisplayJID(RosterItem* item) const; - QIcon getPresenceIcon(RosterItem* item) const; - int getChildCount(RosterItem* item) const; - bool getIsIdle(RosterItem* item) const; - void reLayout(); - /** calculates screenreader-friendly text if in screenreader mode, otherwise uses alternative text */ - QString getScreenReaderTextOr(RosterItem* item, const QString& alternative) const; - private: - Roster* roster_; - QtTreeWidget* view_; - QtScaledAvatarCache* cachedImageScaler_; - bool screenReader_; - }; + signals: + void itemExpanded(const QModelIndex& item, bool expanded); + private: + void handleDataChanged(RosterItem* item); + void handleChildrenChanged(GroupRosterItem* item); + RosterItem* getItem(const QModelIndex& index) const; + QColor intToColor(int color) const; + QColor getTextColor(RosterItem* item) const; + QColor getBackgroundColor(RosterItem* item) const; + QString getToolTip(RosterItem* item) const; + QString getAvatar(RosterItem* item) const; + QString getStatusText(RosterItem* item) const; + QString getJID(RosterItem* item) const; + QString getDisplayJID(RosterItem* item) const; + QIcon getPresenceIcon(RosterItem* item) const; + int getChildCount(RosterItem* item) const; + bool getIsIdle(RosterItem* item) const; + void reLayout(); + /** calculates screenreader-friendly text if in screenreader mode, otherwise uses alternative text */ + QString getScreenReaderTextOr(RosterItem* item, const QString& alternative) const; + private: + Roster* roster_; + QtTreeWidget* view_; + QtScaledAvatarCache* cachedImageScaler_; + bool screenReader_; + }; } diff --git a/Swift/QtUI/Roster/RosterTooltip.cpp b/Swift/QtUI/Roster/RosterTooltip.cpp index 86f175d..ea4c9cd 100644 --- a/Swift/QtUI/Roster/RosterTooltip.cpp +++ b/Swift/QtUI/Roster/RosterTooltip.cpp @@ -4,163 +4,172 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #include <Swift/QtUI/Roster/RosterTooltip.h> +#include <QApplication> #include <QObject> #include <QString> -#include <QApplication> #include <Swiften/Base/Path.h> #include <Swift/Controllers/Roster/ContactRosterItem.h> #include <Swift/Controllers/StatusUtil.h> +#include <Swift/Controllers/Translator.h> -#include <Swift/QtUI/QtSwiftUtil.h> +#include <Swift/QtUI/QtResourceHelper.h> #include <Swift/QtUI/QtScaledAvatarCache.h> +#include <Swift/QtUI/QtSwiftUtil.h> #include <Swift/QtUI/QtUtilities.h> -#include <Swift/QtUI/QtResourceHelper.h> using namespace QtUtilities; namespace Swift { QString RosterTooltip::buildDetailedTooltip(ContactRosterItem* contact, QtScaledAvatarCache* cachedImageScaler) { - QString tooltipTemplate; - if (QApplication::layoutDirection() == Qt::RightToLeft) { - tooltipTemplate = QString( - "<table style='white-space:pre'>" - "<tr>" - "<td>" - "<img src=\"%1\" />" - "</td>" - "<td>" - "<p style='font-size: 14px'>%3 %2</p>" - "<table><tr><td valign='middle'>%5</td><td valign='middle'>%4</td></tr></table>" - "%6" - "%7" - "%8" - "%9" - "</td>" - "</tr>" - "</table>"); - } else { - tooltipTemplate = QString( - "<table style='white-space:pre'>" - "<tr>" - "<td>" - "<img src=\"%1\" />" - "</td>" - "<td>" - "<p style='font-size: 14px'>%2 %3</p>" - "<table><tr><td valign='middle'>%4</td><td valign='middle'>%5</td></tr></table>" - "%6" - "%7" - "%8" - "%9" - "</td>" - "</tr>" - "</table>"); - } - // prepare tooltip - QString fullName = P2QSTRING(contact->getDisplayName()); - - QString vCardSummary; - VCard::ref vCard = contact->getVCard(); - if (vCard) { - fullName = P2QSTRING(vCard->getFullName()).trimmed(); - if (fullName.isEmpty()) { - fullName = (P2QSTRING(vCard->getGivenName()) + " " + P2QSTRING(vCard->getFamilyName())).trimmed(); - } - if (fullName.isEmpty()) { - fullName = P2QSTRING(contact->getDisplayName()); - } - vCardSummary = buildVCardSummary(vCard); - } else { - contact->onVCardRequested(); - } - - QString scaledAvatarPath = cachedImageScaler->getScaledAvatarPath(P2QSTRING(contact->getAvatarPath().empty() ? ":/icons/avatar.png" : pathToString(contact->getAvatarPath()))); - - QString bareJID = contact->getDisplayJID().toString().empty() ? "" : "( " + P2QSTRING(contact->getDisplayJID().toString()) + " )"; - - QString presenceIconTag = QString("<img src='%1' />").arg(statusShowTypeToIconPath(contact->getStatusShow())); - - QString statusMessage = contact->getStatusText().empty() ? QObject::tr("(No message)") : P2QSTRING(contact->getStatusText()); - - QString idleString = P2QSTRING(contact->getIdleText()); - if (!idleString.isEmpty()) { - idleString = QObject::tr("Idle since %1").arg(idleString); - idleString = htmlEscape(idleString) + "<br/>"; - } - - QString lastSeen = P2QSTRING(contact->getOfflineSinceText()); - if (!lastSeen.isEmpty()) { - lastSeen = QObject::tr("Last seen %1").arg(lastSeen); - lastSeen = htmlEscape(lastSeen) + "<br/>"; - } - - QString mucOccupant= P2QSTRING(contact->getMUCAffiliationText()); - if (!mucOccupant.isEmpty()) { - mucOccupant = htmlEscape(mucOccupant) + "<br/>"; - } - - return tooltipTemplate.arg(scaledAvatarPath, htmlEscape(fullName), htmlEscape(bareJID), presenceIconTag, htmlEscape(statusMessage), mucOccupant, idleString, lastSeen, vCardSummary); + QString tooltipTemplate; + if (QApplication::layoutDirection() == Qt::RightToLeft) { + tooltipTemplate = QString( + "<table style='white-space:pre'>" + "<tr>" + "<td>" + "<img src=\"%1\" />" + "</td>" + "<td>" + "<p style='font-size: 14px'>%3 %2</p>" + "<table><tr><td valign='middle'>%5</td><td valign='middle'>%4</td></tr></table>" + "%6" + "%7" + "%8" + "%9" + "</td>" + "</tr>" + "</table>"); + } else { + tooltipTemplate = QString( + "<table style='white-space:pre'>" + "<tr>" + "<td>" + "<img src=\"%1\" />" + "</td>" + "<td>" + "<p style='font-size: 14px'>%2 %3</p>" + "<table><tr><td valign='middle'>%4</td><td valign='middle'>%5</td></tr></table>" + "%6" + "%7" + "%8" + "%9" + "</td>" + "</tr>" + "</table>"); + } + // prepare tooltip + QString fullName = P2QSTRING(contact->getDisplayName()); + + QString vCardSummary; + VCard::ref vCard = contact->getVCard(); + if (vCard) { + fullName = P2QSTRING(vCard->getFullName()).trimmed(); + if (fullName.isEmpty()) { + fullName = (P2QSTRING(vCard->getGivenName()) + " " + P2QSTRING(vCard->getFamilyName())).trimmed(); + } + if (fullName.isEmpty()) { + fullName = P2QSTRING(contact->getDisplayName()); + } + vCardSummary = buildVCardSummary(vCard); + } else { + contact->onVCardRequested(); + } + + QString scaledAvatarPath = cachedImageScaler->getScaledAvatarPath(P2QSTRING(contact->getAvatarPath().empty() ? ":/icons/avatar.svg" : pathToString(contact->getAvatarPath()))); + + QString bareJID = contact->getDisplayJID().toString().empty() ? "" : "( " + P2QSTRING(contact->getDisplayJID().toString()) + " )"; + + QString presenceIconTag = QString("<img src='%1' />").arg(statusShowTypeToIconPath(contact->getStatusShow())); + + QString statusMessage = contact->getStatusText().empty() ? QObject::tr("(No message)") : P2QSTRING(contact->getStatusText()); + + boost::posix_time::ptime idleTime = contact->getIdle(); + QString idleString; + if (!idleTime.is_not_a_date_time()) { + idleString = QObject::tr("Idle since %1").arg(P2QSTRING(Swift::Translator::getInstance()->ptimeToHumanReadableString(idleTime))); + idleString = htmlEscape(idleString) + "<br/>"; + } + + boost::posix_time::ptime lastSeenTime = contact->getOfflineSince(); + QString lastSeen; + if (!lastSeenTime.is_not_a_date_time()) { + lastSeen = QObject::tr("Last seen %1").arg(P2QSTRING(Swift::Translator::getInstance()->ptimeToHumanReadableString(lastSeenTime))); + lastSeen = htmlEscape(lastSeen) + "<br/>"; + } + + QString mucOccupant= P2QSTRING(contact->getMUCAffiliationText()); + if (!mucOccupant.isEmpty()) { + mucOccupant = htmlEscape(mucOccupant) + "<br/>"; + } + + return tooltipTemplate.arg(scaledAvatarPath, htmlEscape(fullName), htmlEscape(bareJID), presenceIconTag, htmlEscape(statusMessage), mucOccupant, idleString, lastSeen, vCardSummary); } QString RosterTooltip::buildVCardSummary(VCard::ref vcard) { - QString summary; - summary = "<table>"; - - // star | name | content - QString currentBlock; - foreach (const VCard::Telephone& tel, vcard->getTelephones()) { - QString type = tel.isFax ? QObject::tr("Fax") : QObject::tr("Telephone"); - QString field = buildVCardField(tel.isPreferred, type, htmlEscape(P2QSTRING(tel.number))); - if (tel.isPreferred) { - currentBlock = field; - break; - } - currentBlock += field; - } - summary += currentBlock; - - currentBlock = ""; - foreach (const VCard::EMailAddress& mail, vcard->getEMailAddresses()) { - QString field = buildVCardField(mail.isPreferred, QObject::tr("E-Mail"), htmlEscape(P2QSTRING(mail.address))); - if (mail.isPreferred) { - currentBlock = field; - break; - } - currentBlock += field; - } - summary += currentBlock; - - currentBlock = ""; - foreach (const VCard::Organization& org, vcard->getOrganizations()) { - QString field = buildVCardField(false, QObject::tr("Organization"), htmlEscape(P2QSTRING(org.name))); - currentBlock += field; - } - summary += currentBlock; - - currentBlock = ""; - foreach(const std::string& title, vcard->getTitles()) { - QString field = buildVCardField(false, QObject::tr("Title"), htmlEscape(P2QSTRING(title))); - currentBlock += field; - } - summary += currentBlock; - - summary += "</table>"; - return summary; + QString summary; + summary = "<table>"; + + // star | name | content + QString currentBlock; + for (const auto& tel : vcard->getTelephones()) { + QString type = tel.isFax ? QObject::tr("Fax") : QObject::tr("Telephone"); + QString field = buildVCardField(tel.isPreferred, type, htmlEscape(P2QSTRING(tel.number))); + if (tel.isPreferred) { + currentBlock = field; + break; + } + currentBlock += field; + } + summary += currentBlock; + + currentBlock = ""; + for (const auto& mail : vcard->getEMailAddresses()) { + QString field = buildVCardField(mail.isPreferred, QObject::tr("E-Mail"), htmlEscape(P2QSTRING(mail.address))); + if (mail.isPreferred) { + currentBlock = field; + break; + } + currentBlock += field; + } + summary += currentBlock; + + currentBlock = ""; + for (const auto& org : vcard->getOrganizations()) { + QString field = buildVCardField(false, QObject::tr("Organization"), htmlEscape(P2QSTRING(org.name))); + currentBlock += field; + } + summary += currentBlock; + + currentBlock = ""; + for (const auto& title : vcard->getTitles()) { + QString field = buildVCardField(false, QObject::tr("Title"), htmlEscape(P2QSTRING(title))); + currentBlock += field; + } + summary += currentBlock; + + summary += "</table>"; + return summary; } QString RosterTooltip::buildVCardField(bool preferred, const QString& name, const QString& content) { - QString rowTemplate; - if (QApplication::layoutDirection() == Qt::RightToLeft) { - rowTemplate = QString("<tr><td>%3</td><td valign='middle'><strong>%2</strong></td><td valign='middle'>%1</td></tr>"); - } else { - rowTemplate = QString("<tr><td>%1</td><td valign='middle'><strong>%2</strong></td><td valign='middle'>%3</td></tr>"); - } - return rowTemplate.arg(preferred ? "<img src=':/icons/star-checked.png' />" : "", name, content); + QString rowTemplate; + if (QApplication::layoutDirection() == Qt::RightToLeft) { + rowTemplate = QString("<tr><td>%3</td><td valign='middle'><strong>%2</strong></td><td valign='middle'>%1</td></tr>"); + } else { + rowTemplate = QString("<tr><td>%1</td><td valign='middle'><strong>%2</strong></td><td valign='middle'>%3</td></tr>"); + } + return rowTemplate.arg(preferred ? "<img src=':/icons/star-checked.png' />" : "", name, content); } } diff --git a/Swift/QtUI/Roster/RosterTooltip.h b/Swift/QtUI/Roster/RosterTooltip.h index 37f5da2..642809f 100644 --- a/Swift/QtUI/Roster/RosterTooltip.h +++ b/Swift/QtUI/Roster/RosterTooltip.h @@ -16,12 +16,12 @@ class ContactRosterItem; class QtScaledAvatarCache; class RosterTooltip { - public: - static QString buildDetailedTooltip(ContactRosterItem* contact, QtScaledAvatarCache* cachedImageScaler); + public: + static QString buildDetailedTooltip(ContactRosterItem* contact, QtScaledAvatarCache* cachedImageScaler); - private: - static QString buildVCardSummary(VCard::ref vcard); - static QString buildVCardField(bool preferred, const QString& name, const QString& content); + private: + static QString buildVCardSummary(VCard::ref vcard); + static QString buildVCardField(bool preferred, const QString& name, const QString& content); }; } diff --git a/Swift/QtUI/Roster/main.cpp b/Swift/QtUI/Roster/main.cpp index c2fecb5..c0402e8 100644 --- a/Swift/QtUI/Roster/main.cpp +++ b/Swift/QtUI/Roster/main.cpp @@ -1,66 +1,67 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <QtGui> -#include "QtTreeWidget.h" -#include "QtTreeWidgetFactory.h" -#include "Swiften/Elements/StatusShow.h" +#include <Swiften/Elements/StatusShow.h> + +#include <Swift/QtUI/Roster/QtTreeWidget.h> +#include <Swift/QtUI/Roster/QtTreeWidgetFactory.h> int main(int argc, char *argv[]) { - QApplication app(argc, argv); + QApplication app(argc, argv); + + //Swift::RosterModel model; + + //QTreeView view; + //view.setModel(&model); + //view.setWindowTitle("A roster"); + //view.show(); - //Swift::RosterModel model; + Swift::QtTreeWidgetFactory treeWidgetFactory; + Swift::QtTreeWidget* tree = dynamic_cast<Swift::QtTreeWidget*>(treeWidgetFactory.createTreeWidget()); + tree->show(); + QList<Swift::QtTreeWidgetItem*> item3s; + for (int i = 0; i < 500; i++) { + Swift::QtTreeWidgetItem* group = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(tree)); + group->setText("People"); + group->setBackgroundColor(0xBBBBBB); + Swift::QtTreeWidgetItem* item1 = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); + Swift::QtTreeWidgetItem* item2 = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); + Swift::QtTreeWidgetItem* item3 = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); + Swift::QtTreeWidgetItem* item4 = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); + item1->setText("Remko"); + item2->setText("Kevin"); + item3->setText("Cath"); + item4->setText("KimTypo"); + item4->setText("Kim"); + item3s.push_back(item3); + } - //QTreeView view; - //view.setModel(&model); - //view.setWindowTitle("A roster"); - //view.show(); + Swift::QtTreeWidgetItem* group = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(tree)); + group->setText("Many People"); - Swift::QtTreeWidgetFactory treeWidgetFactory; - Swift::QtTreeWidget* tree = dynamic_cast<Swift::QtTreeWidget*>(treeWidgetFactory.createTreeWidget()); - tree->show(); - QList<Swift::QtTreeWidgetItem*> item3s; - for (int i = 0; i < 500; i++) { - Swift::QtTreeWidgetItem* group = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(tree)); - group->setText("People"); - group->setBackgroundColor(0xBBBBBB); - Swift::QtTreeWidgetItem* item1 = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); - Swift::QtTreeWidgetItem* item2 = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); - Swift::QtTreeWidgetItem* item3 = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); - Swift::QtTreeWidgetItem* item4 = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); - item1->setText("Remko"); - item2->setText("Kevin"); - item3->setText("Cath"); - item4->setText("KimTypo"); - item4->setText("Kim"); - item3s.push_back(item3); - } - - Swift::QtTreeWidgetItem* group = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(tree)); - group->setText("Many People"); - - Swift::QtTreeWidgetItem* person350; - Swift::QtTreeWidgetItem* person1200; + Swift::QtTreeWidgetItem* person350; + Swift::QtTreeWidgetItem* person1200; - for (int i = 0; i < 1500; i++) { - Swift::QtTreeWidgetItem* item = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); - item->setText(Q2PSTRING(QString("Some person %1").arg(i))); - item->setStatusShow(Swift::StatusShow::Away); - if (i == 350) person350 = item; - if (i == 1200) person1200 = item; - } + for (int i = 0; i < 1500; i++) { + Swift::QtTreeWidgetItem* item = dynamic_cast<Swift::QtTreeWidgetItem*>(treeWidgetFactory.createTreeWidgetItem(group)); + item->setText(Q2PSTRING(QString("Some person %1").arg(i))); + item->setStatusShow(Swift::StatusShow::Away); + if (i == 350) person350 = item; + if (i == 1200) person1200 = item; + } - for (int i = 0; i < item3s.size(); i++) { - item3s[i]->setStatusShow(Swift::StatusShow::XA); - } + for (int i = 0; i < item3s.size(); i++) { + item3s[i]->setStatusShow(Swift::StatusShow::XA); + } - person350->setStatusShow(Swift::StatusShow::DND); - person1200->setStatusShow(Swift::StatusShow::Online); + person350->setStatusShow(Swift::StatusShow::DND); + person1200->setStatusShow(Swift::StatusShow::Online); - return app.exec(); + return app.exec(); } |