From 4d3ba6b11f5704cf09c404e2307dada7ac665322 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 9 Jan 2022 17:32:23 +0300 Subject: [PATCH] 0.2.0 finalization --- CHANGELOG.md | 13 +- README.md | 4 +- core/main.cpp | 2 +- packaging/Archlinux/PKGBUILD | 4 +- shared/global.cpp | 2 +- shared/global.h | 1 + ui/widgets/messageline/feedview.cpp | 58 ++++-- ui/widgets/messageline/feedview.h | 3 + ui/widgets/messageline/messagedelegate.cpp | 220 ++++++++------------- ui/widgets/messageline/messagedelegate.h | 6 +- ui/widgets/messageline/preview.cpp | 55 ++++-- ui/widgets/messageline/preview.h | 5 +- 12 files changed, 194 insertions(+), 179 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf90231..09c382a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,28 @@ # Changelog -## Squawk 0.2.0 (Unreleased) +## Squawk 0.2.0 (Jan 10, 2022) ### Bug fixes - carbon copies switches on again after reconnection - requesting the history of the current chat after reconnection - global availability (in drop down list) gets restored after reconnection - status icon in active chat changes when presence of the pen pal changes - infinite progress when open the dialogue with something that has no history to show +- fallback icons for buttons, when no supported theme is installed (shunf4) +- better handling messages with no id (shunf4) +- removed dependency: uuid, now it's on Qt (shunf4) +- better requesting latest history (shunf4) ### Improvements - slightly reduced the traffic on the startup by not requesting history of all MUCs -- completely rewritten message feed, now it works way faster +- completely rewritten message feed, now it works way faster and looks cooler - OPTIONAL RUNTIME dependency: "KIO Widgets" that is supposed to allow you to open a file in your default file manager - show in folder now is supposed to try it's best to show file in folder, even you don't have KIO installed - once uploaded local files don't get second time uploaded - the remote URL is reused +- way better compilation time (vae) + +### New features +- pasting images from clipboard to attachment (shunf4) +- possible compilation for windows and macOS (shunf4) ## Squawk 0.1.5 (Jul 29, 2020) ### Bug fixes diff --git a/README.md b/README.md index e94972f..ff36f3c 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ [![AUR version](https://img.shields.io/aur/version/squawk?style=flat-square)](https://aur.archlinux.org/packages/squawk/) [![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me) -![Squawk screenshot](https://macaw.me/images/squawk/0.1.4.png) +![Squawk screenshot](https://macaw.me/images/squawk/0.2.0.png) ### Prerequisites - QT 5.12 *(lower versions might work but it wasn't tested)* - lmdb -- CMake 3.0 or higher +- CMake 3.3 or higher - qxmpp 1.1.0 or higher - KDE Frameworks: kwallet (optional) - KDE Frameworks: KIO (optional) diff --git a/core/main.cpp b/core/main.cpp index f63d4f8..d6eea3e 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char *argv[]) #endif QApplication::setApplicationName("squawk"); QApplication::setApplicationDisplayName("Squawk"); - QApplication::setApplicationVersion("0.1.5"); + QApplication::setApplicationVersion("0.2.0"); QTranslator qtTranslator; qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); diff --git a/packaging/Archlinux/PKGBUILD b/packaging/Archlinux/PKGBUILD index 20fea99..68e1558 100644 --- a/packaging/Archlinux/PKGBUILD +++ b/packaging/Archlinux/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Yury Gubich pkgname=squawk -pkgver=0.1.5 +pkgver=0.2.0 pkgrel=1 pkgdesc="An XMPP desktop messenger, written on pure c++ (qt)" arch=('i686' 'x86_64') @@ -11,7 +11,7 @@ makedepends=('cmake>=3.3' 'imagemagick' 'qt5-tools') optdepends=('kwallet: secure password storage (requires rebuild)') source=("$pkgname-$pkgver.tar.gz") -sha256sums=('e1a4c88be9f0481d2aa21078faf42fd0e9d66b490b6d8af82827d441cb58df25') +sha256sums=('8e93d3dbe1fc35cfecb7783af409c6a264244d11609b2241d4fe77d43d068419') build() { cd "$srcdir/squawk" cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release diff --git a/shared/global.cpp b/shared/global.cpp index d6f2169..5f3b4ed 100644 --- a/shared/global.cpp +++ b/shared/global.cpp @@ -144,7 +144,7 @@ Shared::Global::FileInfo Shared::Global::getFileInfo(const QString& path) size = defaultIconFileInfoHeight; } - itr = instance->fileCache.insert(std::make_pair(path, FileInfo({info.fileName(), size, type, p}))).first; + itr = instance->fileCache.insert(std::make_pair(path, FileInfo({info.absoluteFilePath(), info.fileName(), size, type, p}))).first; } return itr->second; diff --git a/shared/global.h b/shared/global.h index 03cf84d..b1ae59c 100644 --- a/shared/global.h +++ b/shared/global.h @@ -55,6 +55,7 @@ namespace Shared { animation }; + QString path; QString name; QSize size; QMimeType mime; diff --git a/ui/widgets/messageline/feedview.cpp b/ui/widgets/messageline/feedview.cpp index d83ca6b..34f9400 100644 --- a/ui/widgets/messageline/feedview.cpp +++ b/ui/widgets/messageline/feedview.cpp @@ -43,6 +43,7 @@ FeedView::FeedView(QWidget* parent): QAbstractItemView(parent), hints(), vo(0), + elementMargin(0), specialDelegate(false), specialModel(false), clearWidgetsMode(false), @@ -106,7 +107,7 @@ QRect FeedView::visualRect(const QModelIndex& index) const } else { const Hint& hint = hints.at(row); const QWidget* vp = viewport(); - return QRect(0, vp->height() - hint.height - hint.offset + vo, vp->width(), hint.height); + return QRect(hint.x, vp->height() - hint.height - hint.offset + vo, hint.width, hint.height); } } @@ -198,7 +199,7 @@ void FeedView::updateGeometries() option.rect.setWidth(layoutBounds.width()); hints.clear(); - uint32_t previousOffset = 0; + uint32_t previousOffset = elementMargin; QDateTime lastDate; for (int i = 0, size = m->rowCount(); i < size; ++i) { QModelIndex index = m->index(i, 0, rootIndex()); @@ -206,19 +207,32 @@ void FeedView::updateGeometries() if (i > 0) { if (currentDate.daysTo(lastDate) > 0) { previousOffset += dividerMetrics.height() + dateDeviderMargin * 2; + } else { + previousOffset += elementMargin; } } lastDate = currentDate; - int height = itemDelegate(index)->sizeHint(option, index).height(); + QSize messageSize = itemDelegate(index)->sizeHint(option, index); + uint32_t offsetX(0); + if (specialDelegate) { + if (index.data(Models::MessageFeed::SentByMe).toBool()) { + offsetX = layoutBounds.width() - messageSize.width() - MessageDelegate::avatarHeight - MessageDelegate::margin * 2; + } else { + offsetX = MessageDelegate::avatarHeight + MessageDelegate::margin * 2; + } + } + hints.emplace_back(Hint({ false, previousOffset, - static_cast(height) + static_cast(messageSize.height()), + static_cast(messageSize.width()), + offsetX })); - previousOffset += height; + previousOffset += messageSize.height(); } - int totalHeight = previousOffset - layoutBounds.height(); + int totalHeight = previousOffset - layoutBounds.height() + dividerMetrics.height() + dateDeviderMargin * 2; if (modelState != Models::MessageFeed::complete) { totalHeight += progressSize; } @@ -240,7 +254,7 @@ void FeedView::updateGeometries() bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewItem& option, const QAbstractItemModel* m, uint32_t totalHeight) { - uint32_t previousOffset = 0; + uint32_t previousOffset = elementMargin; bool success = true; QDateTime lastDate; for (int i = 0, size = m->rowCount(); i < size; ++i) { @@ -249,21 +263,39 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt if (i > 0) { if (currentDate.daysTo(lastDate) > 0) { previousOffset += dateDeviderMargin * 2 + dividerMetrics.height(); + } else { + previousOffset += elementMargin; } } lastDate = currentDate; - int height = itemDelegate(index)->sizeHint(option, index).height(); + QSize messageSize = itemDelegate(index)->sizeHint(option, index); - if (previousOffset + height > totalHeight) { + if (previousOffset + messageSize.height() + elementMargin > totalHeight) { success = false; break; } + + uint32_t offsetX(0); + if (specialDelegate) { + if (index.data(Models::MessageFeed::SentByMe).toBool()) { + offsetX = option.rect.width() - messageSize.width() - MessageDelegate::avatarHeight - MessageDelegate::margin * 2; + } else { + offsetX = MessageDelegate::avatarHeight + MessageDelegate::margin * 2; + } + } hints.emplace_back(Hint({ false, previousOffset, - static_cast(height) + static_cast(messageSize.height()), + static_cast(messageSize.width()), + offsetX })); - previousOffset += height; + previousOffset += messageSize.height(); + } + + previousOffset += dateDeviderMargin * 2 + dividerMetrics.height(); + if (previousOffset > totalHeight) { + success = false; } return success; @@ -336,7 +368,7 @@ void FeedView::paintEvent(QPaintEvent* event) lastDate = currentDate; } if (!lastDate.isNull() && inZone) { //if after drawing all messages there is still space - drawDateDevider(option.rect.bottom(), lastDate, painter); + drawDateDevider(option.rect.top() - dateDeviderMargin * 2 - dividerMetrics.height(), lastDate, painter); } if (clearWidgetsMode && specialDelegate) { @@ -423,10 +455,12 @@ void FeedView::setItemDelegate(QAbstractItemDelegate* delegate) MessageDelegate* del = dynamic_cast(delegate); if (del) { specialDelegate = true; + elementMargin = MessageDelegate::margin; connect(del, &MessageDelegate::buttonPushed, this, &FeedView::onMessageButtonPushed); connect(del, &MessageDelegate::invalidPath, this, &FeedView::onMessageInvalidPath); } else { specialDelegate = false; + elementMargin = 0; } } diff --git a/ui/widgets/messageline/feedview.h b/ui/widgets/messageline/feedview.h index 5e08946..8bcd913 100644 --- a/ui/widgets/messageline/feedview.h +++ b/ui/widgets/messageline/feedview.h @@ -80,9 +80,12 @@ private: bool dirty; uint32_t offset; uint32_t height; + uint32_t width; + uint32_t x; }; std::deque hints; int vo; + int elementMargin; bool specialDelegate; bool specialModel; bool clearWidgetsMode; diff --git a/ui/widgets/messageline/messagedelegate.cpp b/ui/widgets/messageline/messagedelegate.cpp index 5dd0dce..d692752 100644 --- a/ui/widgets/messageline/messagedelegate.cpp +++ b/ui/widgets/messageline/messagedelegate.cpp @@ -26,8 +26,8 @@ #include "messagedelegate.h" #include "messagefeed.h" -constexpr int avatarHeight = 50; -constexpr int margin = 6; +int MessageDelegate::avatarHeight(50); +int MessageDelegate::margin(6); constexpr int textMargin = 2; constexpr int statusIconSize = 16; constexpr float nickFontMultiplier = 1.1; @@ -45,6 +45,7 @@ MessageDelegate::MessageDelegate(QObject* parent): nickMetrics(nickFont), dateMetrics(dateFont), buttonHeight(0), + buttonWidth(0), barHeight(0), buttons(new std::map()), bars(new std::map()), @@ -55,8 +56,9 @@ MessageDelegate::MessageDelegate(QObject* parent): idsToKeep(new std::set()), clearingWidgets(false) { - QPushButton btn; + QPushButton btn(QCoreApplication::translate("MessageLine", "Download")); buttonHeight = btn.sizeHint().height(); + buttonWidth = btn.sizeHint().width(); QProgressBar bar; barHeight = bar.sizeHint().height(); @@ -107,141 +109,79 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); -// if (option.state & QStyle::State_MouseOver) { -// painter->fillRect(option.rect, option.palette.brush(QPalette::Inactive, QPalette::Highlight)); -// } - - + paintBubble(data, painter, option); bool ntds = needToDrawSender(index, data); if (ntds || option.rect.y() < 1) { paintAvatar(data, index, option, painter); } QStyleOptionViewItem opt = option; - QRect messageRect = option.rect.adjusted(margin, margin / 2, -(avatarHeight + 2 * margin), -margin / 2); + opt.rect = option.rect.adjusted(bubbleMargin, bubbleMargin, -bubbleMargin, -bubbleMargin / 2); if (!data.sentByMe) { opt.displayAlignment = Qt::AlignLeft | Qt::AlignTop; - messageRect.adjust(avatarHeight + margin, 0, avatarHeight + margin, 0); } else { opt.displayAlignment = Qt::AlignRight | Qt::AlignTop; } - QPoint bubbleBegin = messageRect.topLeft(); - messageRect.adjust(bubbleMargin, bubbleMargin, -bubbleMargin, -bubbleMargin / 2); - opt.rect = messageRect; - - QSize messageSize(0, 0); QSize bodySize(0, 0); if (data.text.size() > 0) { - messageSize = bodyMetrics.boundingRect(messageRect, Qt::TextWordWrap, data.text).size(); - bodySize = messageSize; - } - - messageSize.rheight() += dateMetrics.height(); - QString dateString = data.date.toLocalTime().toString("hh:mm"); - - if (messageSize.width() < opt.rect.width()) { - if (ntds) { - QSize senderSize = nickMetrics.boundingRect(messageRect, 0, data.sender).size(); - if (senderSize.width() > messageSize.width()) { - messageSize.setWidth(senderSize.width()); - } - } - QSize dateSize = dateMetrics.boundingRect(messageRect, 0, dateString).size(); - int addition = 0; - - if (data.correction.corrected) { - addition += margin + statusIconSize; - } - if (data.sentByMe) { - addition += margin + statusIconSize; - } - if (dateSize.width() + addition > messageSize.width()) { - messageSize.setWidth(dateSize.width() + addition); - } - } else { - messageSize.setWidth(opt.rect.width()); - } - - painter->save(); - - int storedY = opt.rect.y(); - if (ntds) { - opt.rect.adjust(0, nickMetrics.lineSpacing() + textMargin, 0, 0); - } - - int attWidth(0); - switch (data.attach.state) { - case Models::none: - clearHelperWidget(data); //i can't imagine the situation where it's gonna be needed - break; //but it's a possible performance problem - case Models::uploading: - attWidth = std::max(paintPreview(data, painter, opt), attWidth); - [[fallthrough]]; - case Models::downloading: - messageSize.setWidth(opt.rect.width()); - messageSize.rheight() += barHeight + textMargin + opt.rect.y() - storedY; - paintBubble(data, painter, messageSize, opt, bubbleBegin); - attWidth = std::max(paintBar(getBar(data), painter, data.sentByMe, opt), attWidth); - break; - case Models::remote: - attWidth = std::max(paintButton(getButton(data), painter, data.sentByMe, opt), attWidth); - break; - case Models::ready: - case Models::local: - clearHelperWidget(data); - attWidth = std::max(paintPreview(data, painter, opt), attWidth); - break; - case Models::errorDownload: { - attWidth = std::max(paintButton(getButton(data), painter, data.sentByMe, opt), attWidth); - attWidth = std::max(paintComment(data, painter, opt), attWidth); - } - - break; - case Models::errorUpload:{ - clearHelperWidget(data); - attWidth = std::max(paintPreview(data, painter, opt), attWidth); - attWidth = std::max(paintComment(data, painter, opt), attWidth); - } - break; - } - painter->restore(); - if (data.attach.state != Models::uploading && data.attach.state != Models::downloading) { - messageSize.rheight() += opt.rect.y() - storedY; - messageSize.setWidth(std::max(attWidth, messageSize.width())); - paintBubble(data, painter, messageSize, opt, bubbleBegin); + bodySize = bodyMetrics.boundingRect(opt.rect, Qt::TextWordWrap, data.text).size(); } QRect rect; if (ntds) { painter->setFont(nickFont); - int storedY2 = opt.rect.y(); - opt.rect.setY(storedY); painter->drawText(opt.rect, opt.displayAlignment, data.sender, &rect); - opt.rect.setY(storedY2); + opt.rect.adjust(0, nickMetrics.lineSpacing() + textMargin, 0, 0); } + + painter->save(); + switch (data.attach.state) { + case Models::none: + clearHelperWidget(data); //i can't imagine the situation where it's gonna be needed + break; //but it's a possible performance problem + case Models::uploading: + paintPreview(data, painter, opt); + [[fallthrough]]; + case Models::downloading: + paintBar(getBar(data), painter, data.sentByMe, opt); + break; + case Models::remote: + paintButton(getButton(data), painter, data.sentByMe, opt); + break; + case Models::ready: + case Models::local: + clearHelperWidget(data); + paintPreview(data, painter, opt); + break; + case Models::errorDownload: { + paintButton(getButton(data), painter, data.sentByMe, opt); + paintComment(data, painter, opt); + } + + break; + case Models::errorUpload:{ + clearHelperWidget(data); + paintPreview(data, painter, opt); + paintComment(data, painter, opt); + } + break; + } + painter->restore(); - int messageLeft = INT16_MAX; - int messageRight = opt.rect.x() + messageSize.width(); QWidget* vp = static_cast(painter->device()); if (data.text.size() > 0) { QLabel* body = getBody(data); body->setParent(vp); - body->setMaximumWidth(bodySize.width()); - body->setMinimumWidth(bodySize.width()); - body->setMinimumHeight(bodySize.height()); - body->setMaximumHeight(bodySize.height()); - body->setAlignment(opt.displayAlignment); - messageLeft = opt.rect.x(); - if (data.sentByMe) { - messageLeft = opt.rect.topRight().x() - bodySize.width(); - } - body->move(messageLeft, opt.rect.y()); + body->setMinimumSize(bodySize); + body->setMaximumSize(bodySize); + body->move(opt.rect.left(), opt.rect.y()); body->show(); opt.rect.adjust(0, bodySize.height() + textMargin, 0, 0); } painter->setFont(dateFont); QColor q = painter->pen().color(); + QString dateString = data.date.toLocalTime().toString("hh:mm"); q.setAlpha(180); painter->setPen(q); painter->drawText(opt.rect, opt.displayAlignment, dateString, &rect); @@ -250,7 +190,7 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio QLabel* statusIcon = getStatusIcon(data); statusIcon->setParent(vp); - statusIcon->move(opt.rect.topRight().x() - messageSize.width(), currentY); + statusIcon->move(opt.rect.left(), currentY); statusIcon->show(); opt.rect.adjust(0, statusIconSize + textMargin, 0, 0); @@ -261,9 +201,9 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio pencilIcon->setParent(vp); if (data.sentByMe) { - pencilIcon->move(opt.rect.topRight().x() - messageSize.width() + statusIconSize + margin, currentY); + pencilIcon->move(opt.rect.left() + statusIconSize + margin, currentY); } else { - pencilIcon->move(messageRight - statusIconSize - margin, currentY); + pencilIcon->move(opt.rect.right() - statusIconSize - margin, currentY); } pencilIcon->show(); } else { @@ -281,19 +221,16 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio } } -void MessageDelegate::paintBubble(const Models::FeedItem& data, QPainter* painter, const QSize& messageSize, QStyleOptionViewItem& option, QPoint bubbleBegin) const +void MessageDelegate::paintBubble(const Models::FeedItem& data, QPainter* painter, const QStyleOptionViewItem& option) const { painter->save(); if (data.sentByMe) { - bubbleBegin.setX(option.rect.topRight().x() - messageSize.width() - bubbleMargin); painter->setBrush(option.palette.brush(QPalette::Inactive, QPalette::Highlight)); } else { painter->setBrush(option.palette.brush(QPalette::Window)); } - QSize bubbleAddition(2 * bubbleMargin, 1.5 * bubbleMargin); - QRect bubble(bubbleBegin, messageSize + bubbleAddition); painter->setPen(Qt::NoPen); - painter->drawRoundedRect(bubble, bubbleBorderRadius, bubbleBorderRadius); + painter->drawRoundedRect(option.rect, bubbleBorderRadius, bubbleBorderRadius); painter->restore(); } @@ -330,7 +267,7 @@ void MessageDelegate::paintAvatar(const Models::FeedItem& data, const QModelInde int ax; if (data.sentByMe) { - ax = option.rect.width() - avatarHeight - margin; + ax = option.rect.x() + option.rect.width() + margin; } else { ax = margin; } @@ -381,36 +318,51 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel [[fallthrough]]; case Models::downloading: messageSize.rheight() += barHeight + textMargin; + messageSize.setWidth(messageRect.width()); break; case Models::remote: messageSize.rheight() += buttonHeight + textMargin; + messageSize.setWidth(std::max(messageSize.width(), buttonWidth)); break; case Models::ready: - case Models::local: - messageSize.rheight() += Preview::calculateAttachSize(data.attach.localPath, messageRect).height() + textMargin; + case Models::local: { + QSize aSize = Preview::calculateAttachSize(data.attach.localPath, messageRect); + messageSize.rheight() += aSize.height() + textMargin; + messageSize.setWidth(std::max(messageSize.width(), aSize.width())); + } break; - case Models::errorDownload: - messageSize.rheight() += buttonHeight + textMargin; - messageSize.rheight() += dateMetrics.boundingRect(messageRect, Qt::TextWordWrap, data.attach.error).size().height() + textMargin; + case Models::errorDownload: { + QSize commentSize = dateMetrics.boundingRect(messageRect, Qt::TextWordWrap, data.attach.error).size(); + messageSize.rheight() += commentSize.height() + buttonHeight + textMargin * 2; + messageSize.setWidth(std::max(messageSize.width(), std::max(commentSize.width(), buttonWidth))); + } break; - case Models::errorUpload: - messageSize.rheight() += Preview::calculateAttachSize(data.attach.localPath, messageRect).height() + textMargin; - messageSize.rheight() += dateMetrics.boundingRect(messageRect, Qt::TextWordWrap, data.attach.error).size().height() + textMargin; + case Models::errorUpload: { + QSize aSize = Preview::calculateAttachSize(data.attach.localPath, messageRect); + QSize commentSize = dateMetrics.boundingRect(messageRect, Qt::TextWordWrap, data.attach.error).size(); + messageSize.rheight() += aSize.height() + commentSize.height() + textMargin * 2; + messageSize.setWidth(std::max(messageSize.width(), std::max(commentSize.width(), aSize.width()))); + } break; } if (needToDrawSender(index, data)) { - messageSize.rheight() += nickMetrics.lineSpacing() + textMargin; + QSize senderSize = nickMetrics.boundingRect(messageRect, 0, data.sender).size(); + messageSize.rheight() += senderSize.height() + textMargin; + messageSize.setWidth(std::max(senderSize.width(), messageSize.width())); } - messageSize.rheight() += bubbleMargin + bubbleMargin / 2; - messageSize.rheight() += dateMetrics.height() > statusIconSize ? dateMetrics.height() : statusIconSize; - -// if (messageSize.height() < avatarHeight) { -// messageSize.setHeight(avatarHeight); -// } - - messageSize.rheight() += margin; + QString dateString = data.date.toLocalTime().toString("hh:mm"); + QSize dateSize = dateMetrics.boundingRect(messageRect, 0, dateString).size(); + messageSize.rheight() += bubbleMargin * 1.5; + messageSize.rheight() += dateSize.height() > statusIconSize ? dateSize.height() : statusIconSize; + + int statusWidth = dateSize.width() + statusIconSize + margin; + if (data.correction.corrected) { + statusWidth += statusIconSize + margin; + } + messageSize.setWidth(std::max(statusWidth, messageSize.width())); + messageSize.rwidth() += 2 * bubbleMargin; return messageSize; } @@ -508,7 +460,7 @@ int MessageDelegate::paintPreview(const Models::FeedItem& data, QPainter* painte preview->actualize(data.attach.localPath, size, option.rect.topLeft()); } else { QWidget* vp = static_cast(painter->device()); - preview = new Preview(data.attach.localPath, size, option.rect.topLeft(), data.sentByMe, vp); + preview = new Preview(data.attach.localPath, size, option.rect.topLeft(), vp); previews->insert(std::make_pair(data.id, preview)); } diff --git a/ui/widgets/messageline/messagedelegate.h b/ui/widgets/messageline/messagedelegate.h index 87a79c9..b58a1bb 100644 --- a/ui/widgets/messageline/messagedelegate.h +++ b/ui/widgets/messageline/messagedelegate.h @@ -55,6 +55,9 @@ public: bool editorEvent(QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index) override; void endClearWidgets(); void beginClearWidgets(); + + static int avatarHeight; + static int margin; signals: void buttonPushed(const QString& messageId) const; @@ -66,7 +69,7 @@ protected: int paintPreview(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const; int paintComment(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const; void paintAvatar(const Models::FeedItem& data, const QModelIndex& index, const QStyleOptionViewItem& option, QPainter* painter) const; - void paintBubble(const Models::FeedItem& data, QPainter* painter, const QSize& messageSize, QStyleOptionViewItem& option, QPoint bubbleBegin) const; + void paintBubble(const Models::FeedItem& data, QPainter* painter, const QStyleOptionViewItem& option) const; QPushButton* getButton(const Models::FeedItem& data) const; QProgressBar* getBar(const Models::FeedItem& data) const; QLabel* getStatusIcon(const Models::FeedItem& data) const; @@ -94,6 +97,7 @@ private: QFontMetrics dateMetrics; int buttonHeight; + int buttonWidth; int barHeight; std::map* buttons; diff --git a/ui/widgets/messageline/preview.cpp b/ui/widgets/messageline/preview.cpp index e54fce6..137293f 100644 --- a/ui/widgets/messageline/preview.cpp +++ b/ui/widgets/messageline/preview.cpp @@ -25,9 +25,8 @@ constexpr int maxAttachmentHeight = 500; QFont Preview::font; QFontMetrics Preview::metrics(Preview::font); -Preview::Preview(const QString& pPath, const QSize& pMaxSize, const QPoint& pos, bool pRight, QWidget* pParent): +Preview::Preview(const QString& pPath, const QSize& pMaxSize, const QPoint& pos, QWidget* pParent): info(Shared::Global::getFileInfo(pPath)), - path(pPath), maxSize(pMaxSize), actualSize(constrainAttachSize(info.size, maxSize)), cachedLabelSize(0, 0), @@ -37,8 +36,7 @@ Preview::Preview(const QString& pPath, const QSize& pMaxSize, const QPoint& pos, parent(pParent), movie(0), fileReachable(true), - actualPreview(false), - right(pRight) + actualPreview(false) { initializeElements(); @@ -104,9 +102,6 @@ void Preview::actualize(const QString& newPath, const QSize& newSize, const QPoi } } else if (maxSizeChanged) { applyNewMaxSize(); - if (right) { - positionChanged = true; - } } if (positionChanged || !actualPreview) { positionElements(); @@ -135,9 +130,6 @@ void Preview::setSize(const QSize& newSize) } if (maxSizeChanged || !actualPreview) { applyNewMaxSize(); - if (right) { - positionElements(); - } } } } @@ -146,7 +138,7 @@ void Preview::applyNewSize() { switch (info.preview) { case Shared::Global::FileInfo::Preview::picture: { - QImageReader img(path); + QImageReader img(info.path); if (!img.canRead()) { delete widget; fileReachable = false; @@ -216,9 +208,8 @@ void Preview::setPosition(const QPoint& newPoint) bool Preview::setPath(const QString& newPath) { - if (path != newPath) { - path = newPath; - info = Shared::Global::getFileInfo(path); + if (info.path != newPath) { + info = Shared::Global::getFileInfo(newPath); actualSize = constrainAttachSize(info.size, maxSize); clean(); initializeElements(); @@ -235,7 +226,7 @@ void Preview::initializeElements() { switch (info.preview) { case Shared::Global::FileInfo::Preview::picture: { - QImageReader img(path); + QImageReader img(info.path); if (!img.canRead()) { fileReachable = false; } else { @@ -248,7 +239,7 @@ void Preview::initializeElements() } break; case Shared::Global::FileInfo::Preview::animation:{ - movie = new QMovie(path); + movie = new QMovie(info.path); QObject::connect(movie, &QMovie::error, std::bind(&Preview::handleQMovieError, this, std::placeholders::_1) ); @@ -289,9 +280,6 @@ void Preview::initializeElements() void Preview::positionElements() { int start = position.x(); - if (right) { - start += maxSize.width() - size().width(); - } widget->move(start, position.y()); if (!actualPreview) { int x = start + actualSize.width() + margin; @@ -300,11 +288,36 @@ void Preview::positionElements() } } +bool Preview::canVisualize(const Shared::Global::FileInfo& info) +{ + switch (info.preview) { + case Shared::Global::FileInfo::Preview::picture: { + QImageReader img(info.path); + return img.canRead(); + } + break; + case Shared::Global::FileInfo::Preview::animation:{ + QMovie movie(info.path); + return movie.isValid(); + } + break; + default: { + return false; + } + } +} + QSize Preview::calculateAttachSize(const QString& path, const QRect& bounds) { Shared::Global::FileInfo info = Shared::Global::getFileInfo(path); - - return constrainAttachSize(info.size, bounds.size()); + QSize constrained = constrainAttachSize(info.size, bounds.size()); + if (!canVisualize(info)) { + int maxLabelWidth = bounds.width() - info.size.width() - margin; + QString elidedName = metrics.elidedText(info.name, Qt::ElideMiddle, maxLabelWidth); + int labelWidth = metrics.boundingRect(elidedName).size().width(); + constrained.rwidth() += margin + labelWidth; + } + return constrained; } QSize Preview::constrainAttachSize(QSize src, QSize bounds) diff --git a/ui/widgets/messageline/preview.h b/ui/widgets/messageline/preview.h index 004ed45..5165137 100644 --- a/ui/widgets/messageline/preview.h +++ b/ui/widgets/messageline/preview.h @@ -38,7 +38,7 @@ */ class Preview { public: - Preview(const QString& pPath, const QSize& pMaxSize, const QPoint& pos, bool pRight, QWidget* parent); + Preview(const QString& pPath, const QSize& pMaxSize, const QPoint& pos, QWidget* parent); ~Preview(); void actualize(const QString& newPath, const QSize& newSize, const QPoint& newPoint); @@ -51,6 +51,7 @@ public: static void initializeFont(const QFont& newFont); static QSize constrainAttachSize(QSize src, QSize bounds); static QSize calculateAttachSize(const QString& path, const QRect& bounds); + static bool canVisualize(const Shared::Global::FileInfo& info); static QFont font; static QFontMetrics metrics; @@ -64,7 +65,6 @@ private: private: Shared::Global::FileInfo info; - QString path; QSize maxSize; QSize actualSize; QSize cachedLabelSize; @@ -75,7 +75,6 @@ private: QMovie* movie; bool fileReachable; bool actualPreview; - bool right; }; #endif // PREVIEW_H