Skip to content

Commit

Permalink
Add preview functionality for entry attachments
Browse files Browse the repository at this point in the history
Supported types:
- text
- image

Fixes #11506
  • Loading branch information
w15dev committed Jan 8, 2025
1 parent df95ad6 commit 47d1bb0
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ set(gui_SOURCES
gui/entry/EntryAttachmentsWidget.cpp
gui/entry/EntryAttributesModel.cpp
gui/entry/NewEntryAttachmentsDialog.cpp
gui/entry/PreviewEntryAttachmentsDialog.cpp
gui/entry/EntryHistoryModel.cpp
gui/entry/EntryModel.cpp
gui/entry/EntryView.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewEntryAttachmentsDialog</class>
<widget class="QDialog" name="NewEntryAttachmentsDialog">
<class>EntryAttachmentsDialog</class>
<widget class="QDialog" name="EntryAttachmentsDialog">
<property name="geometry">
<rect>
<x>0</x>
Expand All @@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>New entry attachments</string>
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
Expand Down
25 changes: 22 additions & 3 deletions src/gui/entry/EntryAttachmentsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "EntryAttachmentsWidget.h"
#include "NewEntryAttachmentsDialog.h"
#include "PreviewEntryAttachmentsDialog.h"
#include "ui_EntryAttachmentsWidget.h"

#include <QDir>
Expand All @@ -26,11 +27,11 @@
#include <QTemporaryFile>

#include "EntryAttachmentsModel.h"
#include "core/Config.h"
#include "core/EntryAttachments.h"
#include "core/Tools.h"
#include "gui/FileDialog.h"
#include "gui/MessageBox.h"
#include <QDebug>

EntryAttachmentsWidget::EntryAttachmentsWidget(QWidget* parent)
: QWidget(parent)
Expand Down Expand Up @@ -70,6 +71,7 @@ EntryAttachmentsWidget::EntryAttachmentsWidget(QWidget* parent)
connect(m_ui->openAttachmentButton, SIGNAL(clicked()), SLOT(openSelectedAttachments()));
connect(m_ui->addAttachmentButton, SIGNAL(clicked()), SLOT(insertAttachments()));
connect(m_ui->newAttachmentButton, SIGNAL(clicked()), SLOT(newAttachments()));
connect(m_ui->previewButton, SIGNAL(clicked()), SLOT(previewAttachments()));
connect(m_ui->removeAttachmentButton, SIGNAL(clicked()), SLOT(removeSelectedAttachments()));
connect(m_ui->renameAttachmentButton, SIGNAL(clicked()), SLOT(renameSelectedAttachments()));

Expand Down Expand Up @@ -173,12 +175,28 @@ void EntryAttachmentsWidget::newAttachments()
return;
}

auto newWidnow = new NewEntryAttachmentsDialog(m_entryAttachments, this);
if (newWidnow->exec() == QDialog::Accepted) {
NewEntryAttachmentsDialog newEntryDialog{m_entryAttachments, this};
if (newEntryDialog.exec() == QDialog::Accepted) {
emit widgetUpdated();
}
}

void EntryAttachmentsWidget::previewAttachments()
{
Q_ASSERT(m_entryAttachments);

const auto index = m_ui->attachmentsView->selectionModel()->selectedIndexes().first();
if (!index.isValid()) {
qWarning() << tr("Failed to preview an attachment: Attachment not found");
return;
}

PreviewEntryAttachmentsDialog previewDialog{m_entryAttachments, this};
previewDialog.setAttachment(m_attachmentsModel->keyByIndex(index));

previewDialog.exec();
}

void EntryAttachmentsWidget::removeSelectedAttachments()
{
Q_ASSERT(m_entryAttachments);
Expand Down Expand Up @@ -318,6 +336,7 @@ void EntryAttachmentsWidget::updateButtonsEnabled()
m_ui->addAttachmentButton->setEnabled(!m_readOnly);
m_ui->newAttachmentButton->setEnabled(!m_readOnly);
m_ui->removeAttachmentButton->setEnabled(hasSelection && !m_readOnly);
m_ui->previewButton->setEnabled(hasSelection && !m_readOnly);
m_ui->renameAttachmentButton->setEnabled(hasSelection && !m_readOnly);

m_ui->saveAttachmentButton->setEnabled(hasSelection);
Expand Down
1 change: 1 addition & 0 deletions src/gui/entry/EntryAttachmentsWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public slots:
private slots:
void insertAttachments();
void newAttachments();
void previewAttachments();
void removeSelectedAttachments();
void renameSelectedAttachments();
void saveSelectedAttachments();
Expand Down
10 changes: 10 additions & 0 deletions src/gui/entry/EntryAttachmentsWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="previewButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Preview</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="openAttachmentButton">
<property name="enabled">
Expand Down
12 changes: 10 additions & 2 deletions src/gui/entry/NewEntryAttachmentsDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,26 @@

#include "NewEntryAttachmentsDialog.h"
#include "core/EntryAttachments.h"
#include "ui_NewEntryAttachmentsDialog.h"
#include "ui_EntryAttachmentsDialog.h"

#include <QMessageBox>
#include <QPushButton>

NewEntryAttachmentsDialog::NewEntryAttachmentsDialog(QPointer<EntryAttachments> attachments, QWidget* parent)
: QDialog(parent)
, m_attachments(std::move(attachments))
, m_ui(new Ui::NewEntryAttachmentsDialog)
, m_ui(new Ui::EntryAttachmentsDialog)
{
Q_ASSERT(m_attachments);

m_ui->setupUi(this);

setWindowTitle(tr("New entry attachment"));

m_ui->dialogButtons->clear();
m_ui->dialogButtons->addButton(QDialogButtonBox::Ok);
m_ui->dialogButtons->addButton(QDialogButtonBox::Cancel);

connect(m_ui->dialogButtons, SIGNAL(accepted()), this, SLOT(saveAttachment()));
connect(m_ui->dialogButtons, SIGNAL(rejected()), this, SLOT(reject()));
connect(m_ui->titleEdit, SIGNAL(textChanged(const QString&)), this, SLOT(fileNameTextChanged(const QString&)));
Expand Down
4 changes: 2 additions & 2 deletions src/gui/entry/NewEntryAttachmentsDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

namespace Ui
{
class NewEntryAttachmentsDialog;
class EntryAttachmentsDialog;
}

class QByteArray;
Expand All @@ -48,7 +48,7 @@ private slots:
private:
QPointer<EntryAttachments> m_attachments;

QScopedPointer<Ui::NewEntryAttachmentsDialog> m_ui;
QScopedPointer<Ui::EntryAttachmentsDialog> m_ui;
};

#endif // NEWENTRYATTACHMENTSWIDGET_H
109 changes: 109 additions & 0 deletions src/gui/entry/PreviewEntryAttachmentsDialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2021 KeePassXC Team <[email protected]>
*
* 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 2 or (at your option)
* version 3 of the License.
*
* 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 "PreviewEntryAttachmentsDialog.h"
#include "core/EntryAttachments.h"
#include "ui_EntryAttachmentsDialog.h"

#include <QDialogButtonBox>
#include <QMimeDatabase>
#include <QTextCursor>
#include <QtGlobal>

PreviewEntryAttachmentsDialog::PreviewEntryAttachmentsDialog(QPointer<EntryAttachments> attachments, QWidget* parent)
: QDialog(parent)
, m_attachments(std::move(attachments))
, m_ui(new Ui::EntryAttachmentsDialog)
{
Q_ASSERT(m_attachments);

m_ui->setupUi(this);

setWindowTitle(tr("Preview entry attachment"));

m_ui->titleEdit->setReadOnly(true);
m_ui->attachmentTextEdit->setReadOnly(true);

m_ui->dialogButtons->clear();
m_ui->dialogButtons->addButton(QDialogButtonBox::Close);

connect(m_ui->dialogButtons, SIGNAL(rejected()), this, SLOT(reject()));
}

PreviewEntryAttachmentsDialog::~PreviewEntryAttachmentsDialog() = default;

void PreviewEntryAttachmentsDialog::setAttachment(const QString& name)
{
m_name = name;
m_type = attachmentType(m_name);

m_ui->titleEdit->setText(m_name);

update();
}

void PreviewEntryAttachmentsDialog::update()
{
if (m_type == AttachmentType::Unknown) {
updateTextAttachment(tr("No preview available").toUtf8());
} else if (const auto data = m_attachments->value(m_name); m_type == AttachmentType::Image) {
updateImageAttachment(data);
} else if (m_type == AttachmentType::PlantText) {
updateTextAttachment(data);
}
}

void PreviewEntryAttachmentsDialog::updateTextAttachment(const QByteArray& data)
{
m_ui->attachmentTextEdit->setPlainText(QString::fromUtf8(data));
}

void PreviewEntryAttachmentsDialog::updateImageAttachment(const QByteArray& data)
{
QImage image{};
image.loadFromData(data);

m_ui->attachmentTextEdit->clear();
auto cursor = m_ui->attachmentTextEdit->textCursor();

cursor.insertImage(image.scaled(m_ui->attachmentTextEdit->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
}

PreviewEntryAttachmentsDialog::AttachmentType PreviewEntryAttachmentsDialog::attachmentType(const QString& name) const
{
const auto data = m_attachments->value(name);

QMimeDatabase mimeDb{};
const auto mime = mimeDb.mimeTypeForData(data);

if (auto mimeName = mime.name(); mimeName.startsWith("image/")) {
return AttachmentType::Image;
} else if (mimeName.startsWith("text/")) {
return AttachmentType::PlantText;
}

return AttachmentType::Unknown;
}

void PreviewEntryAttachmentsDialog::resizeEvent(QResizeEvent* event)
{
QDialog::resizeEvent(event);

if (m_type == AttachmentType::Image) {
update();
}
}
65 changes: 65 additions & 0 deletions src/gui/entry/PreviewEntryAttachmentsDialog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2021 KeePassXC Team <[email protected]>
*
* 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 2 or (at your option)
* version 3 of the License.
*
* 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/>.
*/

#ifndef PREVIEWENTRYATTACHMENTSWIDGET_H
#define PREVIEWENTRYATTACHMENTSWIDGET_H

#include <QDialog>
#include <QPointer>

namespace Ui
{
class EntryAttachmentsDialog;
}

class QByteArray;
class EntryAttachments;

class PreviewEntryAttachmentsDialog : public QDialog
{
Q_OBJECT
public:
explicit PreviewEntryAttachmentsDialog(QPointer<EntryAttachments> attachments, QWidget* parent = nullptr);
~PreviewEntryAttachmentsDialog() override;

void setAttachment(const QString& name);

private:
enum class AttachmentType
{
Image,
PlantText,
Unknown
};

void resizeEvent(QResizeEvent* event) override;

AttachmentType attachmentType(const QString& name) const;

void update();
void updateTextAttachment(const QByteArray& data);
void updateImageAttachment(const QByteArray& data);
private:
QPointer<EntryAttachments> m_attachments;

QScopedPointer<Ui::EntryAttachmentsDialog> m_ui;

QString m_name;
AttachmentType m_type{AttachmentType::Unknown};
};

#endif // PREVIEWENTRYATTACHMENTSWIDGET_H

0 comments on commit 47d1bb0

Please sign in to comment.