2025-06-19 21:46:42 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2025 KeePassXC Team <team@keepassxc.org>
|
|
|
|
|
*
|
|
|
|
|
* 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 "TextAttachmentsPreviewWidget.h"
|
|
|
|
|
#include "ui_TextAttachmentsPreviewWidget.h"
|
|
|
|
|
|
|
|
|
|
#include <core/Tools.h>
|
|
|
|
|
|
|
|
|
|
#include <QComboBox>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QMetaEnum>
|
2025-09-08 10:22:20 +00:00
|
|
|
#include <QScrollBar>
|
2025-06-19 21:46:42 +00:00
|
|
|
#include <QSortFilterProxyModel>
|
|
|
|
|
#include <QStandardItemModel>
|
2025-09-08 10:22:20 +00:00
|
|
|
#include <QTimer>
|
2025-06-19 21:46:42 +00:00
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
constexpr TextAttachmentsPreviewWidget::PreviewTextType ConvertToPreviewTextType(Tools::MimeType mimeType) noexcept
|
|
|
|
|
{
|
|
|
|
|
if (mimeType == Tools::MimeType::Html) {
|
|
|
|
|
return TextAttachmentsPreviewWidget::Html;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
|
|
|
if (mimeType == Tools::MimeType::Markdown) {
|
|
|
|
|
return TextAttachmentsPreviewWidget::Markdown;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return TextAttachmentsPreviewWidget::PlainText;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
TextAttachmentsPreviewWidget::TextAttachmentsPreviewWidget(QWidget* parent)
|
|
|
|
|
: QWidget(parent)
|
|
|
|
|
, m_ui(new Ui::TextAttachmentsPreviewWidget())
|
2025-09-08 10:22:20 +00:00
|
|
|
, m_userManuallySelectedType(false)
|
2025-06-19 21:46:42 +00:00
|
|
|
{
|
|
|
|
|
m_ui->setupUi(this);
|
|
|
|
|
|
|
|
|
|
initTypeCombobox();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TextAttachmentsPreviewWidget::~TextAttachmentsPreviewWidget() = default;
|
|
|
|
|
|
|
|
|
|
void TextAttachmentsPreviewWidget::openAttachment(attachments::Attachment attachments, attachments::OpenMode mode)
|
|
|
|
|
{
|
|
|
|
|
if (mode == attachments::OpenMode::ReadWrite) {
|
|
|
|
|
qWarning() << "Read-write mode is not supported for text preview attachments";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_attachment = std::move(attachments);
|
|
|
|
|
|
|
|
|
|
updateUi();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attachments::Attachment TextAttachmentsPreviewWidget::getAttachment() const
|
|
|
|
|
{
|
|
|
|
|
return m_attachment;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextAttachmentsPreviewWidget::initTypeCombobox()
|
|
|
|
|
{
|
|
|
|
|
QStandardItemModel* model = new QStandardItemModel(this);
|
|
|
|
|
|
|
|
|
|
const auto metaEnum = QMetaEnum::fromType<TextAttachmentsPreviewWidget::PreviewTextType>();
|
|
|
|
|
for (int i = 0; i < metaEnum.keyCount(); ++i) {
|
|
|
|
|
QStandardItem* item = new QStandardItem(metaEnum.key(i));
|
|
|
|
|
item->setData(metaEnum.value(i), Qt::UserRole);
|
|
|
|
|
model->appendRow(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QSortFilterProxyModel* filterProxyMode = new QSortFilterProxyModel(this);
|
|
|
|
|
filterProxyMode->setSourceModel(model);
|
|
|
|
|
filterProxyMode->sort(0, Qt::SortOrder::DescendingOrder);
|
|
|
|
|
m_ui->typeComboBox->setModel(filterProxyMode);
|
|
|
|
|
|
2025-09-08 10:22:20 +00:00
|
|
|
connect(m_ui->typeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
|
|
|
|
m_userManuallySelectedType = true;
|
|
|
|
|
onTypeChanged(index);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Configure text browser to open external links
|
|
|
|
|
m_ui->previewTextBrowser->setOpenExternalLinks(true);
|
2025-06-19 21:46:42 +00:00
|
|
|
|
2026-01-17 16:39:02 +00:00
|
|
|
m_ui->previewTextBrowser->setTabStopDistance(
|
|
|
|
|
QFontMetrics(m_ui->previewTextBrowser->font()).horizontalAdvance(QString(4, ' ')));
|
|
|
|
|
|
2025-06-19 21:46:42 +00:00
|
|
|
m_ui->typeComboBox->setCurrentIndex(m_ui->typeComboBox->findData(PlainText));
|
|
|
|
|
|
|
|
|
|
onTypeChanged(m_ui->typeComboBox->currentIndex());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextAttachmentsPreviewWidget::updateUi()
|
|
|
|
|
{
|
2025-09-08 10:22:20 +00:00
|
|
|
// Only auto-select format based on file extension if user hasn't manually chosen one
|
|
|
|
|
if (!m_userManuallySelectedType && !m_attachment.name.isEmpty()) {
|
2025-06-19 21:46:42 +00:00
|
|
|
const auto mimeType = Tools::getMimeType(QFileInfo(m_attachment.name));
|
|
|
|
|
|
|
|
|
|
auto index = m_ui->typeComboBox->findData(ConvertToPreviewTextType(mimeType));
|
2025-09-08 10:22:20 +00:00
|
|
|
if (index >= 0) {
|
|
|
|
|
// Temporarily block signals to avoid triggering manual selection flag
|
|
|
|
|
m_ui->typeComboBox->blockSignals(true);
|
|
|
|
|
m_ui->typeComboBox->setCurrentIndex(index);
|
|
|
|
|
m_ui->typeComboBox->blockSignals(false);
|
|
|
|
|
}
|
2025-06-19 21:46:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onTypeChanged(m_ui->typeComboBox->currentIndex());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextAttachmentsPreviewWidget::onTypeChanged(int index)
|
|
|
|
|
{
|
|
|
|
|
if (index < 0) {
|
|
|
|
|
qWarning() << "TextAttachmentsPreviewWidget: Unknown text format";
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 10:22:20 +00:00
|
|
|
const auto scrollPos = m_ui->previewTextBrowser->verticalScrollBar()->value();
|
2025-06-19 21:46:42 +00:00
|
|
|
const auto fileType = m_ui->typeComboBox->itemData(index).toInt();
|
|
|
|
|
if (fileType == TextAttachmentsPreviewWidget::PreviewTextType::PlainText) {
|
|
|
|
|
m_ui->previewTextBrowser->setPlainText(m_attachment.data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fileType == TextAttachmentsPreviewWidget::PreviewTextType::Html) {
|
|
|
|
|
m_ui->previewTextBrowser->setHtml(m_attachment.data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
|
|
|
if (fileType == TextAttachmentsPreviewWidget::PreviewTextType::Markdown) {
|
|
|
|
|
m_ui->previewTextBrowser->setMarkdown(m_attachment.data);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2025-09-08 10:22:20 +00:00
|
|
|
|
|
|
|
|
// Delay setting the scrollbar position to ensure the text is rendered first
|
|
|
|
|
QTimer::singleShot(
|
|
|
|
|
100, this, [this, scrollPos] { m_ui->previewTextBrowser->verticalScrollBar()->setValue(scrollPos); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextAttachmentsPreviewWidget::matchScroll(double percent)
|
|
|
|
|
{
|
|
|
|
|
// Match the scroll position of the text browser to the given percentage
|
|
|
|
|
int maxScroll = m_ui->previewTextBrowser->verticalScrollBar()->maximum();
|
|
|
|
|
int newScrollPos = static_cast<int>(maxScroll * percent);
|
|
|
|
|
m_ui->previewTextBrowser->verticalScrollBar()->setValue(newScrollPos);
|
2025-06-19 21:46:42 +00:00
|
|
|
}
|