From 0c200d360be6dc1d3a59991fb8aad349ace334d1 Mon Sep 17 00:00:00 2001 From: frostasm Date: Wed, 13 Dec 2017 22:22:31 +0200 Subject: [PATCH] Add attachments tab to details view --- src/core/EntryAttachments.cpp | 5 +++ src/core/EntryAttachments.h | 1 + src/gui/DatabaseWidget.cpp | 3 ++ src/gui/DetailsWidget.cpp | 52 +++++++++++++++++++++++++++++-- src/gui/DetailsWidget.h | 13 ++++++-- src/gui/DetailsWidget.ui | 10 ++++++ src/gui/entry/EditEntryWidget.cpp | 5 ++- src/gui/entry/EditEntryWidget.h | 2 +- 8 files changed, 82 insertions(+), 9 deletions(-) diff --git a/src/core/EntryAttachments.cpp b/src/core/EntryAttachments.cpp index bab11057..95755860 100644 --- a/src/core/EntryAttachments.cpp +++ b/src/core/EntryAttachments.cpp @@ -111,6 +111,11 @@ void EntryAttachments::remove(const QStringList& keys) } } +bool EntryAttachments::isEmpty() const +{ + return m_attachments.isEmpty(); +} + void EntryAttachments::clear() { if (m_attachments.isEmpty()) { diff --git a/src/core/EntryAttachments.h b/src/core/EntryAttachments.h index 8fa7c717..0dba9543 100644 --- a/src/core/EntryAttachments.h +++ b/src/core/EntryAttachments.h @@ -36,6 +36,7 @@ public: void set(const QString& key, const QByteArray& value); void remove(const QString& key); void remove(const QStringList& keys); + bool isEmpty() const; void clear(); void copyDataFrom(const EntryAttachments* other); bool operator==(const EntryAttachments& other) const; diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index b851839a..b6e772f6 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -111,6 +111,9 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) "border-radius: 5px;"); m_detailsView = new DetailsWidget(this); + connect(m_detailsView, &DetailsWidget::errorOccured, this, [this](const QString& error) { + showMessage(error, MessageWidget::MessageType::Error, false); + }); QVBoxLayout* vLayout = new QVBoxLayout(rightHandSideWidget); vLayout->setMargin(0); diff --git a/src/gui/DetailsWidget.cpp b/src/gui/DetailsWidget.cpp index 23c3485a..eadc5d47 100644 --- a/src/gui/DetailsWidget.cpp +++ b/src/gui/DetailsWidget.cpp @@ -21,12 +21,16 @@ #include #include +#include +#include +#include #include "core/Config.h" #include "core/FilePath.h" #include "core/TimeInfo.h" #include "gui/Clipboard.h" #include "gui/DatabaseWidget.h" +#include "entry/EntryAttachmentsModel.h" DetailsWidget::DetailsWidget(QWidget* parent) : QWidget(parent) @@ -36,9 +40,11 @@ DetailsWidget::DetailsWidget(QWidget* parent) , m_currentGroup(nullptr) , m_timer(nullptr) , m_attributesWidget(nullptr) + , m_attachmentsWidget(nullptr) , m_autotypeWidget(nullptr) , m_selectedTabEntry(0) , m_selectedTabGroup(0) + , m_attachmentsModel(new EntryAttachmentsModel(this)) { m_ui->setupUi(this); @@ -53,6 +59,17 @@ DetailsWidget::DetailsWidget(QWidget* parent) connect(m_ui->closeButton, SIGNAL(toggled(bool)), SLOT(hideDetails())); connect(m_ui->tabWidget, SIGNAL(tabBarClicked(int)), SLOT(updateTabIndex(int))); + m_ui->attachmentsTableView->setModel(m_attachmentsModel); + m_ui->attachmentsTableView->horizontalHeader()->setStretchLastSection(true); + m_ui->attachmentsTableView->horizontalHeader()->resizeSection(0, 600); + m_ui->attachmentsTableView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_ui->attachmentsTableView->setSelectionMode(QAbstractItemView::SingleSelection); + connect(m_ui->attachmentsTableView, SIGNAL(activated(QModelIndex)), SLOT(openAttachment(QModelIndex))); + + m_attributesWidget = m_ui->tabWidget->widget(AttributesTab); + m_attachmentsWidget = m_ui->tabWidget->widget(AttachmentsTab); + m_autotypeWidget = m_ui->tabWidget->widget(AutotypeTab); + this->hide(); } @@ -75,8 +92,9 @@ void DetailsWidget::getSelectedEntry(Entry* selectedEntry) m_ui->stackedWidget->setCurrentIndex(EntryPreview); - if (m_ui->tabWidget->count() < 4) { + if (m_ui->tabWidget->count() < 5) { m_ui->tabWidget->insertTab(static_cast(AttributesTab), m_attributesWidget, "Attributes"); + m_ui->tabWidget->insertTab(static_cast(AttachmentsTab), m_attachmentsWidget, "Attachments"); m_ui->tabWidget->insertTab(static_cast(AutotypeTab), m_autotypeWidget, "Autotype"); } @@ -173,6 +191,10 @@ void DetailsWidget::getSelectedEntry(Entry* selectedEntry) m_ui->attributesEdit->setText(attributesText); } + const bool hasAttachments = !m_currentEntry->attachments()->isEmpty(); + m_ui->tabWidget->setTabEnabled(AttachmentsTab, hasAttachments); + m_attachmentsModel->setEntryAttachments(hasAttachments ? m_currentEntry->attachments() : nullptr); + m_ui->autotypeTree->clear(); AutoTypeAssociations* autotypeAssociations = m_currentEntry->autoTypeAssociations(); QList items; @@ -209,9 +231,8 @@ void DetailsWidget::getSelectedGroup(Group* selectedGroup) m_ui->stackedWidget->setCurrentIndex(GroupPreview); if (m_ui->tabWidget->count() > 2) { - m_autotypeWidget = m_ui->tabWidget->widget(AutotypeTab); - m_attributesWidget = m_ui->tabWidget->widget(AttributesTab); m_ui->tabWidget->removeTab(AutotypeTab); + m_ui->tabWidget->removeTab(AttachmentsTab); m_ui->tabWidget->removeTab(AttributesTab); } @@ -338,3 +359,28 @@ void DetailsWidget::updateTabIndex(int index) m_selectedTabEntry = index; } } + +void DetailsWidget::openAttachment(const QModelIndex& index) +{ + Q_ASSERT(m_currentEntry != nullptr); + const QString filename = m_attachmentsModel->keyByIndex(index); + const QByteArray attachmentData = m_currentEntry->attachments()->value(filename); + + // tmp file will be removed once the database (or the application) has been closed + const QString tmpFileTemplate = QDir::temp().absoluteFilePath(QString("XXXXXX.").append(filename)); + QTemporaryFile* tmpFile = new QTemporaryFile(tmpFileTemplate, this); + + const bool saveOk = tmpFile->open() + && tmpFile->write(attachmentData) == attachmentData.size() + && tmpFile->flush(); + + if (!saveOk) { + delete tmpFile; + emit errorOccured(tr("Unable to open the attachment:\n").append(tmpFile->errorString())); + return; + } + + tmpFile->close(); + QDesktopServices::openUrl(QUrl::fromLocalFile(tmpFile->fileName())); +} + diff --git a/src/gui/DetailsWidget.h b/src/gui/DetailsWidget.h index 780fe558..c50e2d7e 100644 --- a/src/gui/DetailsWidget.h +++ b/src/gui/DetailsWidget.h @@ -25,6 +25,8 @@ namespace Ui { class DetailsWidget; } +class EntryAttachmentsModel; + class DetailsWidget : public QWidget { Q_OBJECT @@ -44,10 +46,14 @@ public: GeneralTab = 0, AttributesTab = 1, GroupNotesTab = 1, - NotesTab = 2, - AutotypeTab = 3, + AttachmentsTab = 2, + NotesTab = 3, + AutotypeTab = 4, }; +signals: + void errorOccured(const QString& error); + private slots: void getSelectedEntry(Entry* selectedEntry); void getSelectedGroup(Group* selectedGroup); @@ -56,6 +62,7 @@ private slots: void hideDetails(); void setDatabaseMode(DatabaseWidget::Mode mode); void updateTabIndex(int index); + void openAttachment(const QModelIndex& index); private: const QScopedPointer m_ui; @@ -65,9 +72,11 @@ private: quint8 m_step; QTimer* m_timer; QWidget* m_attributesWidget; + QWidget* m_attachmentsWidget; QWidget* m_autotypeWidget; quint8 m_selectedTabEntry; quint8 m_selectedTabGroup; + EntryAttachmentsModel* const m_attachmentsModel; QString shortUrl(QString url); QString shortPassword(QString password); }; diff --git a/src/gui/DetailsWidget.ui b/src/gui/DetailsWidget.ui index 3a0b2f2c..d7cb29cd 100644 --- a/src/gui/DetailsWidget.ui +++ b/src/gui/DetailsWidget.ui @@ -454,6 +454,16 @@ + + + Attachments + + + + + + + Notes diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 2ba395c9..c6d49c82 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -32,7 +32,6 @@ #include #include - #include "core/Config.h" #include "core/Database.h" #include "core/Entry.h" @@ -150,7 +149,7 @@ void EditEntryWidget::setupAdvanced() m_advancedUi->attachmentsView->horizontalHeader()->setStretchLastSection(true); m_advancedUi->attachmentsView->horizontalHeader()->resizeSection(0, 600); m_advancedUi->attachmentsView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_advancedUi->attachmentsView->setSelectionMode(QAbstractItemView::MultiSelection); + m_advancedUi->attachmentsView->setSelectionMode(QAbstractItemView::ExtendedSelection); connect(m_advancedUi->attachmentsView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(updateAttachmentButtonsEnabled())); @@ -1044,7 +1043,7 @@ void EditEntryWidget::revealCurrentAttribute() } } -void EditEntryWidget::insertAttachments(const QStringList &filenames, QString *errorMessage) +void EditEntryWidget::insertAttachments(const QStringList& filenames, QString* errorMessage) { QStringList errors; for (const QString &filename: filenames) { diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index 01c17351..d40b5c14 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -86,7 +86,7 @@ private slots: void updateCurrentAttribute(); void protectCurrentAttribute(bool state); void revealCurrentAttribute(); - void insertAttachments(const QStringList &fileNames, QString *errorMessage = nullptr); + void insertAttachments(const QStringList& fileNames, QString* errorMessage = nullptr); void insertAttachments(); void saveSelectedAttachment(); void saveSelectedAttachments();