diff options
author | Michael Winkelmann <michael.winkelmann@qt.io> | 2021-03-09 12:07:05 +0100 |
---|---|---|
committer | Michael Winkelmann <michael.winkelmann@qt.io> | 2021-03-25 13:48:31 +0000 |
commit | bd9a61fa27bad34144a654b8363ae0667ddd98e1 (patch) | |
tree | 18d33e4a0f33fb50ab0af88024d26a3f6da02696 | |
parent | 3f265c37c619ed0d3a984289b243ad1d99117eba (diff) |
Refactor AnnotationEditors to support different views
Change-Id: I67797e911c320d77b8d6a2eba75de69546b30546
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
22 files changed, 1395 insertions, 399 deletions
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 34ab71154f..63d24df6a1 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -637,6 +637,10 @@ extend_qtc_plugin(QmlDesigner globalannotationeditordialog.cpp globalannotationeditordialog.h globalannotationeditordialog.ui annotationeditor.cpp annotationeditor.h globalannotationeditor.cpp globalannotationeditor.h + defaultannotations.cpp defaultannotations.h + annotationtableview.cpp annotationtableview.h + annotationtabwidget.cpp annotationtabwidget.h + annotationeditor.qrc ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp index b8323bb80d..9a93074721 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp @@ -24,12 +24,12 @@ ****************************************************************************/ #include "annotationcommenttab.h" +#include "defaultannotations.h" #include "ui_annotationcommenttab.h" #include "richtexteditor/richtexteditor.h" #include <QCryptographicHash> -#include "QStringListModel" #include "projectexplorer/session.h" #include "projectexplorer/target.h" @@ -40,7 +40,7 @@ namespace QmlDesigner { AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) : QWidget(parent) - , ui(new Ui::AnnotationCommentTab) + , ui(std::make_unique<Ui::AnnotationCommentTab>()) { ui->setupUi(this); @@ -57,33 +57,12 @@ AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor); - ui->titleEdit->setModel(new QStringListModel{QStringList{"Description", - "Display Condition", - "helper lines", - "position marker", - "highlight", - "project author", - "project confirmed", - "project developer", - "project distributor", - "project modified", - "project type", - "project version", - "Screen Description", - "Section", - "normalcolor", - "focuscolor", - "selectedcolor", - "pressedcolor"}}); - - connect(ui->titleEdit, &QComboBox::currentTextChanged, - this, &AnnotationCommentTab::commentTitleChanged); + connect(ui->titleEdit, &QComboBox::currentTextChanged, this, [this](QString const &text) { + emit titleChanged(text, this); + }); } -AnnotationCommentTab::~AnnotationCommentTab() -{ - delete ui; -} +AnnotationCommentTab::~AnnotationCommentTab() {} Comment AnnotationCommentTab::currentComment() const { @@ -91,7 +70,10 @@ Comment AnnotationCommentTab::currentComment() const result.setTitle(ui->titleEdit->currentText().trimmed()); result.setAuthor(ui->authorEdit->text().trimmed()); - result.setText(m_editor->richText().trimmed()); + if (defaultAnnotations() && !defaultAnnotations()->isRichText(result)) { + result.setText(m_editor->plainText().trimmed()); + } else + result.setText(m_editor->richText().trimmed()); if (m_comment.sameContent(result)) result.setTimestamp(m_comment.timestamp()); @@ -129,9 +111,15 @@ void AnnotationCommentTab::resetComment() m_comment = currentComment(); } -void AnnotationCommentTab::commentTitleChanged(const QString &text) +DefaultAnnotationsModel *AnnotationCommentTab::defaultAnnotations() const +{ + return m_defaults; +} + +void AnnotationCommentTab::setDefaultAnnotations(DefaultAnnotationsModel *defaults) { - emit titleChanged(text, this); + m_defaults = defaults; + ui->titleEdit->setModel(m_defaults); } QString AnnotationCommentTab::backupFile(const QString &filePath) @@ -153,10 +141,8 @@ QString AnnotationCommentTab::backupFile(const QString &filePath) if (!newFile.exists()) { QFile(oldFile.absoluteFilePath()).copy(newFile.absoluteFilePath()); break; - } else if (compareFileChecksum(oldFile.absoluteFilePath(), - newFile.absoluteFilePath()) == 0) { + } else if (compareFileChecksum(oldFile.absoluteFilePath(), newFile.absoluteFilePath()) == 0) break; - } newFile.setFile(imgDir, newName.arg(i)); } @@ -166,9 +152,8 @@ QString AnnotationCommentTab::backupFile(const QString &filePath) void AnnotationCommentTab::ensureDir(const QDir &dir) { - if (!dir.exists()) { + if (!dir.exists()) dir.mkdir("."); - } } int AnnotationCommentTab::compareFileChecksum(const QString &firstFile, const QString &secondFile) diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h index 6fc647669d..beb2e4c377 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h @@ -25,9 +25,12 @@ #pragma once +#include "annotation.h" + #include <QWidget> +#include <QPointer> -#include "annotation.h" +#include <memory> QT_BEGIN_NAMESPACE class QDir; @@ -40,6 +43,7 @@ class AnnotationCommentTab; } class RichTextEditor; +class DefaultAnnotationsModel; class AnnotationCommentTab : public QWidget { @@ -57,17 +61,18 @@ public: void resetUI(); void resetComment(); + DefaultAnnotationsModel *defaultAnnotations() const; + void setDefaultAnnotations(DefaultAnnotationsModel *); + signals: void titleChanged(const QString &text, QWidget *widget); -private slots: - void commentTitleChanged(const QString &text); - private: - Ui::AnnotationCommentTab *ui; + std::unique_ptr<Ui::AnnotationCommentTab> ui; RichTextEditor *m_editor; Comment m_comment; + QPointer<DefaultAnnotationsModel> m_defaults; QString backupFile(const QString &filePath); void ensureDir(const QDir &dir); diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp index efdc727d75..cdc2611a76 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp @@ -61,8 +61,8 @@ void AnnotationEditor::showWidget() { m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(), m_modelNode.id(), - m_modelNode.customId(), - m_modelNode.annotation()); + m_modelNode.customId()); + m_dialog->setAnnotation(m_modelNode.annotation()); QObject::connect(m_dialog, &AnnotationEditorDialog::acceptedDialog, this, &AnnotationEditor::acceptedClicked); diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri index b1773c2dcf..d2340be8fb 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri @@ -3,13 +3,21 @@ HEADERS += $$PWD/annotationeditordialog.h HEADERS += $$PWD/annotationeditor.h HEADERS += $$PWD/globalannotationeditor.h HEADERS += $$PWD/globalannotationeditordialog.h +HEADERS += $$PWD/defaultannotations.h +HEADERS += $$PWD/annotationtableview.h +HEADERS += $$PWD/annotationtabwidget.h SOURCES += $$PWD/annotationcommenttab.cpp SOURCES += $$PWD/annotationeditordialog.cpp SOURCES += $$PWD/annotationeditor.cpp SOURCES += $$PWD/globalannotationeditor.cpp SOURCES += $$PWD/globalannotationeditordialog.cpp +SOURCES += $$PWD/defaultannotations.cpp +SOURCES += $$PWD/annotationtableview.cpp +SOURCES += $$PWD/annotationtabwidget.cpp FORMS += $$PWD/annotationcommenttab.ui FORMS += $$PWD/annotationeditordialog.ui FORMS += $$PWD/globalannotationeditordialog.ui + +RESOURCES += $$PWD/annotationeditor.qrc diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.qrc b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.qrc new file mode 100644 index 0000000000..5ccf08a77f --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/annotationeditor"> + <file>defaultannotations.json</file> + </qresource> +</RCC> diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp index 29b1dc5a8b..3269540466 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp @@ -24,80 +24,65 @@ ****************************************************************************/ #include "annotationeditordialog.h" -#include "ui_annotationeditordialog.h" #include "annotation.h" #include "annotationcommenttab.h" +#include "defaultannotations.h" -#include "ui_annotationcommenttab.h" +#include "ui_annotationeditordialog.h" #include <timelineicons.h> #include <utils/qtcassert.h> -#include <QObject> -#include <QToolBar> #include <QAction> #include <QMessageBox> +#include <QObject> +#include <QToolBar> namespace QmlDesigner { - -AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation) +BasicAnnotationEditorDialog::BasicAnnotationEditorDialog(QWidget *parent) : QDialog(parent) - , ui(new Ui::AnnotationEditorDialog) - , m_customId(customId) - , m_annotation(annotation) + , m_defaults(std::make_unique<DefaultAnnotationsModel>()) { - ui->setupUi(this); - setWindowFlag(Qt::Tool, true); setModal(true); + loadDefaultAnnotations(DefaultAnnotationsModel::defaultJsonFilePath()); - connect(this, &QDialog::accepted, this, &AnnotationEditorDialog::acceptedClicked); - - connect(ui->tabWidget, &QTabWidget::currentChanged, this, &AnnotationEditorDialog::tabChanged); - - auto *commentCornerWidget = new QToolBar; - - auto *commentAddAction = new QAction(TimelineIcons::ADD_TIMELINE.icon(), tr("Add Comment")); //timeline icons? - auto *commentRemoveAction = new QAction(TimelineIcons::REMOVE_TIMELINE.icon(), - tr("Remove Comment")); //timeline icons? - - connect(commentAddAction, &QAction::triggered, this, [this]() { - addComment(Comment()); - }); - - connect(commentRemoveAction, &QAction::triggered, this, [this]() { - - if (ui->tabWidget->count() == 0) { //it is not even supposed to happen but lets be sure - QTC_ASSERT(true, return); - return; - } - - int currentIndex = ui->tabWidget->currentIndex(); - QString currentTitle = ui->tabWidget->tabText(currentIndex); + connect(this, &QDialog::accepted, this, &BasicAnnotationEditorDialog::acceptedClicked); +} - QMessageBox *deleteDialog = new QMessageBox(this); - deleteDialog->setWindowTitle(currentTitle); - deleteDialog->setText(tr("Delete this comment?")); - deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - deleteDialog->setDefaultButton(QMessageBox::Yes); +BasicAnnotationEditorDialog::~BasicAnnotationEditorDialog() {} - int result = deleteDialog->exec(); +Annotation const &BasicAnnotationEditorDialog::annotation() const +{ + return m_annotation; +} - if (result == QMessageBox::Yes) { - removeComment(currentIndex); - } +void BasicAnnotationEditorDialog::setAnnotation(const Annotation &annotation) +{ + m_annotation = annotation; + fillFields(); +} - if (ui->tabWidget->count() == 0) //lets be sure that tabWidget is never empty - addComment(Comment()); - }); +void BasicAnnotationEditorDialog::loadDefaultAnnotations(QString const &filename) +{ + m_defaults->loadFromFile(filename); +} - commentCornerWidget->addAction(commentAddAction); - commentCornerWidget->addAction(commentRemoveAction); +DefaultAnnotationsModel *BasicAnnotationEditorDialog::defaultAnnotations() const +{ + return m_defaults.get(); +} - ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner); +AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, + const QString &targetId, + const QString &customId) + : BasicAnnotationEditorDialog(parent) + , ui(new Ui::AnnotationEditorDialog) + , m_customId(customId) +{ + ui->setupUi(this); ui->targetIdEdit->setText(targetId); - fillFields(); setWindowTitle(annotationEditorTitle); } @@ -106,17 +91,6 @@ AnnotationEditorDialog::~AnnotationEditorDialog() delete ui; } -void AnnotationEditorDialog::setAnnotation(const Annotation &annotation) -{ - m_annotation = annotation; - fillFields(); -} - -Annotation AnnotationEditorDialog::annotation() const -{ - return m_annotation; -} - void AnnotationEditorDialog::setCustomId(const QString &customId) { m_customId = customId; @@ -130,117 +104,34 @@ QString AnnotationEditorDialog::customId() const void AnnotationEditorDialog::acceptedClicked() { - m_customId = ui->customIdEdit->text(); - - Annotation annotation; - - annotation.removeComments(); - - for (int i = 0; i < ui->tabWidget->count(); i++) { - AnnotationCommentTab* tab = reinterpret_cast<AnnotationCommentTab*>(ui->tabWidget->widget(i)); - if (!tab) - continue; - - Comment comment = tab->currentComment(); - - if (!comment.isEmpty()) - annotation.addComment(comment); - } - - m_annotation = annotation; - + updateAnnotation(); emit AnnotationEditorDialog::acceptedDialog(); } -void AnnotationEditorDialog::commentTitleChanged(const QString &text, QWidget *tab) -{ - int tabIndex = ui->tabWidget->indexOf(tab); - if (tabIndex >= 0) - ui->tabWidget->setTabText(tabIndex, text); - - if (text.isEmpty()) - ui->tabWidget->setTabText(tabIndex, - (defaultTabName + " " + QString::number(tabIndex+1))); -} - void AnnotationEditorDialog::fillFields() { ui->customIdEdit->setText(m_customId); - setupComments(); + ui->tabWidget->setupComments(m_annotation.comments()); } -void AnnotationEditorDialog::setupComments() +void AnnotationEditorDialog::updateAnnotation() { - ui->tabWidget->setUpdatesEnabled(false); - - deleteAllTabs(); - - const QVector<Comment> comments = m_annotation.comments(); - - if (comments.isEmpty()) - addComment(Comment()); - - for (const Comment &comment : comments) { - addCommentTab(comment); - } - - ui->tabWidget->setUpdatesEnabled(true); + m_customId = ui->customIdEdit->text(); + Annotation annotation; + annotation.setComments(ui->tabWidget->fetchComments()); + m_annotation = annotation; } void AnnotationEditorDialog::addComment(const Comment &comment) { m_annotation.addComment(comment); - addCommentTab(comment); + ui->tabWidget->addCommentTab(comment); } void AnnotationEditorDialog::removeComment(int index) { - if ((m_annotation.commentsSize() > index) && (index >= 0)) { - m_annotation.removeComment(index); - removeCommentTab(index); - } -} - -void AnnotationEditorDialog::addCommentTab(const Comment &comment) -{ - auto commentTab = new AnnotationCommentTab(); - commentTab->setComment(comment); - - QString tabTitle(comment.title()); - int tabIndex = ui->tabWidget->addTab(commentTab, tabTitle); - ui->tabWidget->setCurrentIndex(tabIndex); - - if (tabTitle.isEmpty()) { - const QString appendix = ((tabIndex > 0) ? QString::number(tabIndex+1) : ""); - - tabTitle = QString("%1 %2").arg(defaultTabName).arg(appendix); - - ui->tabWidget->setTabText(tabIndex, tabTitle); - } - - connect(commentTab, &AnnotationCommentTab::titleChanged, - this, &AnnotationEditorDialog::commentTitleChanged); -} - -void AnnotationEditorDialog::removeCommentTab(int index) -{ - if ((ui->tabWidget->count() > index) && (index >= 0)) { - ui->tabWidget->removeTab(index); - } -} - -void AnnotationEditorDialog::deleteAllTabs() -{ - while (ui->tabWidget->count() > 0) { - QWidget *w = ui->tabWidget->widget(0); - ui->tabWidget->removeTab(0); - delete w; - } -} - -void AnnotationEditorDialog::tabChanged(int index) -{ - (void) index; + m_annotation.removeComment(index); + ui->tabWidget->removeTab(index); } } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h index bc304c9ddd..856eb9bb60 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h @@ -34,46 +34,62 @@ namespace QmlDesigner { namespace Ui { class AnnotationEditorDialog; } +class DefaultAnnotationsModel; -class AnnotationEditorDialog : public QDialog +class BasicAnnotationEditorDialog : public QDialog { Q_OBJECT - public: - explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation); - ~AnnotationEditorDialog(); + explicit BasicAnnotationEditorDialog(QWidget *parent); + ~BasicAnnotationEditorDialog(); + Annotation const &annotation() const; void setAnnotation(const Annotation &annotation); - Annotation annotation() const; - void setCustomId(const QString &customId); - QString customId() const; + void loadDefaultAnnotations(QString const &filename); + + DefaultAnnotationsModel *defaultAnnotations() const; signals: void acceptedDialog(); //use instead of QDialog::accepted +protected: + virtual void fillFields() = 0; + virtual void acceptedClicked() = 0; + + Annotation m_annotation; + std::unique_ptr<DefaultAnnotationsModel> m_defaults; +}; + +class AnnotationEditorDialog : public BasicAnnotationEditorDialog +{ + Q_OBJECT + +public: + explicit AnnotationEditorDialog(QWidget *parent, + const QString &targetId, + const QString &customId); + ~AnnotationEditorDialog(); + + void setCustomId(const QString &customId); + QString customId() const; + private slots: - void acceptedClicked(); - void tabChanged(int index); - void commentTitleChanged(const QString &text, QWidget *tab); + void acceptedClicked() override; private: - void fillFields(); - void setupComments(); + void fillFields() override; + void updateAnnotation(); + void addComment(const Comment &comment); void removeComment(int index); - void addCommentTab(const Comment &comment); - void removeCommentTab(int index); - void deleteAllTabs(); - private: const QString annotationEditorTitle = {tr("Annotation Editor")}; - const QString defaultTabName = {tr("Annotation")}; + Ui::AnnotationEditorDialog *ui; QString m_customId; - Annotation m_annotation; }; } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui index 92dc5c71d5..5dd747a7dc 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui @@ -56,7 +56,7 @@ </widget> </item> <item> - <widget class="QTabWidget" name="tabWidget"> + <widget class="AnnotationTabWidget" name="tabWidget"> <property name="currentIndex"> <number>0</number> </property> @@ -90,6 +90,14 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>AnnotationTabWidget</class> + <extends>QTabWidget</extends> + <header>annotationtabwidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> <tabstops> <tabstop>targetIdEdit</tabstop> <tabstop>customIdEdit</tabstop> diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp new file mode 100644 index 0000000000..8e289a344c --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp @@ -0,0 +1,446 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "annotationtableview.h" + +#include "defaultannotations.h" + +#include <utils/qtcolorbutton.h> + +#include <QApplication> +#include <QCheckBox> +#include <QComboBox> +#include <QCompleter> +#include <QDoubleSpinBox> +#include <QHeaderView> +#include <QItemEditorFactory> +#include <QKeyEvent> +#include <QLabel> +#include <QLineEdit> +#include <QPainter> +#include <QPushButton> +#include <QStandardItem> +#include <QStandardItemModel> +#include <QStringListModel> +#include <QStyle> +#include <QTextEdit> + +namespace QmlDesigner { + +struct ColumnId +{ + enum Column { + Title = 0, + Author = 1, + Value = 2, + }; +}; + +CommentDelegate::CommentDelegate(QObject *parent) + : QItemDelegate(parent) + , m_completer(std::make_unique<QCompleter>()) +{} + +CommentDelegate::~CommentDelegate() {} + +DefaultAnnotationsModel *CommentDelegate::defaultAnnotations() const +{ + return m_defaults; +} + +void CommentDelegate::setDefaultAnnotations(DefaultAnnotationsModel *defaults) +{ + m_defaults = defaults; + m_completer->setModel(m_defaults); +} + +QCompleter *CommentDelegate::completer() const +{ + return m_completer.get(); +} + +void CommentDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + editor->setGeometry(option.rect); +} + +Comment CommentDelegate::comment(QModelIndex const &index) +{ + auto *model = index.model(); + return model->data(model->index(index.row(), ColumnId::Title), CommentRole).value<Comment>(); +} + +CommentTitleDelegate::CommentTitleDelegate(QObject *parent) + : CommentDelegate(parent) +{} + +CommentTitleDelegate::~CommentTitleDelegate() {} + +QWidget *CommentTitleDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + auto *editor = new QComboBox(parent); + editor->setEditable(true); + editor->setCompleter(completer()); + editor->setFrame(false); + editor->setFocusPolicy(Qt::StrongFocus); + + return editor; +} + +void CommentTitleDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + QString text = index.model()->data(index, Qt::DisplayRole).toString(); + auto *comboBox = qobject_cast<QComboBox *>(editor); + comboBox->setModel(defaultAnnotations()); + comboBox->setCurrentText(text); +} + +void CommentTitleDelegate::setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const +{ + auto *comboBox = qobject_cast<QComboBox *>(editor); + auto oldText = model->data(index, Qt::EditRole).toString(); + auto newText = comboBox->currentText(); + + if (oldText != newText) { + model->setData(index, comboBox->currentText(), Qt::EditRole); + auto comment = model->data(index, CommentRole).value<Comment>(); + comment.setTitle(newText); + model->setData(index, QVariant::fromValue(comment), CommentRole); + + // Set default value to data item + auto colIdx = model->index(index.row(), ColumnId::Value); + if (defaultAnnotations()->hasDefault(comment)) + model->setData(colIdx, defaultAnnotations()->defaultValue(comment), Qt::DisplayRole); + else + // Reset to rich text when there is no default item + model->setData(colIdx, + QVariant::fromValue<RichTextProxy>({comment.text()}), + Qt::DisplayRole); + } +} + +CommentValueDelegate::CommentValueDelegate(QObject *parent) + : CommentDelegate(parent) +{} + +CommentValueDelegate::~CommentValueDelegate() {} + +void CommentValueDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + auto data = index.model()->data(index, Qt::DisplayRole); + if (data.userType() == qMetaTypeId<RichTextProxy>()) + drawDisplay(painter, option, option.rect, data.value<RichTextProxy>().plainText()); + else if (data.userType() == QMetaType::QColor) + painter->fillRect(option.rect, data.value<QColor>()); + else + QItemDelegate::paint(painter, option, index); +} + +void CommentValueDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + auto data = index.model()->data(index, Qt::DisplayRole); + if (data.userType() == qMetaTypeId<RichTextProxy>()) { + auto richText = data.value<RichTextProxy>(); + auto *e = qobject_cast<RichTextCellEditor *>(editor); + e->setText(richText.plainText()); + e->setupSignal(index.row(), comment(index).title()); + connect(e, + &RichTextCellEditor::richTextClicked, + this, + &CommentValueDelegate::richTextEditorRequested, + Qt::UniqueConnection); + } else if (data.userType() == QMetaType::QString) { + auto *e = qobject_cast<QLineEdit *>(editor); + e->setText(data.toString()); + } else if (data.userType() == QMetaType::QColor) { + auto *e = qobject_cast<Utils::QtColorButton *>(editor); + e->setColor(data.value<QColor>()); + } else + QItemDelegate::setEditorData(editor, index); +} + +void CommentValueDelegate::setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const +{ + auto data = model->data(index, Qt::EditRole); + if (data.userType() == qMetaTypeId<RichTextProxy>()) + return; + else if (data.userType() == QMetaType::QColor) + model->setData(index, + qobject_cast<Utils::QtColorButton *>(editor)->color(), + Qt::DisplayRole); + else if (data.userType() == QMetaType::QString) + model->setData(index, qobject_cast<QLineEdit *>(editor)->text(), Qt::DisplayRole); + else + QItemDelegate::setModelData(editor, model, index); +} + +RichTextCellEditor::RichTextCellEditor(QWidget *parent) + : QLabel(parent) +{} + +RichTextCellEditor::~RichTextCellEditor() {} + +RichTextProxy RichTextCellEditor::richText() const +{ + return m_richText; +} + +void RichTextCellEditor::setRichText(const RichTextProxy &richText) +{ + if (richText.text == m_richText.text) + return; + + m_richText = richText; + setText(richText.plainText()); + + emit richTextChanged(); +} + +void RichTextCellEditor::setupSignal(int index, const QString &commentTitle) +{ + if (m_connection) + disconnect(m_connection); + + m_connection = connect(this, &RichTextCellEditor::clicked, this, [=]() { + emit richTextClicked(index, commentTitle); + }); +} + +void RichTextCellEditor::mouseReleaseEvent(QMouseEvent *) +{ + emit clicked(); +} + +AnnotationTableView::AnnotationTableView(QWidget *parent) + : QTableView(parent) + , m_model(std::make_unique<QStandardItemModel>()) + , m_editorFactory(std::make_unique<QItemEditorFactory>()) +{ + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::ContiguousSelection); + + setModel(m_model.get()); + connect(m_model.get(), &QStandardItemModel::itemChanged, this, [this](QStandardItem *item) { + if (item->isCheckable()) + m_model->setData(item->index(), item->checkState() == Qt::Checked); + + if (this->m_modelUpdating) + return; + + auto *valueItem = m_model->item(item->row(), ColumnId::Value); + + // When comment title was edited, make value item editable + if (item->column() == ColumnId::Title && valueItem) { + valueItem->setEditable(!item->text().isEmpty()); + valueItem->setCheckable(valueItem->data(Qt::DisplayRole).userType() == QMetaType::Bool); + } + + m_modelUpdating = true; + if (!rowIsEmpty(m_model->rowCount() - 1)) + addEmptyRow(); + m_modelUpdating = false; + }); + + horizontalHeader()->setStretchLastSection(true); + horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + + m_editorFactory->registerEditor(qMetaTypeId<RichTextProxy>(), + new QItemEditorCreator<RichTextCellEditor>("richText")); + m_editorFactory->registerEditor(QMetaType::QColor, + new QItemEditorCreator<Utils::QtColorButton>("color")); + + m_valueDelegate.setItemEditorFactory(m_editorFactory.get()); + connect(&m_valueDelegate, + &CommentValueDelegate::richTextEditorRequested, + this, + &AnnotationTableView::richTextEditorRequested); + + verticalHeader()->hide(); +} + +AnnotationTableView::~AnnotationTableView() {} + +QVector<Comment> AnnotationTableView::fetchComments() const +{ + QVector<Comment> comments; + + for (int i = 0; i < m_model->rowCount(); ++i) { + Comment comment = fetchComment(i); + if (!comment.isEmpty()) + comments.push_back(comment); + } + + return comments; +} + +Comment AnnotationTableView::fetchComment(int row) const +{ + auto *item = m_model->item(row, ColumnId::Title); + if (item->text().isEmpty()) + return {}; + + Comment comment = item->data().value<Comment>(); + comment.setTitle(item->text()); + comment.setAuthor(m_model->item(row, ColumnId::Author)->text()); + comment.setText(dataToCommentText(m_model->item(row, ColumnId::Value)->data(Qt::DisplayRole))); + return comment; +} + +void AnnotationTableView::setupComments(QVector<Comment> const &comments) +{ + m_model->clear(); + m_modelUpdating = true; + m_model->setColumnCount(3); + m_model->setHeaderData(ColumnId::Title, Qt::Horizontal, tr("Title")); + m_model->setHeaderData(ColumnId::Author, Qt::Horizontal, tr("Author")); + m_model->setHeaderData(ColumnId::Value, Qt::Horizontal, tr("Value")); + setItemDelegateForColumn(ColumnId::Title, &m_titleDelegate); + setItemDelegateForColumn(ColumnId::Value, &m_valueDelegate); + + for (auto &comment : comments) { + if (comment.isEmpty()) + continue; + + addEmptyRow(); + changeRow(m_model->rowCount() - 1, comment); + } + + addEmptyRow(); + m_modelUpdating = false; +} + +DefaultAnnotationsModel *AnnotationTableView::defaultAnnotations() const +{ + return m_defaults; +} + +void AnnotationTableView::setDefaultAnnotations(DefaultAnnotationsModel *defaults) +{ + m_defaults = defaults; + m_titleDelegate.setDefaultAnnotations(defaults); + m_valueDelegate.setDefaultAnnotations(defaults); +} + +void AnnotationTableView::changeRow(int index, Comment const &comment) +{ + auto *titleItem = m_model->item(index, ColumnId::Title); + auto *authorItem = m_model->item(index, ColumnId::Author); + auto *textItem = m_model->item(index, ColumnId::Value); + + titleItem->setText(comment.title()); + titleItem->setData(QVariant::fromValue<Comment>(comment)); + + authorItem->setText(comment.author()); + + QVariant data = commentToData(comment, + m_defaults ? m_defaults->defaultType(comment) + : QMetaType::UnknownType); + + textItem->setEditable(data.isValid()); + textItem->setCheckable(data.userType() == QMetaType::Bool); + textItem->setData(data, Qt::DisplayRole); +} + +void AnnotationTableView::removeRow(int index) +{ + m_model->removeRow(index); +} + +void AnnotationTableView::removeSelectedRows() +{ + const auto selRows = selectionModel()->selectedRows(); + for (auto it = selRows.rbegin(); it != selRows.rend(); ++it) + removeRow(it->row()); +} + +void AnnotationTableView::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Delete) + removeSelectedRows(); +} + +void AnnotationTableView::addEmptyRow() +{ + auto *valueItem = new QStandardItem; + valueItem->setEditable(false); + m_model->appendRow({new QStandardItem, new QStandardItem, valueItem}); +} + +bool AnnotationTableView::rowIsEmpty(int row) const +{ + auto itemText = [&](int col) { + return m_model->item(row, col) ? m_model->item(row, col)->text() : QString(); + }; + + return QString(itemText(0) + itemText(1) + itemText(2)).isEmpty(); +} + +QString AnnotationTableView::dataToCommentText(QVariant const &data) +{ + auto type = data.userType(); + if (type == qMetaTypeId<RichTextProxy>()) + return data.value<RichTextProxy>().text; + + switch (type) { + case QMetaType::QColor: + return data.value<QColor>().name(); + case QMetaType::Bool: + return data.toBool() ? QStringLiteral("true") : QStringLiteral("false"); + case QMetaType::QString: + return data.toString(); + } + + return {}; +} + +QVariant AnnotationTableView::commentToData(Comment const& comment, QMetaType::Type type) +{ + switch (type) { + case QMetaType::Bool: + return QVariant::fromValue(comment.deescapedText().toLower().trimmed() == "true"); + case QMetaType::QColor: + return QVariant::fromValue(QColor(comment.deescapedText().toLower().trimmed())); + break; + case QMetaType::QString: + return QVariant::fromValue(comment.text()); + break; + default: + if (type == qMetaTypeId<RichTextProxy>() || type == QMetaType::UnknownType) + return QVariant::fromValue<RichTextProxy>({comment.text()}); + } + return {}; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.h b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.h new file mode 100644 index 0000000000..6bc6e96c77 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include <QItemDelegate> +#include <QLabel> +#include <QPointer> +#include <QTableView> + +#include <memory> + +#include "annotation.h" +#include "defaultannotations.h" + +QT_BEGIN_NAMESPACE +class QStandardItemModel; +class QCompleter; +QT_END_NAMESPACE + +namespace QmlDesigner { +class CommentDelegate : public QItemDelegate +{ + Q_OBJECT +public: + enum Role { CommentRole = Qt::UserRole + 1 }; + + CommentDelegate(QObject *parent = nullptr); + ~CommentDelegate() override; + + DefaultAnnotationsModel *defaultAnnotations() const; + void setDefaultAnnotations(DefaultAnnotationsModel *); + + QCompleter *completer() const; + + void updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + + static Comment comment(QModelIndex const &); + +private: + std::unique_ptr<QCompleter> m_completer; + QPointer<DefaultAnnotationsModel> m_defaults; +}; + +class CommentTitleDelegate : public CommentDelegate +{ + Q_OBJECT +public: + CommentTitleDelegate(QObject *parent = nullptr); + ~CommentTitleDelegate() override; + + QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + + void setEditorData(QWidget *editor, const QModelIndex &index) const override; + void setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const override; +signals: + void commentChanged(int row, Comment const &); +}; + +class CommentValueDelegate : public CommentDelegate +{ + Q_OBJECT +public: + CommentValueDelegate(QObject *parent = nullptr); + ~CommentValueDelegate(); + + void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + + void setEditorData(QWidget *editor, const QModelIndex &index) const override; + void setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const override; +signals: + void richTextEditorRequested(int index, QString const &richText); +}; + +class RichTextCellEditor : public QLabel +{ + Q_OBJECT + Q_PROPERTY(QmlDesigner::RichTextProxy richText READ richText WRITE setRichText NOTIFY + richTextChanged USER true) +public: + RichTextCellEditor(QWidget *parent = nullptr); + ~RichTextCellEditor() override; + + RichTextProxy richText() const; + void setRichText(RichTextProxy const &); + + void setupSignal(int row, QString const &commentTitle); + +signals: + void clicked(); + void richTextChanged(); + void richTextClicked(int index, QString const &text); + +protected: + void mouseReleaseEvent(QMouseEvent *) override; + +private: + RichTextProxy m_richText; + QMetaObject::Connection m_connection; +}; + +class AnnotationTableView : public QTableView +{ + Q_OBJECT +public: + AnnotationTableView(QWidget *parent = nullptr); + ~AnnotationTableView(); + + QVector<Comment> fetchComments() const; + Comment fetchComment(int row) const; + void setupComments(QVector<Comment> const &comments); + + DefaultAnnotationsModel *defaultAnnotations() const; + void setDefaultAnnotations(DefaultAnnotationsModel *); + + void changeRow(int index, Comment const &comment); + void removeRow(int index); + void removeSelectedRows(); + +signals: + void richTextEditorRequested(int index, QString const &commentTitle); + +protected: + void keyPressEvent(QKeyEvent *) override; + +private: + void addEmptyRow(); + bool rowIsEmpty(int row) const; + static QString dataToCommentText(QVariant const &); + static QVariant commentToData(Comment const&, QMetaType::Type type); + + CommentTitleDelegate m_titleDelegate; + CommentValueDelegate m_valueDelegate; + + bool m_modelUpdating = false; + std::unique_ptr<QStandardItemModel> m_model; + std::unique_ptr<QItemEditorFactory> m_editorFactory; + QPointer<DefaultAnnotationsModel> m_defaults; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.cpp new file mode 100644 index 0000000000..8a3339acc4 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "annotationtabwidget.h" + +#include "annotationcommenttab.h" + +#include <timelineeditor/timelineicons.h> + +#include <QAction> +#include <QMessageBox> +#include <QToolBar> + +namespace QmlDesigner { +AnnotationTabWidget::AnnotationTabWidget(QWidget *parent) + : QTabWidget(parent) +{ + auto *commentCornerWidget = new QToolBar; + + auto *commentAddAction = new QAction(TimelineIcons::ADD_TIMELINE.icon(), + tr("Add Comment")); //timeline icons? + auto *commentRemoveAction = new QAction(TimelineIcons::REMOVE_TIMELINE.icon(), + tr("Remove Comment")); //timeline icons? + connect(commentAddAction, &QAction::triggered, this, [this]() { addCommentTab(); }); + + connect(commentRemoveAction, &QAction::triggered, this, [this]() { + int currentIndex = this->currentIndex(); + QString currentTitle = tabText(currentIndex); + if (QMessageBox::question(this, + tr("Global Annotation"), + tr("Do you want to delete this annotation?")) + == QMessageBox::Yes) { + removeTab(currentIndex); + if (count() == 0) //lets be sure that tabWidget is never empty + addCommentTab(); + } + }); + + commentCornerWidget->addAction(commentAddAction); + commentCornerWidget->addAction(commentRemoveAction); + setCornerWidget(commentCornerWidget, Qt::TopRightCorner); +} + +AnnotationTabWidget::~AnnotationTabWidget() {} + +QVector<Comment> AnnotationTabWidget::fetchComments() const +{ + QVector<Comment> comments; + for (int i = 0; i < count(); i++) { + auto *tab = qobject_cast<AnnotationCommentTab *>(widget(i)); + if (!tab) + continue; + + Comment comment = tab->currentComment(); + + if (!comment.isEmpty()) + comments.push_back(comment); + } + + return comments; +} + +void AnnotationTabWidget::setupComments(QVector<Comment> const &comments) +{ + setUpdatesEnabled(false); + + deleteAllTabs(); + if (comments.isEmpty()) + addCommentTab(); + + for (const Comment &comment : comments) + addCommentTab(comment); + + setUpdatesEnabled(true); +} + +DefaultAnnotationsModel *AnnotationTabWidget::defaultAnnotations() const +{ + return m_defaults; +} + +void AnnotationTabWidget::setDefaultAnnotations(DefaultAnnotationsModel *defaults) +{ + m_defaults = defaults; + for (int i = 0; i < count(); i++) { + // The tab widget might be contain regular QTabs initially, hence we need this qobject_cast test + if (auto *tab = qobject_cast<AnnotationCommentTab *>(widget(i))) + tab->setDefaultAnnotations(defaults); + } +} + +void AnnotationTabWidget::onCommentTitleChanged(const QString &text, QWidget *tab) +{ + int tabIndex = indexOf(tab); + if (tabIndex >= 0) + setTabText(tabIndex, text); + + if (text.isEmpty()) + setTabText(tabIndex, defaultTabName + " " + QString::number(tabIndex + 1)); +} + +void AnnotationTabWidget::addCommentTab(const Comment &comment) +{ + auto *commentTab = new AnnotationCommentTab(); + commentTab->setDefaultAnnotations(m_defaults); + commentTab->setComment(comment); + + QString tabTitle(comment.title()); + int tabIndex = addTab(commentTab, tabTitle); + setCurrentIndex(tabIndex); + + if (tabTitle.isEmpty()) { + const QString appendix = ((tabIndex > 0) ? QString::number(tabIndex + 1) : ""); + tabTitle = QString("%1 %2").arg(defaultTabName).arg(appendix); + setTabText(tabIndex, tabTitle); + } + connect(commentTab, + &AnnotationCommentTab::titleChanged, + this, + &AnnotationTabWidget::onCommentTitleChanged); +} + +void AnnotationTabWidget::deleteAllTabs() +{ + while (count() > 0) { + QWidget *w = widget(0); + removeTab(0); + delete w; + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.h b/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.h new file mode 100644 index 0000000000..962a36e45e --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include <QTabWidget> + +#include "annotation.h" +#include "defaultannotations.h" + +namespace QmlDesigner { +class AnnotationCommentTab; + +class AnnotationTabWidget : public QTabWidget +{ + Q_OBJECT +public: + AnnotationTabWidget(QWidget *parent = nullptr); + ~AnnotationTabWidget(); + + QVector<Comment> fetchComments() const; + void setupComments(QVector<Comment> const &comments); + + DefaultAnnotationsModel *defaultAnnotations() const; + void setDefaultAnnotations(DefaultAnnotationsModel *); + +public slots: + void addCommentTab(const Comment &comment = {}); + void deleteAllTabs(); + +private slots: + void onCommentTitleChanged(const QString &text, QWidget *tab); + +private: + const QString defaultTabName = {tr("Annotation")}; + + QPointer<DefaultAnnotationsModel> m_defaults; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp new file mode 100644 index 0000000000..b5e0d54840 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "defaultannotations.h" + +#include <QColor> +#include <QFile> +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonValue> + +namespace QmlDesigner { +DefaultAnnotationsModel::DefaultAnnotationsModel(QObject *parent) + : QAbstractListModel(parent) +{ + qRegisterMetaType<RichTextProxy>(); +} + +DefaultAnnotationsModel::~DefaultAnnotationsModel() {} + +int DefaultAnnotationsModel::rowCount(const QModelIndex &) const +{ + return static_cast<int>(m_defaults.size()); +} + +QVariant DefaultAnnotationsModel::data(const QModelIndex &index, int role) const +{ + const auto row = static_cast<size_t>(index.row()); + if (!index.isValid() || m_defaults.size() < row) + return {}; + + auto &item = m_defaults[row]; + + switch (role) { + case Qt::DisplayRole: + case Qt::EditRole: + case Name: + return item.first; + case Type: + return item.second.typeName(); + case Default: + return item.second; + } + + return {}; +} + +QVariantMap DefaultAnnotationsModel::fetchData() const +{ + return m_defaultMap; +} + +bool DefaultAnnotationsModel::hasDefault(const Comment &comment) const +{ + return m_defaultMap.count(comment.title().toLower()); +} + +QMetaType::Type DefaultAnnotationsModel::defaultType(const Comment &comment) const +{ + return hasDefault(comment) ? QMetaType::Type(m_defaultMap[comment.title().toLower()].userType()) + : QMetaType::UnknownType; +} + +QVariant DefaultAnnotationsModel::defaultValue(const Comment &comment) const +{ + return hasDefault(comment) ? m_defaultMap.value(comment.title().toLower()) : QVariant(); +} + +bool DefaultAnnotationsModel::isRichText(const Comment &comment) const +{ + const auto type = defaultType(comment); + return type == QMetaType::UnknownType || type == qMetaTypeId<RichTextProxy>(); +} + +void DefaultAnnotationsModel::loadFromFile(QString const &filename) +{ + QFile file(filename); + if (file.open(QFile::ReadOnly)) { + loadFromFile(&file); + } +} + +void DefaultAnnotationsModel::loadFromFile(QIODevice *io) +{ + QJsonParseError error; + auto doc = QJsonDocument::fromJson(io->readAll(), &error); + + if (error.error == QJsonParseError::NoError) + loadFromJson(doc); + else { + } // TODO: Error handling +} + +void DefaultAnnotationsModel::loadFromJson(const QJsonDocument &doc) +{ + beginResetModel(); + m_defaultMap = asVariantMapFromJson(doc); + m_defaults.clear(); + m_defaults.reserve(m_defaultMap.size()); + + for (auto &key : m_defaultMap.keys()) + m_defaults.emplace_back(key, m_defaultMap.value(key)); + + endResetModel(); +} + +QVariantMap DefaultAnnotationsModel::asVariantMapFromJson(const QJsonDocument &doc) +{ + QVariantMap map; + QJsonObject obj = doc.object(); + for (auto key : obj.keys()) { + key = key.toLower(); + auto val = obj[key]; + + switch (val.type()) { + case QJsonValue::Double: + map[key] = double{0.0}; + break; + case QJsonValue::String: + map[key] = QString{}; + break; + case QJsonValue::Bool: + map[key] = false; + break; + case QJsonValue::Object: { + auto o = val.toObject(); + auto type = o["type"].toString().toLower(); + auto val = o["value"].toVariant(); + + if (type == QStringLiteral("richtext")) + map[key] = QVariant::fromValue(RichTextProxy{val.toString()}); + else if (type == QStringLiteral("string")) + map[key] = QVariant::fromValue(val.toString()); + else if (type == QStringLiteral("bool")) + map[key] = QVariant::fromValue(val.toBool()); + else if (type == QStringLiteral("double")) + map[key] = QVariant::fromValue(val.toDouble()); + else if (type == QStringLiteral("color")) + map[key] = QVariant::fromValue(QColor(val.toString())); + } + } + } + + return map; +} + +QString DefaultAnnotationsModel::defaultJsonFilePath() +{ + return QStringLiteral(":/annotationeditor/defaultannotations.json"); +} + +QString RichTextProxy::plainText() const +{ + QString plainText(text); + plainText.remove(QRegularExpression("<.*?>")); + return plainText.mid(plainText.indexOf("}") + 1); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.h b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.h new file mode 100644 index 0000000000..3553720773 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#pragma once + +#include "annotation.h" + +#include <QAbstractListModel> + +QT_BEGIN_NAMESPACE +class QJsonDocument; +QT_END_NAMESPACE + +namespace QmlDesigner { + +// We need this proxy type to distinguish between a 'normal' QString +// and a 'richtext' string when they are stored in a QVariant +struct RichTextProxy +{ + QString text; + + QString plainText() const; +}; + +class DefaultAnnotationsModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum Role { Name = Qt::UserRole + 1, Type, Default }; + Q_ENUM(Role) + + DefaultAnnotationsModel(QObject *parent = nullptr); + ~DefaultAnnotationsModel() override; + + int rowCount(const QModelIndex & = {}) const override; + QVariant data(const QModelIndex &, int role) const override; + + QVariantMap fetchData() const; + + bool hasDefault(const Comment &comment) const; + QMetaType::Type defaultType(const Comment &comment) const; + QVariant defaultValue(const Comment &comment) const; + bool isRichText(const Comment &comment) const; + + void loadFromFile(QString const &); + void loadFromFile(QIODevice *); + void loadFromJson(const QJsonDocument &); + + static QVariantMap asVariantMapFromJson(const QJsonDocument &); + static QString defaultJsonFilePath(); + +private: + std::vector<std::pair<QString, QVariant>> m_defaults; + QVariantMap m_defaultMap; +}; + +} // namespace QmlDesigner + +Q_DECLARE_METATYPE(QmlDesigner::RichTextProxy); diff --git a/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.json b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.json new file mode 100644 index 0000000000..aaa060a555 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.json @@ -0,0 +1,36 @@ +{ + "description" : "", + "display condition" : "", + "helper lines" : true, + "position marker" : true, + "highlight" : true, + "project author" : "", + "project confirmed" : true, + "project developer" : "", + "project distributor" : "", + "project modified" : "", + "project type" : "", + "project version" : "", + "screen description" : "", + "section" : "", + "normalcolor" : { + "type": "color", + "value": "#000000" + }, + "focuscolor" : { + "type": "color", + "value": "#000000" + }, + "selectedcolor" : { + "type": "color", + "value": "#000000" + }, + "pressedcolor" : { + "type": "color", + "value": "#000000" + }, + "overview" : { + "type": "richtext", + "value": "" + } +} diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp index f17833b0c7..8875e9ba83 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp @@ -50,8 +50,8 @@ GlobalAnnotationEditor::~GlobalAnnotationEditor() void GlobalAnnotationEditor::showWidget() { m_dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(), - modelNode().globalAnnotation(), modelNode().globalStatus()); + m_dialog->setAnnotation(modelNode().globalAnnotation()); QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::acceptedDialog, this, &GlobalAnnotationEditor::acceptedClicked); @@ -142,7 +142,6 @@ void GlobalAnnotationEditor::acceptedClicked() hideWidget(); emit accepted(); - emit annotationChanged(); } diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp index ecfa00baab..3722935643 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp @@ -24,87 +24,55 @@ ****************************************************************************/ #include "globalannotationeditordialog.h" -#include "ui_globalannotationeditordialog.h" #include "annotation.h" #include "annotationcommenttab.h" - -#include "ui_annotationcommenttab.h" +#include "ui_globalannotationeditordialog.h" #include <timelineicons.h> #include <utils/qtcassert.h> -#include <QObject> -#include <QToolBar> #include <QAction> #include <QMessageBox> +#include <QObject> +#include <QToolBar> namespace QmlDesigner { -GlobalAnnotationEditorDialog::GlobalAnnotationEditorDialog(QWidget *parent, const Annotation &annotation, GlobalAnnotationStatus status) - : QDialog(parent) +GlobalAnnotationEditorDialog::GlobalAnnotationEditorDialog(QWidget *parent, + GlobalAnnotationStatus status) + : BasicAnnotationEditorDialog(parent) , ui(new Ui::GlobalAnnotationEditorDialog) - , m_annotation(annotation) , m_globalStatus(status) , m_statusIsActive(false) { ui->setupUi(this); - - setWindowFlag(Qt::Tool, true); - setModal(true); - - connect(this, &QDialog::accepted, this, &GlobalAnnotationEditorDialog::acceptedClicked); - - connect(ui->tabWidget, &QTabWidget::currentChanged, this, &GlobalAnnotationEditorDialog::tabChanged); - - auto *commentCornerWidget = new QToolBar; - - auto *commentAddAction = new QAction(TimelineIcons::ADD_TIMELINE.icon(), tr("Add Comment")); //timeline icons? - auto *commentRemoveAction = new QAction(TimelineIcons::REMOVE_TIMELINE.icon(), - tr("Remove Comment")); //timeline icons? - - connect(commentAddAction, &QAction::triggered, this, [this]() { - addComment(Comment()); - }); - - connect(commentRemoveAction, &QAction::triggered, this, [this]() { - - if (ui->tabWidget->count() == 0) { //it is not even supposed to happen but lets be sure - QTC_ASSERT(false, return); - return; - } - - int currentIndex = ui->tabWidget->currentIndex(); - QString currentTitle = ui->tabWidget->tabText(currentIndex); - - QMessageBox *deleteDialog = new QMessageBox(this); - deleteDialog->setWindowTitle(currentTitle); - deleteDialog->setText(tr("Delete this comment?")); - deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - deleteDialog->setDefaultButton(QMessageBox::Yes); - - int result = deleteDialog->exec(); - - if (result == QMessageBox::Yes) { - removeComment(currentIndex); - } - - if (ui->tabWidget->count() == 0) //lets be sure that tabWidget is never empty - addComment(Comment()); - }); - - commentCornerWidget->addAction(commentAddAction); - commentCornerWidget->addAction(commentRemoveAction); - - ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner); - - connect(ui->statusAddButton, &QPushButton::clicked, [&](bool){ + ui->tabWidget->setDefaultAnnotations(defaultAnnotations()); + ui->tableView->setDefaultAnnotations(defaultAnnotations()); + + connect(ui->tableView, + &AnnotationTableView::richTextEditorRequested, + this, + [&](int index, QString const &) { + switchToTabView(); + ui->tabWidget->setCurrentIndex(index); + }); + + connect(ui->statusAddButton, &QPushButton::clicked, this, [&](bool) { setStatusVisibility(true); }); - setStatus(m_globalStatus); + connect(ui->rbTableView, + &QRadioButton::clicked, + this, + &GlobalAnnotationEditorDialog::switchToTableView); + connect(ui->rbTabView, + &QRadioButton::clicked, + this, + &GlobalAnnotationEditorDialog::switchToTabView); - fillFields(); + setStatus(m_globalStatus); setWindowTitle(globalEditorTitle); + switchToTabView(); } GlobalAnnotationEditorDialog::~GlobalAnnotationEditorDialog() @@ -112,26 +80,18 @@ GlobalAnnotationEditorDialog::~GlobalAnnotationEditorDialog() delete ui; } -void GlobalAnnotationEditorDialog::setAnnotation(const Annotation &annotation) +GlobalAnnotationEditorDialog::ViewMode GlobalAnnotationEditorDialog::viewMode() const { - m_annotation = annotation; - fillFields(); -} - -Annotation GlobalAnnotationEditorDialog::annotation() const -{ - return m_annotation; + return ui->rbTableView->isChecked() ? TableView : TabsView; } void GlobalAnnotationEditorDialog::setStatus(GlobalAnnotationStatus status) { m_globalStatus = status; + bool hasStatus = status.status() != GlobalAnnotationStatus::NoStatus; - bool hasStatus = (status.status() != GlobalAnnotationStatus::NoStatus); - - if (hasStatus) { + if (hasStatus) ui->statusComboBox->setCurrentIndex(int(status.status())); - } setStatusVisibility(hasStatus); } @@ -141,117 +101,73 @@ GlobalAnnotationStatus GlobalAnnotationEditorDialog::globalStatus() const return m_globalStatus; } -void GlobalAnnotationEditorDialog::acceptedClicked() +void GlobalAnnotationEditorDialog::showStatusContainer(bool show) { - Annotation annotation; - - annotation.removeComments(); - - for (int i = 0; i < ui->tabWidget->count(); i++) { - AnnotationCommentTab* tab = reinterpret_cast<AnnotationCommentTab*>(ui->tabWidget->widget(i)); - if (!tab) - continue; - - Comment comment = tab->currentComment(); - - if (!comment.isEmpty()) - annotation.addComment(comment); - } - - m_annotation = annotation; - - if (m_statusIsActive) { - m_globalStatus.setStatus(ui->statusComboBox->currentIndex()); - } + ui->statusContainer->setVisible(show); +} - emit GlobalAnnotationEditorDialog::acceptedDialog(); +void GlobalAnnotationEditorDialog::switchToTabView() +{ + m_annotation.setComments(ui->tableView->fetchComments()); + ui->rbTabView->setChecked(true); + ui->tableView->hide(); + ui->tabWidget->show(); + fillFields(); } -void GlobalAnnotationEditorDialog::commentTitleChanged(const QString &text, QWidget *tab) +void GlobalAnnotationEditorDialog::switchToTableView() { - int tabIndex = ui->tabWidget->indexOf(tab); - if (tabIndex >= 0) - ui->tabWidget->setTabText(tabIndex, text); + m_annotation.setComments(ui->tabWidget->fetchComments()); + ui->rbTableView->setChecked(true); + ui->tabWidget->hide(); + ui->tableView->show(); + fillFields(); +} - if (text.isEmpty()) - ui->tabWidget->setTabText(tabIndex, - (defaultTabName + " " + QString::number(tabIndex+1))); +void GlobalAnnotationEditorDialog::acceptedClicked() +{ + updateAnnotation(); + emit GlobalAnnotationEditorDialog::acceptedDialog(); } void GlobalAnnotationEditorDialog::fillFields() { - setupComments(); + ui->tabWidget->setupComments(m_annotation.comments()); + ui->tableView->setupComments(m_annotation.comments()); } -void GlobalAnnotationEditorDialog::setupComments() +void GlobalAnnotationEditorDialog::updateAnnotation() { - ui->tabWidget->setUpdatesEnabled(false); - - deleteAllTabs(); - - const QVector<Comment> comments = m_annotation.comments(); - - if (comments.isEmpty()) - addComment(Comment()); - - for (const Comment &comment : comments) { - addCommentTab(comment); + Annotation annotation; + switch (viewMode()) { + case TabsView: + annotation.setComments(ui->tabWidget->fetchComments()); + break; + case TableView: + annotation.setComments(ui->tableView->fetchComments()); + break; } - ui->tabWidget->setUpdatesEnabled(true); + m_annotation = annotation; + + if (m_statusIsActive) + m_globalStatus.setStatus(ui->statusComboBox->currentIndex()); } void GlobalAnnotationEditorDialog::addComment(const Comment &comment) { m_annotation.addComment(comment); - addCommentTab(comment); + ui->tabWidget->addCommentTab(comment); } void GlobalAnnotationEditorDialog::removeComment(int index) { if ((m_annotation.commentsSize() > index) && (index >= 0)) { m_annotation.removeComment(index); - removeCommentTab(index); - } -} - -void GlobalAnnotationEditorDialog::addCommentTab(const Comment &comment) -{ - auto commentTab = new AnnotationCommentTab(); - commentTab->setComment(comment); - - QString tabTitle(comment.title()); - int tabIndex = ui->tabWidget->addTab(commentTab, tabTitle); - ui->tabWidget->setCurrentIndex(tabIndex); - - if (tabTitle.isEmpty()) { - const QString appendix = ((tabIndex > 0) ? QString::number(tabIndex+1) : ""); - - tabTitle = QString("%1 %2").arg(defaultTabName).arg(appendix); - - ui->tabWidget->setTabText(tabIndex, tabTitle); - } - - connect(commentTab, &AnnotationCommentTab::titleChanged, - this, &GlobalAnnotationEditorDialog::commentTitleChanged); -} - -void GlobalAnnotationEditorDialog::removeCommentTab(int index) -{ - if ((ui->tabWidget->count() > index) && (index >= 0)) { ui->tabWidget->removeTab(index); } } -void GlobalAnnotationEditorDialog::deleteAllTabs() -{ - while (ui->tabWidget->count() > 0) { - QWidget *w = ui->tabWidget->widget(0); - ui->tabWidget->removeTab(0); - delete w; - } -} - void GlobalAnnotationEditorDialog::setStatusVisibility(bool hasStatus) { ui->statusAddButton->setVisible(!hasStatus); @@ -260,9 +176,4 @@ void GlobalAnnotationEditorDialog::setStatusVisibility(bool hasStatus) m_statusIsActive = hasStatus; } -void GlobalAnnotationEditorDialog::tabChanged(int index) -{ - (void) index; -} - } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h index 5688c54ecf..2f4c942809 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h @@ -25,9 +25,7 @@ #pragma once -#include <QDialog> - -#include "annotation.h" +#include "annotationeditordialog.h" namespace QmlDesigner { @@ -35,46 +33,46 @@ namespace Ui { class GlobalAnnotationEditorDialog; } -class GlobalAnnotationEditorDialog : public QDialog +class GlobalAnnotationEditorDialog : public BasicAnnotationEditorDialog { Q_OBJECT - public: - explicit GlobalAnnotationEditorDialog(QWidget *parent, const Annotation &annotation, GlobalAnnotationStatus status); + enum ViewMode { + TableView, + TabsView + }; + + explicit GlobalAnnotationEditorDialog( + QWidget *parent = nullptr, GlobalAnnotationStatus status = GlobalAnnotationStatus::NoStatus); ~GlobalAnnotationEditorDialog(); - void setAnnotation(const Annotation &annotation); - Annotation annotation() const; + ViewMode viewMode() const; void setStatus(GlobalAnnotationStatus status); GlobalAnnotationStatus globalStatus() const; -signals: - void acceptedDialog(); //use instead of QDialog::accepted +public slots: + void showStatusContainer(bool show); + void switchToTabView(); + void switchToTableView(); private slots: - void acceptedClicked(); - void tabChanged(int index); - void commentTitleChanged(const QString &text, QWidget *tab); + void acceptedClicked() override; private: - void fillFields(); - void setupComments(); + + void fillFields() override; + void updateAnnotation(); void addComment(const Comment &comment); void removeComment(int index); - void addCommentTab(const Comment &comment); - void removeCommentTab(int index); - void deleteAllTabs(); - void setStatusVisibility(bool hasStatus); private: const QString globalEditorTitle = {tr("Global Annotation Editor")}; - const QString defaultTabName = {tr("Annotation")}; + Ui::GlobalAnnotationEditorDialog *ui; - Annotation m_annotation; GlobalAnnotationStatus m_globalStatus; bool m_statusIsActive; }; diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui index bc0f3efdca..75d99d26e0 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui @@ -74,6 +74,23 @@ </widget> </item> <item> + <widget class="QRadioButton" name="rbTabView"> + <property name="text"> + <string>Tab View</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rbTableView"> + <property name="text"> + <string>Table View</string> + </property> + </widget> + </item> + <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -90,7 +107,7 @@ </widget> </item> <item> - <widget class="QTabWidget" name="tabWidget"> + <widget class="AnnotationTabWidget" name="tabWidget"> <property name="currentIndex"> <number>0</number> </property> @@ -110,6 +127,9 @@ </widget> </item> <item> + <widget class="AnnotationTableView" name="tableView"/> + </item> + <item> <widget class="QDialogButtonBox" name="buttonBox"> <property name="focusPolicy"> <enum>Qt::StrongFocus</enum> @@ -124,6 +144,19 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>AnnotationTabWidget</class> + <extends>QTabWidget</extends> + <header>annotationtabwidget.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>AnnotationTableView</class> + <extends>QTableView</extends> + <header>annotationtableview.h</header> + </customwidget> + </customwidgets> <tabstops> <tabstop>tabWidget</tabstop> </tabstops> diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp index 997c712af6..ff36174a4f 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp @@ -426,8 +426,8 @@ void FormEditorAnnotationIcon::createAnnotationEditor() m_annotationEditor = new AnnotationEditorDialog(Core::ICore::dialogParent(), m_modelNode.displayName(), - m_modelNode.customId(), - m_modelNode.annotation()); + m_modelNode.customId()); + m_annotationEditor->setAnnotation(m_modelNode.annotation()); connect(m_annotationEditor, &AnnotationEditorDialog::acceptedDialog, this, &FormEditorAnnotationIcon::annotationDialogAccepted); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 816c3d6573..cac16af404 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -730,6 +730,7 @@ Project { "annotationeditor/annotationcommenttab.ui", "annotationeditor/annotationeditor.cpp", "annotationeditor/annotationeditor.h", + "annotationeditor/annotationeditor.qrc", "annotationeditor/globalannotationeditor.cpp", "annotationeditor/globalannotationeditor.h", "annotationeditor/annotationeditordialog.cpp", @@ -738,6 +739,12 @@ Project { "annotationeditor/globalannotationeditordialog.cpp", "annotationeditor/globalannotationeditordialog.h", "annotationeditor/globalannotationeditordialog.ui", + "annotationeditor/defaultannotations.cpp", + "annotationeditor/defaultannotations.h", + "annotationeditor/annotationtableview.cpp", + "annotationeditor/annotationtableview.h", + "annotationeditor/annotationtabwidget.cpp", + "annotationeditor/annotationtabwidget.h", "bindingeditor/bindingeditor.cpp", "bindingeditor/bindingeditor.h", "bindingeditor/actioneditor.cpp", |