forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -637,6 +637,10 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
globalannotationeditordialog.cpp globalannotationeditordialog.h globalannotationeditordialog.ui
|
globalannotationeditordialog.cpp globalannotationeditordialog.h globalannotationeditordialog.ui
|
||||||
annotationeditor.cpp annotationeditor.h
|
annotationeditor.cpp annotationeditor.h
|
||||||
globalannotationeditor.cpp globalannotationeditor.h
|
globalannotationeditor.cpp globalannotationeditor.h
|
||||||
|
defaultannotations.cpp defaultannotations.h
|
||||||
|
annotationtableview.cpp annotationtableview.h
|
||||||
|
annotationtabwidget.cpp annotationtabwidget.h
|
||||||
|
annotationeditor.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
|
|||||||
@@ -24,12 +24,12 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "annotationcommenttab.h"
|
#include "annotationcommenttab.h"
|
||||||
|
#include "defaultannotations.h"
|
||||||
#include "ui_annotationcommenttab.h"
|
#include "ui_annotationcommenttab.h"
|
||||||
|
|
||||||
#include "richtexteditor/richtexteditor.h"
|
#include "richtexteditor/richtexteditor.h"
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include "QStringListModel"
|
|
||||||
|
|
||||||
#include "projectexplorer/session.h"
|
#include "projectexplorer/session.h"
|
||||||
#include "projectexplorer/target.h"
|
#include "projectexplorer/target.h"
|
||||||
@@ -40,7 +40,7 @@ namespace QmlDesigner {
|
|||||||
|
|
||||||
AnnotationCommentTab::AnnotationCommentTab(QWidget *parent)
|
AnnotationCommentTab::AnnotationCommentTab(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, ui(new Ui::AnnotationCommentTab)
|
, ui(std::make_unique<Ui::AnnotationCommentTab>())
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@@ -57,33 +57,12 @@ AnnotationCommentTab::AnnotationCommentTab(QWidget *parent)
|
|||||||
|
|
||||||
ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor);
|
ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor);
|
||||||
|
|
||||||
ui->titleEdit->setModel(new QStringListModel{QStringList{"Description",
|
connect(ui->titleEdit, &QComboBox::currentTextChanged, this, [this](QString const &text) {
|
||||||
"Display Condition",
|
emit titleChanged(text, this);
|
||||||
"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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AnnotationCommentTab::~AnnotationCommentTab()
|
AnnotationCommentTab::~AnnotationCommentTab() {}
|
||||||
{
|
|
||||||
delete ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
Comment AnnotationCommentTab::currentComment() const
|
Comment AnnotationCommentTab::currentComment() const
|
||||||
{
|
{
|
||||||
@@ -91,6 +70,9 @@ Comment AnnotationCommentTab::currentComment() const
|
|||||||
|
|
||||||
result.setTitle(ui->titleEdit->currentText().trimmed());
|
result.setTitle(ui->titleEdit->currentText().trimmed());
|
||||||
result.setAuthor(ui->authorEdit->text().trimmed());
|
result.setAuthor(ui->authorEdit->text().trimmed());
|
||||||
|
if (defaultAnnotations() && !defaultAnnotations()->isRichText(result)) {
|
||||||
|
result.setText(m_editor->plainText().trimmed());
|
||||||
|
} else
|
||||||
result.setText(m_editor->richText().trimmed());
|
result.setText(m_editor->richText().trimmed());
|
||||||
|
|
||||||
if (m_comment.sameContent(result))
|
if (m_comment.sameContent(result))
|
||||||
@@ -129,9 +111,15 @@ void AnnotationCommentTab::resetComment()
|
|||||||
m_comment = currentComment();
|
m_comment = currentComment();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnotationCommentTab::commentTitleChanged(const QString &text)
|
DefaultAnnotationsModel *AnnotationCommentTab::defaultAnnotations() const
|
||||||
{
|
{
|
||||||
emit titleChanged(text, this);
|
return m_defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnnotationCommentTab::setDefaultAnnotations(DefaultAnnotationsModel *defaults)
|
||||||
|
{
|
||||||
|
m_defaults = defaults;
|
||||||
|
ui->titleEdit->setModel(m_defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AnnotationCommentTab::backupFile(const QString &filePath)
|
QString AnnotationCommentTab::backupFile(const QString &filePath)
|
||||||
@@ -153,10 +141,8 @@ QString AnnotationCommentTab::backupFile(const QString &filePath)
|
|||||||
if (!newFile.exists()) {
|
if (!newFile.exists()) {
|
||||||
QFile(oldFile.absoluteFilePath()).copy(newFile.absoluteFilePath());
|
QFile(oldFile.absoluteFilePath()).copy(newFile.absoluteFilePath());
|
||||||
break;
|
break;
|
||||||
} else if (compareFileChecksum(oldFile.absoluteFilePath(),
|
} else if (compareFileChecksum(oldFile.absoluteFilePath(), newFile.absoluteFilePath()) == 0)
|
||||||
newFile.absoluteFilePath()) == 0) {
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
newFile.setFile(imgDir, newName.arg(i));
|
newFile.setFile(imgDir, newName.arg(i));
|
||||||
}
|
}
|
||||||
@@ -166,10 +152,9 @@ QString AnnotationCommentTab::backupFile(const QString &filePath)
|
|||||||
|
|
||||||
void AnnotationCommentTab::ensureDir(const QDir &dir)
|
void AnnotationCommentTab::ensureDir(const QDir &dir)
|
||||||
{
|
{
|
||||||
if (!dir.exists()) {
|
if (!dir.exists())
|
||||||
dir.mkdir(".");
|
dir.mkdir(".");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int AnnotationCommentTab::compareFileChecksum(const QString &firstFile, const QString &secondFile)
|
int AnnotationCommentTab::compareFileChecksum(const QString &firstFile, const QString &secondFile)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,10 +25,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
#include "annotation.h"
|
#include "annotation.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QDir;
|
class QDir;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
@@ -40,6 +43,7 @@ class AnnotationCommentTab;
|
|||||||
}
|
}
|
||||||
|
|
||||||
class RichTextEditor;
|
class RichTextEditor;
|
||||||
|
class DefaultAnnotationsModel;
|
||||||
|
|
||||||
class AnnotationCommentTab : public QWidget
|
class AnnotationCommentTab : public QWidget
|
||||||
{
|
{
|
||||||
@@ -57,17 +61,18 @@ public:
|
|||||||
void resetUI();
|
void resetUI();
|
||||||
void resetComment();
|
void resetComment();
|
||||||
|
|
||||||
|
DefaultAnnotationsModel *defaultAnnotations() const;
|
||||||
|
void setDefaultAnnotations(DefaultAnnotationsModel *);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void titleChanged(const QString &text, QWidget *widget);
|
void titleChanged(const QString &text, QWidget *widget);
|
||||||
|
|
||||||
private slots:
|
|
||||||
void commentTitleChanged(const QString &text);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::AnnotationCommentTab *ui;
|
std::unique_ptr<Ui::AnnotationCommentTab> ui;
|
||||||
RichTextEditor *m_editor;
|
RichTextEditor *m_editor;
|
||||||
|
|
||||||
Comment m_comment;
|
Comment m_comment;
|
||||||
|
QPointer<DefaultAnnotationsModel> m_defaults;
|
||||||
|
|
||||||
QString backupFile(const QString &filePath);
|
QString backupFile(const QString &filePath);
|
||||||
void ensureDir(const QDir &dir);
|
void ensureDir(const QDir &dir);
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ void AnnotationEditor::showWidget()
|
|||||||
{
|
{
|
||||||
m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(),
|
m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(),
|
||||||
m_modelNode.id(),
|
m_modelNode.id(),
|
||||||
m_modelNode.customId(),
|
m_modelNode.customId());
|
||||||
m_modelNode.annotation());
|
m_dialog->setAnnotation(m_modelNode.annotation());
|
||||||
|
|
||||||
QObject::connect(m_dialog, &AnnotationEditorDialog::acceptedDialog,
|
QObject::connect(m_dialog, &AnnotationEditorDialog::acceptedDialog,
|
||||||
this, &AnnotationEditor::acceptedClicked);
|
this, &AnnotationEditor::acceptedClicked);
|
||||||
|
|||||||
@@ -3,13 +3,21 @@ HEADERS += $$PWD/annotationeditordialog.h
|
|||||||
HEADERS += $$PWD/annotationeditor.h
|
HEADERS += $$PWD/annotationeditor.h
|
||||||
HEADERS += $$PWD/globalannotationeditor.h
|
HEADERS += $$PWD/globalannotationeditor.h
|
||||||
HEADERS += $$PWD/globalannotationeditordialog.h
|
HEADERS += $$PWD/globalannotationeditordialog.h
|
||||||
|
HEADERS += $$PWD/defaultannotations.h
|
||||||
|
HEADERS += $$PWD/annotationtableview.h
|
||||||
|
HEADERS += $$PWD/annotationtabwidget.h
|
||||||
|
|
||||||
SOURCES += $$PWD/annotationcommenttab.cpp
|
SOURCES += $$PWD/annotationcommenttab.cpp
|
||||||
SOURCES += $$PWD/annotationeditordialog.cpp
|
SOURCES += $$PWD/annotationeditordialog.cpp
|
||||||
SOURCES += $$PWD/annotationeditor.cpp
|
SOURCES += $$PWD/annotationeditor.cpp
|
||||||
SOURCES += $$PWD/globalannotationeditor.cpp
|
SOURCES += $$PWD/globalannotationeditor.cpp
|
||||||
SOURCES += $$PWD/globalannotationeditordialog.cpp
|
SOURCES += $$PWD/globalannotationeditordialog.cpp
|
||||||
|
SOURCES += $$PWD/defaultannotations.cpp
|
||||||
|
SOURCES += $$PWD/annotationtableview.cpp
|
||||||
|
SOURCES += $$PWD/annotationtabwidget.cpp
|
||||||
|
|
||||||
FORMS += $$PWD/annotationcommenttab.ui
|
FORMS += $$PWD/annotationcommenttab.ui
|
||||||
FORMS += $$PWD/annotationeditordialog.ui
|
FORMS += $$PWD/annotationeditordialog.ui
|
||||||
FORMS += $$PWD/globalannotationeditordialog.ui
|
FORMS += $$PWD/globalannotationeditordialog.ui
|
||||||
|
|
||||||
|
RESOURCES += $$PWD/annotationeditor.qrc
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/annotationeditor">
|
||||||
|
<file>defaultannotations.json</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
@@ -24,80 +24,65 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "annotationeditordialog.h"
|
#include "annotationeditordialog.h"
|
||||||
#include "ui_annotationeditordialog.h"
|
|
||||||
#include "annotation.h"
|
#include "annotation.h"
|
||||||
#include "annotationcommenttab.h"
|
#include "annotationcommenttab.h"
|
||||||
|
#include "defaultannotations.h"
|
||||||
|
|
||||||
#include "ui_annotationcommenttab.h"
|
#include "ui_annotationeditordialog.h"
|
||||||
|
|
||||||
#include <timelineicons.h>
|
#include <timelineicons.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QToolBar>
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QToolBar>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
BasicAnnotationEditorDialog::BasicAnnotationEditorDialog(QWidget *parent)
|
||||||
AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation)
|
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, ui(new Ui::AnnotationEditorDialog)
|
, m_defaults(std::make_unique<DefaultAnnotationsModel>())
|
||||||
, m_customId(customId)
|
|
||||||
, m_annotation(annotation)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
|
||||||
|
|
||||||
setWindowFlag(Qt::Tool, true);
|
setWindowFlag(Qt::Tool, true);
|
||||||
setModal(true);
|
setModal(true);
|
||||||
|
loadDefaultAnnotations(DefaultAnnotationsModel::defaultJsonFilePath());
|
||||||
|
|
||||||
connect(this, &QDialog::accepted, this, &AnnotationEditorDialog::acceptedClicked);
|
connect(this, &QDialog::accepted, this, &BasicAnnotationEditorDialog::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();
|
BasicAnnotationEditorDialog::~BasicAnnotationEditorDialog() {}
|
||||||
QString currentTitle = ui->tabWidget->tabText(currentIndex);
|
|
||||||
|
|
||||||
QMessageBox *deleteDialog = new QMessageBox(this);
|
Annotation const &BasicAnnotationEditorDialog::annotation() const
|
||||||
deleteDialog->setWindowTitle(currentTitle);
|
{
|
||||||
deleteDialog->setText(tr("Delete this comment?"));
|
return m_annotation;
|
||||||
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
|
void BasicAnnotationEditorDialog::setAnnotation(const Annotation &annotation)
|
||||||
addComment(Comment());
|
{
|
||||||
});
|
m_annotation = annotation;
|
||||||
|
fillFields();
|
||||||
|
}
|
||||||
|
|
||||||
commentCornerWidget->addAction(commentAddAction);
|
void BasicAnnotationEditorDialog::loadDefaultAnnotations(QString const &filename)
|
||||||
commentCornerWidget->addAction(commentRemoveAction);
|
{
|
||||||
|
m_defaults->loadFromFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner);
|
DefaultAnnotationsModel *BasicAnnotationEditorDialog::defaultAnnotations() const
|
||||||
|
{
|
||||||
|
return m_defaults.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
ui->targetIdEdit->setText(targetId);
|
||||||
|
|
||||||
fillFields();
|
|
||||||
setWindowTitle(annotationEditorTitle);
|
setWindowTitle(annotationEditorTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,17 +91,6 @@ AnnotationEditorDialog::~AnnotationEditorDialog()
|
|||||||
delete ui;
|
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)
|
void AnnotationEditorDialog::setCustomId(const QString &customId)
|
||||||
{
|
{
|
||||||
m_customId = customId;
|
m_customId = customId;
|
||||||
@@ -130,117 +104,34 @@ QString AnnotationEditorDialog::customId() const
|
|||||||
|
|
||||||
void AnnotationEditorDialog::acceptedClicked()
|
void AnnotationEditorDialog::acceptedClicked()
|
||||||
{
|
{
|
||||||
m_customId = ui->customIdEdit->text();
|
updateAnnotation();
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
emit AnnotationEditorDialog::acceptedDialog();
|
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()
|
void AnnotationEditorDialog::fillFields()
|
||||||
{
|
{
|
||||||
ui->customIdEdit->setText(m_customId);
|
ui->customIdEdit->setText(m_customId);
|
||||||
setupComments();
|
ui->tabWidget->setupComments(m_annotation.comments());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnotationEditorDialog::setupComments()
|
void AnnotationEditorDialog::updateAnnotation()
|
||||||
{
|
{
|
||||||
ui->tabWidget->setUpdatesEnabled(false);
|
m_customId = ui->customIdEdit->text();
|
||||||
|
Annotation annotation;
|
||||||
deleteAllTabs();
|
annotation.setComments(ui->tabWidget->fetchComments());
|
||||||
|
m_annotation = annotation;
|
||||||
const QVector<Comment> comments = m_annotation.comments();
|
|
||||||
|
|
||||||
if (comments.isEmpty())
|
|
||||||
addComment(Comment());
|
|
||||||
|
|
||||||
for (const Comment &comment : comments) {
|
|
||||||
addCommentTab(comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->tabWidget->setUpdatesEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnotationEditorDialog::addComment(const Comment &comment)
|
void AnnotationEditorDialog::addComment(const Comment &comment)
|
||||||
{
|
{
|
||||||
m_annotation.addComment(comment);
|
m_annotation.addComment(comment);
|
||||||
addCommentTab(comment);
|
ui->tabWidget->addCommentTab(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnotationEditorDialog::removeComment(int index)
|
void AnnotationEditorDialog::removeComment(int index)
|
||||||
{
|
{
|
||||||
if ((m_annotation.commentsSize() > index) && (index >= 0)) {
|
|
||||||
m_annotation.removeComment(index);
|
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);
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
} //namespace QmlDesigner
|
} //namespace QmlDesigner
|
||||||
|
|||||||
@@ -34,46 +34,62 @@ namespace QmlDesigner {
|
|||||||
namespace Ui {
|
namespace Ui {
|
||||||
class AnnotationEditorDialog;
|
class AnnotationEditorDialog;
|
||||||
}
|
}
|
||||||
|
class DefaultAnnotationsModel;
|
||||||
|
|
||||||
class AnnotationEditorDialog : public QDialog
|
class BasicAnnotationEditorDialog : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation);
|
explicit BasicAnnotationEditorDialog(QWidget *parent);
|
||||||
~AnnotationEditorDialog();
|
~BasicAnnotationEditorDialog();
|
||||||
|
|
||||||
|
Annotation const &annotation() const;
|
||||||
void setAnnotation(const Annotation &annotation);
|
void setAnnotation(const Annotation &annotation);
|
||||||
Annotation annotation() const;
|
|
||||||
|
|
||||||
void setCustomId(const QString &customId);
|
void loadDefaultAnnotations(QString const &filename);
|
||||||
QString customId() const;
|
|
||||||
|
DefaultAnnotationsModel *defaultAnnotations() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void acceptedDialog(); //use instead of QDialog::accepted
|
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:
|
private slots:
|
||||||
void acceptedClicked();
|
void acceptedClicked() override;
|
||||||
void tabChanged(int index);
|
|
||||||
void commentTitleChanged(const QString &text, QWidget *tab);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillFields();
|
void fillFields() override;
|
||||||
void setupComments();
|
void updateAnnotation();
|
||||||
|
|
||||||
void addComment(const Comment &comment);
|
void addComment(const Comment &comment);
|
||||||
void removeComment(int index);
|
void removeComment(int index);
|
||||||
|
|
||||||
void addCommentTab(const Comment &comment);
|
|
||||||
void removeCommentTab(int index);
|
|
||||||
void deleteAllTabs();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString annotationEditorTitle = {tr("Annotation Editor")};
|
const QString annotationEditorTitle = {tr("Annotation Editor")};
|
||||||
const QString defaultTabName = {tr("Annotation")};
|
|
||||||
Ui::AnnotationEditorDialog *ui;
|
Ui::AnnotationEditorDialog *ui;
|
||||||
|
|
||||||
QString m_customId;
|
QString m_customId;
|
||||||
Annotation m_annotation;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} //namespace QmlDesigner
|
} //namespace QmlDesigner
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="AnnotationTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
@@ -90,6 +90,14 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>AnnotationTabWidget</class>
|
||||||
|
<extends>QTabWidget</extends>
|
||||||
|
<header>annotationtabwidget.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>targetIdEdit</tabstop>
|
<tabstop>targetIdEdit</tabstop>
|
||||||
<tabstop>customIdEdit</tabstop>
|
<tabstop>customIdEdit</tabstop>
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
@@ -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": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,8 +50,8 @@ GlobalAnnotationEditor::~GlobalAnnotationEditor()
|
|||||||
void GlobalAnnotationEditor::showWidget()
|
void GlobalAnnotationEditor::showWidget()
|
||||||
{
|
{
|
||||||
m_dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(),
|
m_dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(),
|
||||||
modelNode().globalAnnotation(),
|
|
||||||
modelNode().globalStatus());
|
modelNode().globalStatus());
|
||||||
|
m_dialog->setAnnotation(modelNode().globalAnnotation());
|
||||||
|
|
||||||
QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::acceptedDialog,
|
QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::acceptedDialog,
|
||||||
this, &GlobalAnnotationEditor::acceptedClicked);
|
this, &GlobalAnnotationEditor::acceptedClicked);
|
||||||
@@ -142,7 +142,6 @@ void GlobalAnnotationEditor::acceptedClicked()
|
|||||||
hideWidget();
|
hideWidget();
|
||||||
|
|
||||||
emit accepted();
|
emit accepted();
|
||||||
|
|
||||||
emit annotationChanged();
|
emit annotationChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,87 +24,55 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "globalannotationeditordialog.h"
|
#include "globalannotationeditordialog.h"
|
||||||
#include "ui_globalannotationeditordialog.h"
|
|
||||||
#include "annotation.h"
|
#include "annotation.h"
|
||||||
#include "annotationcommenttab.h"
|
#include "annotationcommenttab.h"
|
||||||
|
#include "ui_globalannotationeditordialog.h"
|
||||||
#include "ui_annotationcommenttab.h"
|
|
||||||
|
|
||||||
#include <timelineicons.h>
|
#include <timelineicons.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QToolBar>
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QToolBar>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
GlobalAnnotationEditorDialog::GlobalAnnotationEditorDialog(QWidget *parent, const Annotation &annotation, GlobalAnnotationStatus status)
|
GlobalAnnotationEditorDialog::GlobalAnnotationEditorDialog(QWidget *parent,
|
||||||
: QDialog(parent)
|
GlobalAnnotationStatus status)
|
||||||
|
: BasicAnnotationEditorDialog(parent)
|
||||||
, ui(new Ui::GlobalAnnotationEditorDialog)
|
, ui(new Ui::GlobalAnnotationEditorDialog)
|
||||||
, m_annotation(annotation)
|
|
||||||
, m_globalStatus(status)
|
, m_globalStatus(status)
|
||||||
, m_statusIsActive(false)
|
, m_statusIsActive(false)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
ui->tabWidget->setDefaultAnnotations(defaultAnnotations());
|
||||||
|
ui->tableView->setDefaultAnnotations(defaultAnnotations());
|
||||||
|
|
||||||
setWindowFlag(Qt::Tool, true);
|
connect(ui->tableView,
|
||||||
setModal(true);
|
&AnnotationTableView::richTextEditorRequested,
|
||||||
|
this,
|
||||||
connect(this, &QDialog::accepted, this, &GlobalAnnotationEditorDialog::acceptedClicked);
|
[&](int index, QString const &) {
|
||||||
|
switchToTabView();
|
||||||
connect(ui->tabWidget, &QTabWidget::currentChanged, this, &GlobalAnnotationEditorDialog::tabChanged);
|
ui->tabWidget->setCurrentIndex(index);
|
||||||
|
|
||||||
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]() {
|
connect(ui->statusAddButton, &QPushButton::clicked, this, [&](bool) {
|
||||||
|
|
||||||
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){
|
|
||||||
setStatusVisibility(true);
|
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);
|
setWindowTitle(globalEditorTitle);
|
||||||
|
switchToTabView();
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalAnnotationEditorDialog::~GlobalAnnotationEditorDialog()
|
GlobalAnnotationEditorDialog::~GlobalAnnotationEditorDialog()
|
||||||
@@ -112,26 +80,18 @@ GlobalAnnotationEditorDialog::~GlobalAnnotationEditorDialog()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalAnnotationEditorDialog::setAnnotation(const Annotation &annotation)
|
GlobalAnnotationEditorDialog::ViewMode GlobalAnnotationEditorDialog::viewMode() const
|
||||||
{
|
{
|
||||||
m_annotation = annotation;
|
return ui->rbTableView->isChecked() ? TableView : TabsView;
|
||||||
fillFields();
|
|
||||||
}
|
|
||||||
|
|
||||||
Annotation GlobalAnnotationEditorDialog::annotation() const
|
|
||||||
{
|
|
||||||
return m_annotation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalAnnotationEditorDialog::setStatus(GlobalAnnotationStatus status)
|
void GlobalAnnotationEditorDialog::setStatus(GlobalAnnotationStatus status)
|
||||||
{
|
{
|
||||||
m_globalStatus = 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()));
|
ui->statusComboBox->setCurrentIndex(int(status.status()));
|
||||||
}
|
|
||||||
|
|
||||||
setStatusVisibility(hasStatus);
|
setStatusVisibility(hasStatus);
|
||||||
}
|
}
|
||||||
@@ -141,117 +101,73 @@ GlobalAnnotationStatus GlobalAnnotationEditorDialog::globalStatus() const
|
|||||||
return m_globalStatus;
|
return m_globalStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::showStatusContainer(bool show)
|
||||||
|
{
|
||||||
|
ui->statusContainer->setVisible(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::switchToTabView()
|
||||||
|
{
|
||||||
|
m_annotation.setComments(ui->tableView->fetchComments());
|
||||||
|
ui->rbTabView->setChecked(true);
|
||||||
|
ui->tableView->hide();
|
||||||
|
ui->tabWidget->show();
|
||||||
|
fillFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::switchToTableView()
|
||||||
|
{
|
||||||
|
m_annotation.setComments(ui->tabWidget->fetchComments());
|
||||||
|
ui->rbTableView->setChecked(true);
|
||||||
|
ui->tabWidget->hide();
|
||||||
|
ui->tableView->show();
|
||||||
|
fillFields();
|
||||||
|
}
|
||||||
|
|
||||||
void GlobalAnnotationEditorDialog::acceptedClicked()
|
void GlobalAnnotationEditorDialog::acceptedClicked()
|
||||||
{
|
{
|
||||||
Annotation annotation;
|
updateAnnotation();
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
emit GlobalAnnotationEditorDialog::acceptedDialog();
|
emit GlobalAnnotationEditorDialog::acceptedDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalAnnotationEditorDialog::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 GlobalAnnotationEditorDialog::fillFields()
|
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);
|
Annotation annotation;
|
||||||
|
switch (viewMode()) {
|
||||||
deleteAllTabs();
|
case TabsView:
|
||||||
|
annotation.setComments(ui->tabWidget->fetchComments());
|
||||||
const QVector<Comment> comments = m_annotation.comments();
|
break;
|
||||||
|
case TableView:
|
||||||
if (comments.isEmpty())
|
annotation.setComments(ui->tableView->fetchComments());
|
||||||
addComment(Comment());
|
break;
|
||||||
|
|
||||||
for (const Comment &comment : comments) {
|
|
||||||
addCommentTab(comment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->setUpdatesEnabled(true);
|
m_annotation = annotation;
|
||||||
|
|
||||||
|
if (m_statusIsActive)
|
||||||
|
m_globalStatus.setStatus(ui->statusComboBox->currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalAnnotationEditorDialog::addComment(const Comment &comment)
|
void GlobalAnnotationEditorDialog::addComment(const Comment &comment)
|
||||||
{
|
{
|
||||||
m_annotation.addComment(comment);
|
m_annotation.addComment(comment);
|
||||||
addCommentTab(comment);
|
ui->tabWidget->addCommentTab(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalAnnotationEditorDialog::removeComment(int index)
|
void GlobalAnnotationEditorDialog::removeComment(int index)
|
||||||
{
|
{
|
||||||
if ((m_annotation.commentsSize() > index) && (index >= 0)) {
|
if ((m_annotation.commentsSize() > index) && (index >= 0)) {
|
||||||
m_annotation.removeComment(index);
|
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);
|
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)
|
void GlobalAnnotationEditorDialog::setStatusVisibility(bool hasStatus)
|
||||||
{
|
{
|
||||||
ui->statusAddButton->setVisible(!hasStatus);
|
ui->statusAddButton->setVisible(!hasStatus);
|
||||||
@@ -260,9 +176,4 @@ void GlobalAnnotationEditorDialog::setStatusVisibility(bool hasStatus)
|
|||||||
m_statusIsActive = hasStatus;
|
m_statusIsActive = hasStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalAnnotationEditorDialog::tabChanged(int index)
|
|
||||||
{
|
|
||||||
(void) index;
|
|
||||||
}
|
|
||||||
|
|
||||||
} //namespace QmlDesigner
|
} //namespace QmlDesigner
|
||||||
|
|||||||
@@ -25,9 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QDialog>
|
#include "annotationeditordialog.h"
|
||||||
|
|
||||||
#include "annotation.h"
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -35,46 +33,46 @@ namespace Ui {
|
|||||||
class GlobalAnnotationEditorDialog;
|
class GlobalAnnotationEditorDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GlobalAnnotationEditorDialog : public QDialog
|
class GlobalAnnotationEditorDialog : public BasicAnnotationEditorDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GlobalAnnotationEditorDialog(QWidget *parent, const Annotation &annotation, GlobalAnnotationStatus status);
|
enum ViewMode {
|
||||||
|
TableView,
|
||||||
|
TabsView
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit GlobalAnnotationEditorDialog(
|
||||||
|
QWidget *parent = nullptr, GlobalAnnotationStatus status = GlobalAnnotationStatus::NoStatus);
|
||||||
~GlobalAnnotationEditorDialog();
|
~GlobalAnnotationEditorDialog();
|
||||||
|
|
||||||
void setAnnotation(const Annotation &annotation);
|
ViewMode viewMode() const;
|
||||||
Annotation annotation() const;
|
|
||||||
|
|
||||||
void setStatus(GlobalAnnotationStatus status);
|
void setStatus(GlobalAnnotationStatus status);
|
||||||
GlobalAnnotationStatus globalStatus() const;
|
GlobalAnnotationStatus globalStatus() const;
|
||||||
|
|
||||||
signals:
|
public slots:
|
||||||
void acceptedDialog(); //use instead of QDialog::accepted
|
void showStatusContainer(bool show);
|
||||||
|
void switchToTabView();
|
||||||
|
void switchToTableView();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void acceptedClicked();
|
void acceptedClicked() override;
|
||||||
void tabChanged(int index);
|
|
||||||
void commentTitleChanged(const QString &text, QWidget *tab);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillFields();
|
|
||||||
void setupComments();
|
void fillFields() override;
|
||||||
|
void updateAnnotation();
|
||||||
void addComment(const Comment &comment);
|
void addComment(const Comment &comment);
|
||||||
void removeComment(int index);
|
void removeComment(int index);
|
||||||
|
|
||||||
void addCommentTab(const Comment &comment);
|
|
||||||
void removeCommentTab(int index);
|
|
||||||
void deleteAllTabs();
|
|
||||||
|
|
||||||
void setStatusVisibility(bool hasStatus);
|
void setStatusVisibility(bool hasStatus);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString globalEditorTitle = {tr("Global Annotation Editor")};
|
const QString globalEditorTitle = {tr("Global Annotation Editor")};
|
||||||
const QString defaultTabName = {tr("Annotation")};
|
|
||||||
Ui::GlobalAnnotationEditorDialog *ui;
|
Ui::GlobalAnnotationEditorDialog *ui;
|
||||||
|
|
||||||
Annotation m_annotation;
|
|
||||||
GlobalAnnotationStatus m_globalStatus;
|
GlobalAnnotationStatus m_globalStatus;
|
||||||
bool m_statusIsActive;
|
bool m_statusIsActive;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -73,6 +73,23 @@
|
|||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@@ -90,7 +107,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="AnnotationTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
@@ -109,6 +126,9 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="AnnotationTableView" name="tableView"/>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
@@ -124,6 +144,19 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</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>
|
<tabstops>
|
||||||
<tabstop>tabWidget</tabstop>
|
<tabstop>tabWidget</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
|
|||||||
@@ -426,8 +426,8 @@ void FormEditorAnnotationIcon::createAnnotationEditor()
|
|||||||
|
|
||||||
m_annotationEditor = new AnnotationEditorDialog(Core::ICore::dialogParent(),
|
m_annotationEditor = new AnnotationEditorDialog(Core::ICore::dialogParent(),
|
||||||
m_modelNode.displayName(),
|
m_modelNode.displayName(),
|
||||||
m_modelNode.customId(),
|
m_modelNode.customId());
|
||||||
m_modelNode.annotation());
|
m_annotationEditor->setAnnotation(m_modelNode.annotation());
|
||||||
|
|
||||||
connect(m_annotationEditor, &AnnotationEditorDialog::acceptedDialog,
|
connect(m_annotationEditor, &AnnotationEditorDialog::acceptedDialog,
|
||||||
this, &FormEditorAnnotationIcon::annotationDialogAccepted);
|
this, &FormEditorAnnotationIcon::annotationDialogAccepted);
|
||||||
|
|||||||
@@ -730,6 +730,7 @@ Project {
|
|||||||
"annotationeditor/annotationcommenttab.ui",
|
"annotationeditor/annotationcommenttab.ui",
|
||||||
"annotationeditor/annotationeditor.cpp",
|
"annotationeditor/annotationeditor.cpp",
|
||||||
"annotationeditor/annotationeditor.h",
|
"annotationeditor/annotationeditor.h",
|
||||||
|
"annotationeditor/annotationeditor.qrc",
|
||||||
"annotationeditor/globalannotationeditor.cpp",
|
"annotationeditor/globalannotationeditor.cpp",
|
||||||
"annotationeditor/globalannotationeditor.h",
|
"annotationeditor/globalannotationeditor.h",
|
||||||
"annotationeditor/annotationeditordialog.cpp",
|
"annotationeditor/annotationeditordialog.cpp",
|
||||||
@@ -738,6 +739,12 @@ Project {
|
|||||||
"annotationeditor/globalannotationeditordialog.cpp",
|
"annotationeditor/globalannotationeditordialog.cpp",
|
||||||
"annotationeditor/globalannotationeditordialog.h",
|
"annotationeditor/globalannotationeditordialog.h",
|
||||||
"annotationeditor/globalannotationeditordialog.ui",
|
"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.cpp",
|
||||||
"bindingeditor/bindingeditor.h",
|
"bindingeditor/bindingeditor.h",
|
||||||
"bindingeditor/actioneditor.cpp",
|
"bindingeditor/actioneditor.cpp",
|
||||||
|
|||||||
Reference in New Issue
Block a user