/* * Squawk messenger. * Copyright (C) 2019 Yury Gubich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "preview.h" constexpr int margin = 6; 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): info(Shared::Global::getFileInfo(pPath)), path(pPath), maxSize(pMaxSize), actualSize(constrainAttachSize(info.size, maxSize)), cachedLabelSize(0, 0), position(pos), widget(0), label(0), parent(pParent), movie(0), fileReachable(true), actualPreview(false), right(pRight) { initializeElements(); if (fileReachable) { positionElements(); } } void Preview::initializeFont(const QFont& newFont) { font = newFont; font.setBold(true); metrics = QFontMetrics(font); } Preview::~Preview() { clean(); } void Preview::clean() { if (fileReachable) { if (info.preview == Shared::Global::FileInfo::Preview::animation) { delete movie; } delete widget; if (!actualPreview) { delete label; } else { actualPreview = false; } } else { fileReachable = true; } } void Preview::actualize(const QString& newPath, const QSize& newSize, const QPoint& newPoint) { bool positionChanged = false; bool sizeChanged = false; bool maxSizeChanged = false; if (maxSize != newSize) { maxSize = newSize; maxSizeChanged = true; QSize ns = constrainAttachSize(info.size, maxSize); if (actualSize != ns) { sizeChanged = true; actualSize = ns; } } if (position != newPoint) { position = newPoint; positionChanged = true; } if (!setPath(newPath) && fileReachable) { if (sizeChanged) { applyNewSize(); if (maxSizeChanged && !actualPreview) { applyNewMaxSize(); } } else if (maxSizeChanged) { applyNewMaxSize(); if (right) { positionChanged = true; } } if (positionChanged || !actualPreview) { positionElements(); } } } void Preview::setSize(const QSize& newSize) { bool sizeChanged = false; bool maxSizeChanged = false; if (maxSize != newSize) { maxSize = newSize; maxSizeChanged = true; QSize ns = constrainAttachSize(info.size, maxSize); if (actualSize != ns) { sizeChanged = true; actualSize = ns; } } if (fileReachable) { if (sizeChanged) { applyNewSize(); } if (maxSizeChanged || !actualPreview) { applyNewMaxSize(); if (right) { positionElements(); } } } } void Preview::applyNewSize() { switch (info.preview) { case Shared::Global::FileInfo::Preview::picture: { QImageReader img(path); if (!img.canRead()) { delete widget; fileReachable = false; } else { img.setScaledSize(actualSize); widget->resize(actualSize); widget->setPixmap(QPixmap::fromImage(img.read())); } } break; case Shared::Global::FileInfo::Preview::animation:{ movie->setScaledSize(actualSize); widget->resize(actualSize); } break; default: { QIcon icon = QIcon::fromTheme(info.mime.iconName()); widget->setPixmap(icon.pixmap(actualSize)); widget->resize(actualSize); } } } void Preview::applyNewMaxSize() { switch (info.preview) { case Shared::Global::FileInfo::Preview::picture: case Shared::Global::FileInfo::Preview::animation: break; default: { int labelWidth = maxSize.width() - actualSize.width() - margin; QString elidedName = metrics.elidedText(info.name, Qt::ElideMiddle, labelWidth); cachedLabelSize = metrics.boundingRect(elidedName).size(); label->setText(elidedName); label->resize(cachedLabelSize); } } } QSize Preview::size() const { if (actualPreview) { return actualSize; } else { return QSize(actualSize.width() + margin + cachedLabelSize.width(), actualSize.height()); } } bool Preview::isFileReachable() const { return fileReachable; } void Preview::setPosition(const QPoint& newPoint) { if (position != newPoint) { position = newPoint; if (fileReachable) { positionElements(); } } } bool Preview::setPath(const QString& newPath) { if (path != newPath) { path = newPath; info = Shared::Global::getFileInfo(path); actualSize = constrainAttachSize(info.size, maxSize); clean(); initializeElements(); if (fileReachable) { positionElements(); } return true; } else { return false; } } void Preview::initializeElements() { switch (info.preview) { case Shared::Global::FileInfo::Preview::picture: { QImageReader img(path); if (!img.canRead()) { fileReachable = false; } else { actualPreview = true; img.setScaledSize(actualSize); widget = new QLabel(parent); widget->setPixmap(QPixmap::fromImage(img.read())); widget->show(); } } break; case Shared::Global::FileInfo::Preview::animation:{ movie = new QMovie(path); QObject::connect(movie, &QMovie::error, std::bind(&Preview::handleQMovieError, this, std::placeholders::_1) ); if (!movie->isValid()) { fileReachable = false; delete movie; } else { actualPreview = true; movie->setScaledSize(actualSize); widget = new QLabel(parent); widget->setMovie(movie); movie->start(); widget->show(); } } break; default: { QIcon icon = QIcon::fromTheme(info.mime.iconName()); widget = new QLabel(parent); widget->setPixmap(icon.pixmap(actualSize)); widget->show(); label = new QLabel(parent); label->setFont(font); int labelWidth = maxSize.width() - actualSize.width() - margin; QString elidedName = metrics.elidedText(info.name, Qt::ElideMiddle, labelWidth); cachedLabelSize = metrics.boundingRect(elidedName).size(); label->setText(elidedName); label->show(); } } } 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; int y = position.y() + (actualSize.height() - cachedLabelSize.height()) / 2; label->move(x, y); } } QSize Preview::calculateAttachSize(const QString& path, const QRect& bounds) { Shared::Global::FileInfo info = Shared::Global::getFileInfo(path); return constrainAttachSize(info.size, bounds.size()); } QSize Preview::constrainAttachSize(QSize src, QSize bounds) { if (bounds.height() > maxAttachmentHeight) { bounds.setHeight(maxAttachmentHeight); } if (src.width() > bounds.width() || src.height() > bounds.height()) { src.scale(bounds, Qt::KeepAspectRatio); } return src; } void Preview::handleQMovieError(QImageReader::ImageReaderError error) { if (error == QImageReader::FileNotFoundError) { fileReachable = false; movie->deleteLater(); widget->deleteLater(); } }