From f5a49e6b0be2fa5d4ae8570a52c42bc59acd4509 Mon Sep 17 00:00:00 2001 From: Lukasz Ornatek Date: Wed, 16 Dec 2020 14:59:17 +0100 Subject: [PATCH] Implement adding images in the rich text format to the annotations Task-number: QDS-3306 Change-Id: I8372c3d10ad5beb1ec52d8d3d45a3f963711a63c Reviewed-by: Leena Miettinen Reviewed-by: Michael Winkelmann Reviewed-by: Thomas Hartmann --- .../annotationeditor/annotationcommenttab.cpp | 78 ++++++++++++++++++- .../annotationeditor/annotationcommenttab.h | 6 ++ .../richtexteditor/richtexteditor.cpp | 36 +++++++++ .../richtexteditor/richtexteditor.h | 9 +++ 4 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp index 29e38362418..e1afef38be1 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp @@ -28,8 +28,14 @@ #include "richtexteditor/richtexteditor.h" +#include #include "QStringListModel" +#include "projectexplorer/session.h" +#include "projectexplorer/target.h" +#include "qmldesignerplugin.h" +#include "qmlprojectmanager/qmlproject.h" + namespace QmlDesigner { AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) @@ -38,7 +44,17 @@ AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) { ui->setupUi(this); - m_editor = new RichTextEditor; + m_editor = new RichTextEditor{this}; + + connect(m_editor, &RichTextEditor::insertingImage, this, [this](QString &filePath) { + filePath = backupFile(filePath); + }); + + Utils::FilePath projPath = ProjectExplorer::SessionManager::startupProject()->projectFilePath(); + + m_editor->setDocumentBaseUrl(QUrl::fromLocalFile(projPath.toString())); + m_editor->setImageActionVisible(true); + ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor); ui->titleEdit->setModel(new QStringListModel{QStringList{"Description", @@ -113,4 +129,64 @@ void AnnotationCommentTab::commentTitleChanged(const QString &text) emit titleChanged(text, this); } +QString AnnotationCommentTab::backupFile(const QString &filePath) +{ + const QDir projDir( + ProjectExplorer::SessionManager::startupProject()->projectDirectory().toString()); + + const QString imageSubDir(".AnnotationImages"); + const QDir imgDir(projDir.absolutePath() + QDir::separator() + imageSubDir); + + ensureDir(imgDir); + + const QFileInfo oldFile(filePath); + QFileInfo newFile(imgDir, oldFile.fileName()); + + QString newName = newFile.baseName() + "_%1." + newFile.completeSuffix(); + + for (size_t i = 1; true; ++i) { + if (!newFile.exists()) { + QFile(oldFile.absoluteFilePath()).copy(newFile.absoluteFilePath()); + break; + } else if (compareFileChecksum(oldFile.absoluteFilePath(), + newFile.absoluteFilePath()) == 0) { + break; + } + + newFile.setFile(imgDir, newName.arg(i)); + } + + return projDir.relativeFilePath(newFile.absoluteFilePath()); +} + +void AnnotationCommentTab::ensureDir(const QDir &dir) +{ + if (!dir.exists()) { + dir.mkdir("."); + } +} + +int AnnotationCommentTab::compareFileChecksum(const QString &firstFile, const QString &secondFile) +{ + QCryptographicHash sum1(QCryptographicHash::Md5); + + { + QFile f1(firstFile); + if (f1.open(QFile::ReadOnly)) { + sum1.addData(&f1); + } + } + + QCryptographicHash sum2(QCryptographicHash::Md5); + + { + QFile f2(secondFile); + if (f2.open(QFile::ReadOnly)) { + sum2.addData(&f2); + } + } + + return sum1.result().compare(sum2.result()); +} + } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h index 55fcf6ff1ed..5f9605f39f7 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h @@ -29,6 +29,8 @@ #include "annotation.h" +class QDir; + namespace QmlDesigner { namespace Ui { @@ -64,6 +66,10 @@ private: RichTextEditor *m_editor; Comment m_comment; + + QString backupFile(const QString &filePath); + void ensureDir(const QDir &dir); + int compareFileChecksum(const QString &firstFile, const QString &secondFile); }; } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp index a8e693876e0..d576cf19d1d 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,7 @@ RichTextEditor::RichTextEditor(QWidget *parent) setupEditActions(); setupTextActions(); + setupImageActions(); setupHyperlinkActions(); setupAlignActions(); setupListActions(); @@ -184,6 +186,16 @@ void RichTextEditor::setTabChangesFocus(bool change) ui->textEdit->setTabChangesFocus(change); } +void RichTextEditor::setImageActionVisible(bool change) +{ + m_actionImage->setVisible(change); +} + +void RichTextEditor::setDocumentBaseUrl(const QUrl& url) +{ + ui->textEdit->document()->setBaseUrl(url); +} + QIcon RichTextEditor::getIcon(Theme::Icon icon) { const QString fontName = "qtds_propertyIconFont.ttf"; @@ -361,6 +373,30 @@ void RichTextEditor::setupTextActions() ui->toolBar->addSeparator(); } +void RichTextEditor::setupImageActions() +{ + auto insertImage = [this]() { + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setWindowTitle(tr("Select Image")); + dialog.setNameFilters({tr("Image files (*.png *.jpg)")}); + + if (dialog.exec()) { + QStringList files = dialog.selectedFiles(); + for (QString& filePath : files) { + emit insertingImage(filePath); + + ui->textEdit->insertHtml(""); + } + } + }; + + m_actionImage = ui->toolBar + ->addAction(getIcon(Theme::Icon::addFile), tr("Insert &Image"), insertImage); + + setImageActionVisible(false); +} + void RichTextEditor::setupHyperlinkActions() { const QIcon bulletIcon(getIcon(Theme::Icon::actionIconBinding)); diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h index 50053c1ab3c..a2f44dd0443 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h @@ -63,6 +63,13 @@ public: void setTabChangesFocus(bool change); + void setImageActionVisible(bool change); + + void setDocumentBaseUrl(const QUrl &url); + +signals: + void insertingImage(QString &filePath); + private slots: void currentCharFormatChanged(const QTextCharFormat &format); void cursorPositionChanged(); @@ -79,6 +86,7 @@ private: void setupEditActions(); void setupTextActions(); + void setupImageActions(); void setupHyperlinkActions(); void setupAlignActions(); void setupListActions(); @@ -97,6 +105,7 @@ private: QAction *m_actionTextItalic; QAction *m_actionTextUnderline; + QAction *m_actionImage; QAction *m_actionHyperlink; QAction *m_actionAlignLeft;