summary refs log tree commit diff
path: root/src/timeline/widgets
diff options
context:
space:
mode:
authorKonstantinos Sideris <sideris.konstantin@gmail.com>2017-11-30 13:53:28 +0200
committerKonstantinos Sideris <sideris.konstantin@gmail.com>2017-11-30 13:53:28 +0200
commit32c83405771b2f7a751783529d17e1b84dad4224 (patch)
tree70b51c8f019bfcaae99207fba8d0214e4b69e94d /src/timeline/widgets
parentUse templates for the TimelineItem generation (diff)
downloadnheko-32c83405771b2f7a751783529d17e1b84dad4224.tar.xz
Create directories for related files
Diffstat (limited to 'src/timeline/widgets')
-rw-r--r--src/timeline/widgets/FileItem.cc208
-rw-r--r--src/timeline/widgets/ImageItem.cc223
2 files changed, 431 insertions, 0 deletions
diff --git a/src/timeline/widgets/FileItem.cc b/src/timeline/widgets/FileItem.cc
new file mode 100644
index 00000000..8d0100c7
--- /dev/null
+++ b/src/timeline/widgets/FileItem.cc
@@ -0,0 +1,208 @@
+/*
+ * nheko Copyright (C) 2017  Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <QBrush>
+#include <QDebug>
+#include <QDesktopServices>
+#include <QFile>
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QPainter>
+#include <QPixmap>
+
+#include "timeline/widgets/FileItem.h"
+
+namespace events = matrix::events;
+namespace msgs   = matrix::events::messages;
+
+void
+FileItem::init()
+{
+        setMouseTracking(true);
+        setCursor(Qt::PointingHandCursor);
+        setAttribute(Qt::WA_Hover, true);
+
+        icon_.addFile(":/icons/icons/ui/arrow-pointing-down.png");
+
+        QList<QString> url_parts = url_.toString().split("mxc://");
+        if (url_parts.size() != 2) {
+                qDebug() << "Invalid format for image" << url_.toString();
+                return;
+        }
+
+        QString media_params = url_parts[1];
+        url_                 = QString("%1/_matrix/media/r0/download/%2")
+                 .arg(client_.data()->getHomeServer().toString(), media_params);
+
+        connect(client_.data(), &MatrixClient::fileDownloaded, this, &FileItem::fileDownloaded);
+}
+
+FileItem::FileItem(QSharedPointer<MatrixClient> client,
+                   const events::MessageEvent<msgs::File> &event,
+                   QWidget *parent)
+  : QWidget(parent)
+  , url_{event.msgContent().url()}
+  , text_{event.content().body()}
+  , event_{event}
+  , client_{client}
+{
+        readableFileSize_ = calculateFileSize(event.msgContent().info().size);
+
+        init();
+}
+
+FileItem::FileItem(QSharedPointer<MatrixClient> client,
+                   const QString &url,
+                   const QString &filename,
+                   QWidget *parent)
+  : QWidget(parent)
+  , url_{url}
+  , text_{QFileInfo(filename).fileName()}
+  , client_{client}
+{
+        readableFileSize_ = calculateFileSize(QFileInfo(filename).size());
+
+        init();
+}
+
+QString
+FileItem::calculateFileSize(int nbytes) const
+{
+        if (nbytes < 1024)
+                return QString("%1 B").arg(nbytes);
+
+        if (nbytes < 1024 * 1024)
+                return QString("%1 KB").arg(nbytes / 1024);
+
+        return QString("%1 MB").arg(nbytes / 1024 / 1024);
+}
+
+void
+FileItem::openUrl()
+{
+        if (url_.toString().isEmpty())
+                return;
+
+        if (!QDesktopServices::openUrl(url_))
+                qWarning() << "Could not open url" << url_.toString();
+}
+
+QSize
+FileItem::sizeHint() const
+{
+        return QSize(MaxWidth, Height);
+}
+
+void
+FileItem::mousePressEvent(QMouseEvent *event)
+{
+        if (event->button() != Qt::LeftButton)
+                return;
+
+        auto point = event->pos();
+
+        // Click on the download icon.
+        if (QRect(HorizontalPadding, VerticalPadding / 2, IconDiameter, IconDiameter)
+              .contains(point)) {
+                filenameToSave_ = QFileDialog::getSaveFileName(this, tr("Save File"), text_);
+
+                if (filenameToSave_.isEmpty())
+                        return;
+
+                client_->downloadFile(event_.eventId(), url_);
+        } else {
+                openUrl();
+        }
+}
+
+void
+FileItem::fileDownloaded(const QString &event_id, const QByteArray &data)
+{
+        if (event_id != event_.eventId())
+                return;
+
+        try {
+                QFile file(filenameToSave_);
+
+                if (!file.open(QIODevice::WriteOnly))
+                        return;
+
+                file.write(data);
+                file.close();
+        } catch (const std::exception &ex) {
+                qDebug() << "Error while saving file to:" << ex.what();
+        }
+}
+
+void
+FileItem::paintEvent(QPaintEvent *event)
+{
+        Q_UNUSED(event);
+
+        QPainter painter(this);
+        painter.setRenderHint(QPainter::Antialiasing);
+
+        QFont font("Open Sans");
+        font.setPixelSize(12);
+        font.setWeight(80);
+
+        QFontMetrics fm(font);
+
+        int computedWidth = std::min(
+          fm.width(text_) + 2 * IconRadius + VerticalPadding * 2 + TextPadding, (double)MaxWidth);
+
+        QPainterPath path;
+        path.addRoundedRect(QRectF(0, 0, computedWidth, Height), 10, 10);
+
+        painter.setPen(Qt::NoPen);
+        painter.fillPath(path, backgroundColor_);
+        painter.drawPath(path);
+
+        QPainterPath circle;
+        circle.addEllipse(QPoint(IconXCenter, IconYCenter), IconRadius, IconRadius);
+
+        painter.setPen(Qt::NoPen);
+        painter.fillPath(circle, iconColor_);
+        painter.drawPath(circle);
+
+        icon_.paint(&painter,
+                    QRect(IconXCenter - DownloadIconRadius / 2,
+                          IconYCenter - DownloadIconRadius / 2,
+                          DownloadIconRadius,
+                          DownloadIconRadius),
+                    Qt::AlignCenter,
+                    QIcon::Normal);
+
+        const int textStartX = HorizontalPadding + 2 * IconRadius + TextPadding;
+        const int textStartY = VerticalPadding + fm.ascent() / 2;
+
+        // Draw the filename.
+        QString elidedText =
+          fm.elidedText(text_,
+                        Qt::ElideRight,
+                        computedWidth - HorizontalPadding * 2 - TextPadding - 2 * IconRadius);
+
+        painter.setFont(font);
+        painter.setPen(QPen(textColor_));
+        painter.drawText(QPoint(textStartX, textStartY), elidedText);
+
+        // Draw the filesize.
+        font.setWeight(50);
+        painter.setFont(font);
+        painter.setPen(QPen(textColor_));
+        painter.drawText(QPoint(textStartX, textStartY + 1.5 * fm.ascent()), readableFileSize_);
+}
diff --git a/src/timeline/widgets/ImageItem.cc b/src/timeline/widgets/ImageItem.cc
new file mode 100644
index 00000000..106fc79b
--- /dev/null
+++ b/src/timeline/widgets/ImageItem.cc
@@ -0,0 +1,223 @@
+/*
+ * nheko Copyright (C) 2017  Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <QBrush>
+#include <QDebug>
+#include <QDesktopServices>
+#include <QFileInfo>
+#include <QPainter>
+#include <QPixmap>
+
+#include "dialogs/ImageOverlayDialog.h"
+#include "timeline/widgets/ImageItem.h"
+
+namespace events = matrix::events;
+namespace msgs   = matrix::events::messages;
+
+ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
+                     const events::MessageEvent<msgs::Image> &event,
+                     QWidget *parent)
+  : QWidget(parent)
+  , event_{event}
+  , client_{client}
+{
+        setMouseTracking(true);
+        setCursor(Qt::PointingHandCursor);
+        setAttribute(Qt::WA_Hover, true);
+
+        url_  = event.msgContent().url();
+        text_ = event.content().body();
+
+        QList<QString> url_parts = url_.toString().split("mxc://");
+
+        if (url_parts.size() != 2) {
+                qDebug() << "Invalid format for image" << url_.toString();
+                return;
+        }
+
+        QString media_params = url_parts[1];
+        url_                 = QString("%1/_matrix/media/r0/download/%2")
+                 .arg(client_.data()->getHomeServer().toString(), media_params);
+
+        client_.data()->downloadImage(event.eventId(), url_);
+
+        connect(client_.data(),
+                SIGNAL(imageDownloaded(const QString &, const QPixmap &)),
+                this,
+                SLOT(imageDownloaded(const QString &, const QPixmap &)));
+}
+
+ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
+                     const QString &url,
+                     const QString &filename,
+                     QWidget *parent)
+  : QWidget(parent)
+  , url_{url}
+  , text_{QFileInfo(filename).fileName()}
+  , client_{client}
+{
+        setMouseTracking(true);
+        setCursor(Qt::PointingHandCursor);
+        setAttribute(Qt::WA_Hover, true);
+
+        QList<QString> url_parts = url_.toString().split("mxc://");
+
+        if (url_parts.size() != 2) {
+                qDebug() << "Invalid format for image" << url_.toString();
+                return;
+        }
+
+        QString media_params = url_parts[1];
+        url_                 = QString("%1/_matrix/media/r0/download/%2")
+                 .arg(client_.data()->getHomeServer().toString(), media_params);
+
+        setImage(QPixmap(filename));
+}
+
+void
+ImageItem::imageDownloaded(const QString &event_id, const QPixmap &img)
+{
+        if (event_id != event_.eventId())
+                return;
+
+        setImage(img);
+}
+
+void
+ImageItem::openUrl()
+{
+        if (url_.toString().isEmpty())
+                return;
+
+        if (!QDesktopServices::openUrl(url_))
+                qWarning() << "Could not open url" << url_.toString();
+}
+
+void
+ImageItem::scaleImage()
+{
+        if (image_.isNull())
+                return;
+
+        auto width_ratio  = (double)max_width_ / (double)image_.width();
+        auto height_ratio = (double)max_height_ / (double)image_.height();
+
+        auto min_aspect_ratio = std::min(width_ratio, height_ratio);
+
+        if (min_aspect_ratio > 1) {
+                width_  = image_.width();
+                height_ = image_.height();
+        } else {
+                width_  = image_.width() * min_aspect_ratio;
+                height_ = image_.height() * min_aspect_ratio;
+        }
+
+        setFixedSize(width_, height_);
+        scaled_image_ =
+          image_.scaled(width_, height_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+}
+
+QSize
+ImageItem::sizeHint() const
+{
+        if (image_.isNull())
+                return QSize(max_width_, bottom_height_);
+
+        return QSize(width_, height_);
+}
+
+void
+ImageItem::setImage(const QPixmap &image)
+{
+        image_ = image;
+        scaleImage();
+        update();
+}
+
+void
+ImageItem::mousePressEvent(QMouseEvent *event)
+{
+        if (event->button() != Qt::LeftButton)
+                return;
+
+        if (image_.isNull()) {
+                openUrl();
+                return;
+        }
+
+        auto point = event->pos();
+
+        // Click on the text box.
+        if (QRect(0, height_ - bottom_height_, width_, bottom_height_).contains(point)) {
+                openUrl();
+        } else {
+                auto image_dialog = new ImageOverlayDialog(image_, this);
+                image_dialog->show();
+        }
+}
+
+void
+ImageItem::resizeEvent(QResizeEvent *event)
+{
+        Q_UNUSED(event);
+
+        scaleImage();
+}
+
+void
+ImageItem::paintEvent(QPaintEvent *event)
+{
+        Q_UNUSED(event);
+
+        QPainter painter(this);
+        painter.setRenderHint(QPainter::Antialiasing);
+
+        QFont font("Open Sans");
+        font.setPixelSize(12);
+
+        QFontMetrics metrics(font);
+        int fontHeight = metrics.height();
+
+        if (image_.isNull()) {
+                int height = fontHeight + 10;
+
+                QString elidedText = metrics.elidedText(text_, Qt::ElideRight, max_width_ - 10);
+
+                setFixedSize(metrics.width(elidedText), fontHeight + 10);
+
+                painter.setFont(font);
+                painter.setPen(QPen(QColor(66, 133, 244)));
+                painter.drawText(QPoint(0, height / 2 + 2), elidedText);
+
+                return;
+        }
+
+        painter.fillRect(QRect(0, 0, width_, height_), scaled_image_);
+
+        if (underMouse()) {
+                // Bottom text section
+                painter.fillRect(QRect(0, height_ - bottom_height_, width_, bottom_height_),
+                                 QBrush(QColor(33, 33, 33, 128)));
+
+                QString elidedText = metrics.elidedText(text_, Qt::ElideRight, width_ - 10);
+
+                font.setWeight(80);
+                painter.setFont(font);
+                painter.setPen(QPen(QColor("white")));
+                painter.drawText(QPoint(5, height_ - fontHeight / 2), elidedText);
+        }
+}