aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Winkelmann <michael.winkelmann@qt.io>2021-03-09 12:07:05 +0100
committerMichael Winkelmann <michael.winkelmann@qt.io>2021-03-25 13:48:31 +0000
commitbd9a61fa27bad34144a654b8363ae0667ddd98e1 (patch)
tree18d33e4a0f33fb50ab0af88024d26a3f6da02696
parent3f265c37c619ed0d3a984289b243ad1d99117eba (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>
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt4
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp55
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h15
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp4
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri8
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditor.qrc5
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp199
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h52
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui10
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp446
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationtableview.h170
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.cpp154
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.h59
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp181
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/defaultannotations.h80
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/defaultannotations.json36
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp3
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp227
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h40
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui35
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp4
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.qbs7
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",