forked from qt-creator/qt-creator
QmlDesigner: Add listmodeleditor
Task-number: QDS-2294 Change-Id: I66cae3a0d4265ab112eaf6b04e3a5972d185ff43 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -386,6 +386,13 @@ extend_qtc_plugin(QmlDesigner
|
||||
texteditorwidget.cpp texteditorwidget.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX components/listmodeleditor
|
||||
SOURCES
|
||||
listmodeleditordialog.cpp listmodeleditordialog.h
|
||||
listmodeleditordialog.cpp listmodeleditormodel.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX designercore
|
||||
SOURCES
|
||||
|
@@ -181,6 +181,9 @@ const char addFlowActionToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
const char fitRootToScreenToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fit the root element inside the available space.");
|
||||
const char fitSelectionToScreenToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fit the selected elements inside the available space.");
|
||||
|
||||
const char editListModelDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Edit List Model...");
|
||||
|
||||
const int priorityFirst = 280;
|
||||
const int prioritySelectionCategory = 220;
|
||||
const int priorityQmlPreviewCategory = 200;
|
||||
|
@@ -41,10 +41,14 @@
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <viewmanager.h>
|
||||
|
||||
#include <listmodeleditor/listmodeleditordialog.h>
|
||||
#include <listmodeleditor/listmodeleditormodel.h>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QGraphicsLinearLayout>
|
||||
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/utilsicons.h>
|
||||
@@ -335,6 +339,64 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class EditListModelAction final : public ModelNodeContextMenuAction
|
||||
{
|
||||
public:
|
||||
EditListModelAction()
|
||||
: ModelNodeContextMenuAction("EditListModel",
|
||||
ComponentCoreConstants::editListModelDisplayName,
|
||||
{},
|
||||
ComponentCoreConstants::rootCategory,
|
||||
QKeySequence("Alt+e"),
|
||||
1001,
|
||||
&openDialog,
|
||||
&isListViewInBaseState,
|
||||
&isListViewInBaseState)
|
||||
{}
|
||||
|
||||
static bool isListViewInBaseState(const SelectionContext &selectionState)
|
||||
{
|
||||
return selectionState.isInBaseState() && selectionState.singleNodeIsSelected()
|
||||
&& selectionState.currentSingleSelectedNode().metaInfo().isSubclassOf(
|
||||
"QtQuick.ListView");
|
||||
}
|
||||
|
||||
bool isEnabled(const SelectionContext &) const override { return true; }
|
||||
|
||||
static ModelNode listModelNode(const ModelNode &listViewNode)
|
||||
{
|
||||
if (listViewNode.hasProperty("model")) {
|
||||
if (listViewNode.hasBindingProperty("model"))
|
||||
return listViewNode.bindingProperty("model").resolveToModelNode();
|
||||
else if (listViewNode.hasNodeProperty("model"))
|
||||
return listViewNode.nodeProperty("model").modelNode();
|
||||
}
|
||||
|
||||
ModelNode newModel = listViewNode.view()->createModelNode("QtQml.Models.ListModel", 2, 15);
|
||||
listViewNode.nodeProperty("mode").reparentHere(newModel);
|
||||
|
||||
return newModel;
|
||||
}
|
||||
|
||||
static void openDialog(const SelectionContext &selectionState)
|
||||
{
|
||||
ListModelEditorModel model;
|
||||
|
||||
ModelNode targetNode = selectionState.targetNode();
|
||||
if (!targetNode.isValid())
|
||||
targetNode = selectionState.currentSingleSelectedNode();
|
||||
if (!targetNode.isValid())
|
||||
return;
|
||||
|
||||
model.setListModel(listModelNode(targetNode));
|
||||
|
||||
ListModelEditorDialog dialog{Core::ICore::mainWindow()};
|
||||
dialog.setModel(&model);
|
||||
|
||||
dialog.exec();
|
||||
}
|
||||
};
|
||||
|
||||
bool flowOptionVisible(const SelectionContext &context)
|
||||
{
|
||||
return QmlFlowViewNode::isValidQmlFlowViewNode(context.rootNode());
|
||||
@@ -1217,6 +1279,8 @@ void DesignerActionManager::createDefaultDesignerActions()
|
||||
priorityGenericToolBar));
|
||||
|
||||
addDesignerAction(new ChangeStyleAction());
|
||||
|
||||
addDesignerAction(new EditListModelAction);
|
||||
}
|
||||
|
||||
void DesignerActionManager::createDefaultAddResourceHandler()
|
||||
|
@@ -0,0 +1,7 @@
|
||||
SOURCES += \
|
||||
$$PWD/listmodeleditordialog.cpp \
|
||||
$$PWD/listmodeleditormodel.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/listmodeleditordialog.h \
|
||||
$$PWD/listmodeleditormodel.h
|
@@ -0,0 +1,163 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "listmodeleditordialog.h"
|
||||
#include "listmodeleditormodel.h"
|
||||
|
||||
#include <theme.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/stylehelper.h>
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QInputDialog>
|
||||
#include <QKeyEvent>
|
||||
#include <QTableView>
|
||||
#include <QToolBar>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
namespace {
|
||||
QIcon getIcon(Theme::Icon icon)
|
||||
{
|
||||
const QString fontName = "qtds_propertyIconFont.ttf";
|
||||
|
||||
return Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(icon), 30, 30);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ListModelEditorDialog::ListModelEditorDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
resize((Core::ICore::mainWindow()->size() * 8) / 10);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
|
||||
QToolBar *toolBar = new QToolBar();
|
||||
toolBar->setIconSize({30, 30});
|
||||
mainLayout->addWidget(toolBar);
|
||||
m_tableView = new QTableView;
|
||||
mainLayout->addWidget(m_tableView);
|
||||
|
||||
m_addRowAction = toolBar->addAction(getIcon(Theme::Icon::addRowAfter), tr("Add Row"));
|
||||
m_removeRowsAction = toolBar->addAction(getIcon(Theme::Icon::deleteRow), tr("Remove Columns"));
|
||||
m_addColumnAction = toolBar->addAction(getIcon(Theme::Icon::addColumnAfter), tr("Add Column"));
|
||||
m_removeColumnsAction = toolBar->addAction(getIcon(Theme::Icon::deleteColumn),
|
||||
tr("Remove Columns"));
|
||||
}
|
||||
|
||||
ListModelEditorDialog::~ListModelEditorDialog() = default;
|
||||
|
||||
void ListModelEditorDialog::setModel(ListModelEditorModel *model)
|
||||
{
|
||||
m_model = model;
|
||||
|
||||
connect(m_addRowAction, &QAction::triggered, m_model, &ListModelEditorModel::addRow);
|
||||
connect(m_addColumnAction, &QAction::triggered, this, &ListModelEditorDialog::openColumnDialog);
|
||||
connect(m_removeRowsAction, &QAction::triggered, this, &ListModelEditorDialog::removeRows);
|
||||
connect(m_removeColumnsAction, &QAction::triggered, this, &ListModelEditorDialog::removeColumns);
|
||||
connect(m_tableView->horizontalHeader(),
|
||||
&QHeaderView::sectionDoubleClicked,
|
||||
this,
|
||||
&ListModelEditorDialog::changeHeader);
|
||||
|
||||
m_tableView->setModel(model);
|
||||
m_tableView->horizontalHeader()->setMinimumSectionSize(60);
|
||||
m_tableView->verticalHeader()->setMinimumSectionSize(25);
|
||||
m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
m_tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
}
|
||||
|
||||
void ListModelEditorDialog::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) {
|
||||
for (const QModelIndex index : m_tableView->selectionModel()->selectedIndexes())
|
||||
m_model->setData(index, QVariant(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
|
||||
void ListModelEditorDialog::openColumnDialog()
|
||||
{
|
||||
bool ok;
|
||||
QString columnName = QInputDialog::getText(
|
||||
this, tr("Add Property"), tr("Property Name:"), QLineEdit::Normal, "", &ok);
|
||||
if (ok && !columnName.isEmpty())
|
||||
m_model->addColumn(columnName);
|
||||
}
|
||||
|
||||
void ListModelEditorDialog::removeRows()
|
||||
{
|
||||
const QList<QModelIndex> indices = m_tableView->selectionModel()->selectedRows();
|
||||
std::vector<int> rows;
|
||||
rows.reserve(indices.size());
|
||||
|
||||
for (QModelIndex index : indices)
|
||||
rows.push_back(index.row());
|
||||
|
||||
std::sort(rows.begin(), rows.end());
|
||||
|
||||
rows.erase(std::unique(rows.begin(), rows.end()), rows.end());
|
||||
|
||||
std::reverse(rows.begin(), rows.end());
|
||||
|
||||
for (int row : rows)
|
||||
m_model->removeRow(row);
|
||||
}
|
||||
|
||||
void ListModelEditorDialog::removeColumns()
|
||||
{
|
||||
const QList<QModelIndex> indices = m_tableView->selectionModel()->selectedColumns();
|
||||
std::vector<int> columns;
|
||||
columns.reserve(indices.size());
|
||||
|
||||
for (QModelIndex index : indices)
|
||||
columns.push_back(index.column());
|
||||
|
||||
std::sort(columns.begin(), columns.end());
|
||||
|
||||
columns.erase(std::unique(columns.begin(), columns.end()), columns.end());
|
||||
|
||||
std::reverse(columns.begin(), columns.end());
|
||||
|
||||
for (int row : columns)
|
||||
m_model->removeColumn(row);
|
||||
}
|
||||
|
||||
void ListModelEditorDialog::changeHeader(int column)
|
||||
{
|
||||
const QString propertyName = QString::fromUtf8(m_model->propertyNames()[column]);
|
||||
|
||||
bool ok;
|
||||
QString newPropertyName = QInputDialog::getText(
|
||||
this, tr("Change Propertry"), tr("Column Name:"), QLineEdit::Normal, propertyName, &ok);
|
||||
|
||||
if (ok && !newPropertyName.isEmpty())
|
||||
m_model->renameColumn(column, newPropertyName);
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -25,14 +25,48 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <abstractview.h>
|
||||
#include <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAbstractItemModel;
|
||||
class QTableView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Ui {
|
||||
class ListModelEditorDialog;
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ListModelEditorView : public AbstractView
|
||||
class ListModelEditorModel;
|
||||
|
||||
class ListModelEditorDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ListModelEditorView();
|
||||
explicit ListModelEditorDialog(QWidget *parent = nullptr);
|
||||
~ListModelEditorDialog();
|
||||
|
||||
void setModel(ListModelEditorModel *model);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *) override;
|
||||
|
||||
private:
|
||||
void addRow();
|
||||
void openColumnDialog();
|
||||
void removeRows();
|
||||
void removeColumns();
|
||||
void changeHeader(int column);
|
||||
|
||||
private:
|
||||
ListModelEditorModel *m_model{};
|
||||
QAction *m_addRowAction{};
|
||||
QAction *m_removeRowsAction{};
|
||||
QAction *m_addColumnAction{};
|
||||
QAction *m_removeColumnsAction{};
|
||||
QTableView *m_tableView{};
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -25,11 +25,278 @@
|
||||
|
||||
#include "listmodeleditormodel.h"
|
||||
|
||||
#include <abstractview.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <variantproperty.h>
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
ListModelEditorModel::ListModelEditorModel()
|
||||
class ListModelItem : public QStandardItem
|
||||
{
|
||||
public:
|
||||
ListModelItem(ModelNode node, PropertyName propertyName)
|
||||
: node(std::move(node))
|
||||
, propertyName(propertyName)
|
||||
{
|
||||
setEditable(true);
|
||||
}
|
||||
|
||||
QVariant maybeConvertToNumber(const QVariant &value)
|
||||
{
|
||||
bool canConvert = false;
|
||||
double convertedValue = value.toDouble(&canConvert);
|
||||
if (canConvert) {
|
||||
return convertedValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
QVariant data(int role) const override
|
||||
{
|
||||
if (role == Qt::BackgroundColorRole && hasInvalidValue)
|
||||
return QColor{Qt::darkYellow};
|
||||
|
||||
return QStandardItem::data(role);
|
||||
}
|
||||
|
||||
void setData(const QVariant &value, int role) override
|
||||
{
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||
hasInvalidValue = !value.isValid();
|
||||
|
||||
if (role == Qt::EditRole) {
|
||||
const QVariant &convertedValue = maybeConvertToNumber(value);
|
||||
QStandardItem::setData(convertedValue, role);
|
||||
if (value.isValid())
|
||||
node.variantProperty(propertyName).setValue(convertedValue);
|
||||
else
|
||||
node.removeProperty(propertyName);
|
||||
} else {
|
||||
QStandardItem::setData(value, role);
|
||||
}
|
||||
}
|
||||
|
||||
void removeProperty() { node.removeProperty(propertyName); }
|
||||
|
||||
void renameProperty(const PropertyName &newPropertyName)
|
||||
{
|
||||
if (node.hasProperty(propertyName)) {
|
||||
node.removeProperty(propertyName);
|
||||
node.variantProperty(newPropertyName).setValue(data(Qt::EditRole));
|
||||
}
|
||||
propertyName = newPropertyName;
|
||||
}
|
||||
|
||||
public:
|
||||
ModelNode node;
|
||||
PropertyName propertyName;
|
||||
bool hasInvalidValue = false;
|
||||
};
|
||||
|
||||
namespace {
|
||||
QList<PropertyName> getPropertyNames(const ModelNode &listElementNode)
|
||||
{
|
||||
auto properties = listElementNode.variantProperties();
|
||||
|
||||
QList<PropertyName> names;
|
||||
names.reserve(properties.size());
|
||||
|
||||
for (const auto &property : properties)
|
||||
names.push_back(property.name());
|
||||
|
||||
std::sort(names.begin(), names.end());
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
QList<PropertyName> mergeProperyNames(const QList<PropertyName> &first,
|
||||
const QList<PropertyName> &second)
|
||||
{
|
||||
QList<PropertyName> merged;
|
||||
merged.reserve(first.size() + second.size());
|
||||
|
||||
std::set_union(first.begin(),
|
||||
first.end(),
|
||||
second.begin(),
|
||||
second.end(),
|
||||
std::back_inserter(merged));
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
std::unique_ptr<ListModelItem> createItem(const ModelNode &listElementNode,
|
||||
const PropertyName &propertyName)
|
||||
{
|
||||
auto item = std::make_unique<ListModelItem>(listElementNode, propertyName);
|
||||
|
||||
QVariant value = listElementNode.variantProperty(propertyName).value();
|
||||
|
||||
item->setData(value, Qt::DisplayRole);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
QList<QString> convertToStringList(const QList<PropertyName> &propertyNames)
|
||||
{
|
||||
QList<QString> names;
|
||||
names.reserve(propertyNames.size());
|
||||
|
||||
for (const auto &propertyName : propertyNames)
|
||||
names.push_back(QString::fromUtf8(propertyName));
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
QList<PropertyName> createProperyNames(const QList<ModelNode> &listElementNodes)
|
||||
{
|
||||
QList<PropertyName> propertyNames;
|
||||
propertyNames.reserve(10);
|
||||
|
||||
for (const ModelNode &listElementNode : listElementNodes)
|
||||
propertyNames = mergeProperyNames(getPropertyNames(listElementNode), propertyNames);
|
||||
|
||||
return propertyNames;
|
||||
}
|
||||
|
||||
QList<QStandardItem *> createColumnItems(const ModelNode &listModelNode,
|
||||
const PropertyName &propertyName)
|
||||
{
|
||||
QList<QStandardItem *> items;
|
||||
const auto listElementNodes = listModelNode.defaultNodeListProperty().toModelNodeList();
|
||||
|
||||
for (const ModelNode &listElementNode : listElementNodes)
|
||||
items.push_back(createItem(listElementNode, propertyName).release());
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
void renameProperties(const QStandardItemModel *model,
|
||||
int columnIndex,
|
||||
const PropertyName &newPropertyName)
|
||||
{
|
||||
for (int rowIndex = 0; rowIndex < model->rowCount(); ++rowIndex)
|
||||
static_cast<ListModelItem *>(model->item(rowIndex, columnIndex))->renameProperty(newPropertyName);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ListModelEditorModel::populateModel()
|
||||
{
|
||||
const auto listElementNodes = m_listModelNode.defaultNodeListProperty().toModelNodeList();
|
||||
|
||||
m_propertyNames = createProperyNames(listElementNodes);
|
||||
|
||||
setHorizontalHeaderLabels(convertToStringList(m_propertyNames));
|
||||
|
||||
createItems(listElementNodes);
|
||||
}
|
||||
|
||||
void ListModelEditorModel::createItems(const QList<ModelNode> &listElementNodes)
|
||||
{
|
||||
for (const ModelNode &listElementNode : listElementNodes)
|
||||
appendItems(listElementNode);
|
||||
}
|
||||
|
||||
void ListModelEditorModel::appendItems(const ModelNode &listElementNode)
|
||||
{
|
||||
QList<QStandardItem *> row;
|
||||
row.reserve(m_propertyNames.size());
|
||||
for (const PropertyName &propertyName : propertyNames())
|
||||
row.push_back(createItem(listElementNode, propertyName).release());
|
||||
|
||||
appendRow(row);
|
||||
}
|
||||
|
||||
void ListModelEditorModel::addRow()
|
||||
{
|
||||
auto newElement = m_listModelNode.view()->createModelNode("QtQml.Models.ListElement", 2, 15);
|
||||
m_listModelNode.defaultNodeListProperty().reparentHere(newElement);
|
||||
|
||||
appendItems(newElement);
|
||||
}
|
||||
|
||||
void ListModelEditorModel::addColumn(const QString &columnName)
|
||||
{
|
||||
PropertyName propertyName = columnName.toUtf8();
|
||||
|
||||
auto found = std::lower_bound(m_propertyNames.begin(), m_propertyNames.end(), propertyName);
|
||||
|
||||
if (found != m_propertyNames.end() && *found == columnName)
|
||||
return;
|
||||
|
||||
int newIndex = static_cast<int>(std::distance(m_propertyNames.begin(), found));
|
||||
|
||||
m_propertyNames.insert(found, propertyName);
|
||||
|
||||
insertColumn(newIndex, createColumnItems(m_listModelNode, propertyName));
|
||||
|
||||
setHorizontalHeaderItem(newIndex, new QStandardItem(columnName));
|
||||
}
|
||||
|
||||
bool ListModelEditorModel::setValue(int row, int column, QVariant value, Qt::ItemDataRole role)
|
||||
{
|
||||
QModelIndex index = createIndex(row, column, invisibleRootItem());
|
||||
bool success = setData(index, value, role);
|
||||
emit dataChanged(index, index);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void ListModelEditorModel::removeColumn(int column)
|
||||
{
|
||||
QList<QStandardItem *> columnItems = QStandardItemModel::takeColumn(column);
|
||||
m_propertyNames.removeAt(column);
|
||||
|
||||
for (QStandardItem *columnItem : columnItems) {
|
||||
static_cast<ListModelItem *>(columnItem)->removeProperty();
|
||||
delete columnItem;
|
||||
}
|
||||
}
|
||||
|
||||
void ListModelEditorModel::removeRow(int row)
|
||||
{
|
||||
QList<QStandardItem *> rowItems = QStandardItemModel::takeRow(row);
|
||||
|
||||
if (rowItems.size())
|
||||
static_cast<ListModelItem *>(rowItems.front())->node.destroy();
|
||||
|
||||
qDeleteAll(rowItems);
|
||||
}
|
||||
|
||||
void ListModelEditorModel::renameColumn(int oldColumn, const QString &newColumnName)
|
||||
{
|
||||
const PropertyName newPropertyName = newColumnName.toUtf8();
|
||||
|
||||
auto found = std::lower_bound(m_propertyNames.begin(), m_propertyNames.end(), newPropertyName);
|
||||
|
||||
if (found != m_propertyNames.end() && *found == newPropertyName)
|
||||
return;
|
||||
|
||||
int newColumn = static_cast<int>(std::distance(m_propertyNames.begin(), found));
|
||||
|
||||
if (oldColumn == newColumn) {
|
||||
*found = newPropertyName;
|
||||
renameProperties(this, newColumn, newPropertyName);
|
||||
} else if (newColumn < oldColumn) {
|
||||
m_propertyNames.insert(found, newPropertyName);
|
||||
m_propertyNames.erase(std::next(m_propertyNames.begin(), oldColumn + 1));
|
||||
insertColumn(newColumn, takeColumn(oldColumn));
|
||||
renameProperties(this, newColumn, newPropertyName);
|
||||
} else {
|
||||
m_propertyNames.insert(found, newPropertyName);
|
||||
m_propertyNames.erase(std::next(m_propertyNames.begin(), oldColumn));
|
||||
insertColumn(newColumn - 1, takeColumn(oldColumn));
|
||||
renameProperties(this, newColumn - 1, newPropertyName);
|
||||
}
|
||||
|
||||
setHorizontalHeaderLabels(convertToStringList(m_propertyNames));
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -25,14 +25,41 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <modelnode.h>
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ListModelEditorModel : public QStandardItemModel
|
||||
{
|
||||
|
||||
public:
|
||||
ListModelEditorModel();
|
||||
void setListModel(ModelNode node)
|
||||
{
|
||||
m_listModelNode = node;
|
||||
populateModel();
|
||||
}
|
||||
|
||||
void addRow();
|
||||
void addColumn(const QString &columnName);
|
||||
|
||||
const QList<QmlDesigner::PropertyName> &propertyNames() const { return m_propertyNames; }
|
||||
|
||||
bool setValue(int row, int column, QVariant value, Qt::ItemDataRole role = Qt::EditRole);
|
||||
|
||||
void removeColumn(int column);
|
||||
void removeRow(int row);
|
||||
void renameColumn(int column, const QString &newColumnName);
|
||||
|
||||
private:
|
||||
void populateModel();
|
||||
void createItems(const QList<ModelNode> &listElementNodes);
|
||||
void appendItems(const ModelNode &listElementNode);
|
||||
|
||||
private:
|
||||
ModelNode m_listModelNode;
|
||||
QList<QmlDesigner::PropertyName> m_propertyNames;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -1,35 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "listmodeleditorview.h"
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
ListModelEditorView::ListModelEditorView()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -91,9 +91,12 @@ public:
|
||||
ModelNode(const Internal::InternalNodePointer &internalNode, Model *model, const AbstractView *view);
|
||||
ModelNode(const ModelNode &modelNode, AbstractView *view);
|
||||
ModelNode(const ModelNode &other);
|
||||
ModelNode(ModelNode &&other);
|
||||
~ModelNode();
|
||||
|
||||
ModelNode& operator=(const ModelNode &other);
|
||||
ModelNode &operator=(const ModelNode &other);
|
||||
ModelNode &operator=(ModelNode &&other);
|
||||
|
||||
TypeName type() const;
|
||||
QString simplifiedTypeName() const;
|
||||
QString displayName() const;
|
||||
@@ -226,6 +229,15 @@ public:
|
||||
bool isSubclassOf(const TypeName &typeName, int majorVersion = -1, int minorVersion = -1) const;
|
||||
QIcon typeIcon() const;
|
||||
|
||||
friend void swap(ModelNode &first, ModelNode &second)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
swap(first.m_internalNode, second.m_internalNode);
|
||||
swap(first.m_model, second.m_model);
|
||||
swap(first.m_view, second.m_view);
|
||||
}
|
||||
|
||||
private: // functions
|
||||
Internal::InternalNodePointer internalNode() const;
|
||||
|
||||
|
@@ -93,7 +93,25 @@ ModelNode::ModelNode(const ModelNode &modelNode, AbstractView *view)
|
||||
m_model(modelNode.model()),
|
||||
m_view(view)
|
||||
{
|
||||
}
|
||||
|
||||
ModelNode::ModelNode(ModelNode &&other)
|
||||
: m_internalNode(std::move(other.m_internalNode))
|
||||
, m_model(std::move(other.m_model))
|
||||
, m_view(std::move(other.m_view))
|
||||
{
|
||||
other.m_model = {};
|
||||
other.m_view = {};
|
||||
}
|
||||
|
||||
ModelNode &ModelNode::operator=(ModelNode &&other)
|
||||
{
|
||||
ModelNode newNode;
|
||||
|
||||
swap(other, newNode);
|
||||
swap(*this, newNode);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief contructs a invalid model node
|
||||
@@ -103,7 +121,6 @@ ModelNode::ModelNode(const ModelNode &modelNode, AbstractView *view)
|
||||
ModelNode::ModelNode():
|
||||
m_internalNode(new InternalNode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ModelNode::ModelNode(const ModelNode &other) = default;
|
||||
|
@@ -33,7 +33,7 @@ include(components/bindingeditor/bindingeditor.pri)
|
||||
include(components/annotationeditor/annotationeditor.pri)
|
||||
include(components/richtexteditor/richtexteditor.pri)
|
||||
include(components/transitioneditor/transitioneditor.pri)
|
||||
|
||||
include(components/listmodeleditor/listmodeleditor.pri)
|
||||
|
||||
BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH)
|
||||
!isEmpty(BUILD_PUPPET_IN_CREATOR_BINPATH) {
|
||||
|
@@ -59,6 +59,7 @@ Project {
|
||||
"components/stateseditor",
|
||||
"components/texteditor",
|
||||
"components/timelineeditor",
|
||||
"compenents/listmodeleditor",
|
||||
])
|
||||
|
||||
Properties {
|
||||
@@ -843,6 +844,10 @@ Project {
|
||||
"timelineeditor/timelineview.h",
|
||||
"timelineeditor/timelinewidget.cpp",
|
||||
"timelineeditor/timelinewidget.h",
|
||||
"listmodeleditor/listmodeleditordialog.cpp ",
|
||||
"listmodeleditor/listmodeleditordialog.h ",
|
||||
"listmodeleditor/listmodeleditormodel.cpp ",
|
||||
"listmodeleditor/listmodeleditordialog.h ",
|
||||
"transitioneditor/transitioneditorview.cpp",
|
||||
"transitioneditor/transitioneditorview.h",
|
||||
"transitioneditor/transitioneditorwidget.cpp",
|
||||
|
@@ -14,14 +14,12 @@ SOURCES += \
|
||||
$$PWD/designercore/model/import.cpp \
|
||||
$$PWD/designercore/model/abstractproperty.cpp \
|
||||
$$PWD/designercore/model/abstractview.cpp \
|
||||
$$PWD/components/listmodeleditor/listmodeleditormodel.cpp \
|
||||
$$PWD/designercore/model/internalproperty.cpp \
|
||||
$$PWD/designercore/model/internalbindingproperty.cpp \
|
||||
$$PWD/designercore/model/internalnodeabstractproperty.cpp \
|
||||
$$PWD/designercore/model/internalnodelistproperty.cpp \
|
||||
$$PWD/designercore/model/internalnodeproperty.cpp \
|
||||
$$PWD/designercore/model/internalsignalhandlerproperty.cpp \
|
||||
$$PWD/designercore/model/internalproperty.cpp \
|
||||
$$PWD/designercore/model/internalnode.cpp \
|
||||
$$PWD/designercore/model/internalvariantproperty.cpp \
|
||||
$$PWD/designercore/model/bindingproperty.cpp \
|
||||
@@ -30,9 +28,9 @@ SOURCES += \
|
||||
$$PWD/designercore/model/nodeproperty.cpp \
|
||||
$$PWD/designercore/model/signalhandlerproperty.cpp \
|
||||
$$PWD/designercore/model/variantproperty.cpp\
|
||||
$$PWD/designercore/model/annotation.cpp\
|
||||
$$PWD/designercore/model/annotation.cpp \
|
||||
$$PWD/designercore/rewritertransaction.cpp
|
||||
$$PWD/designercore/rewritertransaction.cpp \
|
||||
$$PWD/components/listmodeleditor/listmodeleditormodel.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/designercore/include/modelnode.h \
|
||||
@@ -41,7 +39,6 @@ HEADERS += \
|
||||
$$PWD/designercore/include/import.h \
|
||||
$$PWD/designercore/include/abstractproperty.h \
|
||||
$$PWD/designercore/include/abstractview.h \
|
||||
$$PWD/components/listmodeleditor/listmodeleditormodel.h \
|
||||
$$PWD/designercore/model/model_p.h \
|
||||
$$PWD/designercore/include/qmldesignercorelib_global.h \
|
||||
$$PWD/designercore/model/internalbindingproperty.h \
|
||||
@@ -58,4 +55,5 @@ HEADERS += \
|
||||
$$PWD/designercore/include/nodeproperty.h \
|
||||
$$PWD/designercore/include/signalhandlerproperty.h \
|
||||
$$PWD/designercore/include/variantproperty.h \
|
||||
$$PWD/designercore/rewritertransaction.h
|
||||
$$PWD/designercore/rewritertransaction.h \
|
||||
$$PWD/components/listmodeleditor/listmodeleditormodel.h
|
||||
|
@@ -65,6 +65,8 @@ using testing::Property;
|
||||
using testing::Return;
|
||||
using testing::ReturnRef;
|
||||
using testing::SafeMatcherCast;
|
||||
using testing::SaveArg;
|
||||
using testing::SaveArgPointee;
|
||||
using testing::Sequence;
|
||||
using testing::SizeIs;
|
||||
using testing::StrEq;
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include <filepathview.h>
|
||||
#include <filestatus.h>
|
||||
#include <includesearchpath.h>
|
||||
#include <modelnode.h>
|
||||
#include <nativefilepath.h>
|
||||
#include <pchpaths.h>
|
||||
#include <pchtask.h>
|
||||
@@ -68,6 +69,7 @@
|
||||
#include <tooltipinfo.h>
|
||||
#include <usedmacro.h>
|
||||
#include <utils/link.h>
|
||||
#include <variantproperty.h>
|
||||
|
||||
#include <sqlite3ext.h>
|
||||
|
||||
@@ -1449,6 +1451,25 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag) {
|
||||
} // namespace Internal
|
||||
} // namespace ClangTools
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const ModelNode &node)
|
||||
{
|
||||
if (!node.isValid())
|
||||
return out << "(invalid)";
|
||||
|
||||
return out << "(" << node.id() << ")";
|
||||
}
|
||||
std::ostream &operator<<(std::ostream &out, const VariantProperty &property)
|
||||
{
|
||||
if (!property.isValid())
|
||||
return out << "(invalid)";
|
||||
|
||||
return out << "(" << property.parentModelNode() << ", " << property.name() << ", "
|
||||
<< property.value() << ")";
|
||||
}
|
||||
} // namespace QmlDesigner
|
||||
|
||||
void setFilePathCache(ClangBackEnd::FilePathCaching *cache)
|
||||
{
|
||||
filePathCache = cache;
|
||||
|
@@ -350,4 +350,12 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag);
|
||||
} // namespace Internal
|
||||
} // namespace CppTools
|
||||
|
||||
namespace QmlDesigner {
|
||||
class ModelNode;
|
||||
class VariantProperty;
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const ModelNode &node);
|
||||
std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
|
||||
} // namespace QmlDesigner
|
||||
|
||||
void setFilePathCache(ClangBackEnd::FilePathCaching *filePathCache);
|
||||
|
@@ -59,9 +59,11 @@ std::ostream &operator<<(std::ostream &out, const QVariant &variant)
|
||||
QString output;
|
||||
QDebug debug(&output);
|
||||
|
||||
debug << variant;
|
||||
debug.noquote().nospace() << variant;
|
||||
|
||||
return out << output;
|
||||
QByteArray utf8Text = output.toUtf8();
|
||||
|
||||
return out.write(utf8Text.data(), utf8Text.size());
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format)
|
||||
@@ -88,4 +90,14 @@ void PrintTo(const QString &text, std::ostream *os)
|
||||
*os << text;
|
||||
}
|
||||
|
||||
void PrintTo(const QVariant &variant, std::ostream *os)
|
||||
{
|
||||
*os << variant;
|
||||
}
|
||||
|
||||
void PrintTo(const QByteArray &text, std::ostream *os)
|
||||
{
|
||||
*os << text;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@@ -35,10 +35,12 @@ class QVariant;
|
||||
class QString;
|
||||
class QTextCharFormat;
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const QVariant &variant);
|
||||
std::ostream &operator<<(std::ostream &out, const QVariant &QVariant);
|
||||
std::ostream &operator<<(std::ostream &out, const QString &text);
|
||||
std::ostream &operator<<(std::ostream &out, const QByteArray &byteArray);
|
||||
std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format);
|
||||
|
||||
void PrintTo(const QString &text, std::ostream *os);
|
||||
void PrintTo(const QVariant &variant, std::ostream *os);
|
||||
void PrintTo(const QByteArray &text, std::ostream *os);
|
||||
QT_END_NAMESPACE
|
||||
|
@@ -27,21 +27,926 @@
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include "mocklistmodeleditorview.h"
|
||||
|
||||
#include <qmldesigner/components/listmodeleditor/listmodeleditormodel.h>
|
||||
#include <qmldesigner/components/listmodeleditor/listmodeleditorview.h>
|
||||
#include <qmldesigner/designercore/include/abstractview.h>
|
||||
#include <qmldesigner/designercore/include/model.h>
|
||||
#include <qmldesigner/designercore/include/nodelistproperty.h>
|
||||
#include <qmldesigner/designercore/include/variantproperty.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using QmlDesigner::AbstractProperty;
|
||||
using QmlDesigner::AbstractView;
|
||||
using QmlDesigner::ModelNode;
|
||||
|
||||
MATCHER_P2(HasItem,
|
||||
name,
|
||||
value,
|
||||
std::string(negation ? "hasn't " : "has ") + "(" + name + ", " + value + ")")
|
||||
{
|
||||
QStandardItem *item = arg;
|
||||
|
||||
return item->data(Qt::UserRole).toString() == name && item->data(Qt::UserRole).toDouble() == value;
|
||||
}
|
||||
|
||||
MATCHER(IsInvalid, std::string(negation ? "isn't null" : "is null"))
|
||||
{
|
||||
return !arg.isValid();
|
||||
}
|
||||
|
||||
MATCHER_P3(IsVariantProperty,
|
||||
node,
|
||||
name,
|
||||
value,
|
||||
std::string(negation ? "isn't " : "is ") + "(" + name + ", " + PrintToString(value) + ")")
|
||||
{
|
||||
const QmlDesigner::VariantProperty &property = arg;
|
||||
|
||||
return property.parentModelNode() == node && property.name() == name && property.value() == value;
|
||||
}
|
||||
|
||||
MATCHER_P2(IsVariantProperty,
|
||||
name,
|
||||
value,
|
||||
std::string(negation ? "isn't " : "is ") + "(" + name + ", " + PrintToString(value) + ")")
|
||||
{
|
||||
const QmlDesigner::VariantProperty &property = arg;
|
||||
|
||||
return property.name() == name && property.value() == value;
|
||||
}
|
||||
|
||||
MATCHER_P2(IsAbstractProperty, node, name, std::string(negation ? "isn't " : "is ") + "(" + name + ")")
|
||||
{
|
||||
const QmlDesigner::AbstractProperty &property = arg;
|
||||
|
||||
return property.parentModelNode() == node && property.name() == name;
|
||||
}
|
||||
|
||||
class ListModelEditor : public testing::Test
|
||||
{
|
||||
public:
|
||||
ListModelEditor() { designerModel->attachView(&view); }
|
||||
ListModelEditor()
|
||||
{
|
||||
designerModel->attachView(&mockView);
|
||||
|
||||
emptyListModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
|
||||
|
||||
listModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
|
||||
mockView.rootModelNode().defaultNodeListProperty().reparentHere(listModelNode);
|
||||
element1 = createElement({{"name", "foo"}, {"value", 1}, {"value2", 42}});
|
||||
element2 = createElement({{"value", 4}, {"name", "bar"}, {"image", "pic.png"}});
|
||||
element3 = createElement({{"image", "pic.png"}, {"name", "poo"}, {"value", 111}});
|
||||
}
|
||||
|
||||
using Entry = std::pair<QmlDesigner::PropertyName, QVariant>;
|
||||
|
||||
ModelNode createElement(std::initializer_list<Entry> entries)
|
||||
{
|
||||
auto element = mockView.createModelNode("QtQml.Models/ListElement", 2, 15);
|
||||
listModelNode.defaultNodeListProperty().reparentHere(element);
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
element.variantProperty(entry.first).setValue(entry.second);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
QList<QString> headerLabels(const QmlDesigner::ListModelEditorModel &model) const
|
||||
{
|
||||
QList<QString> labels;
|
||||
labels.reserve(model.columnCount());
|
||||
|
||||
for (int i = 0; i < model.columnCount(); ++i)
|
||||
labels.push_back(model.headerData(i, Qt::Horizontal).toString());
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
QList<QList<QVariant>> displayValues() const
|
||||
{
|
||||
QList<QList<QVariant>> rows;
|
||||
|
||||
for (int rowIndex = 0; rowIndex < model.rowCount(); ++rowIndex) {
|
||||
QList<QVariant> row;
|
||||
|
||||
for (int columnIndex = 0; columnIndex < model.columnCount(); ++columnIndex)
|
||||
row.push_back(model.data(model.index(rowIndex, columnIndex), Qt::DisplayRole));
|
||||
|
||||
rows.push_back(row);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
QList<QList<QColor>> backgroundColors() const
|
||||
{
|
||||
QList<QList<QColor>> rows;
|
||||
|
||||
for (int rowIndex = 0; rowIndex < model.rowCount(); ++rowIndex) {
|
||||
QList<QColor> row;
|
||||
|
||||
for (int columnIndex = 0; columnIndex < model.columnCount(); ++columnIndex)
|
||||
row.push_back(
|
||||
model.data(model.index(rowIndex, columnIndex), Qt::BackgroundColorRole)
|
||||
.value<QColor>());
|
||||
|
||||
rows.push_back(row);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
QList<QList<QmlDesigner::VariantProperty>> properties() const
|
||||
{
|
||||
QList<QList<QmlDesigner::VariantProperty>> properties;
|
||||
properties.reserve(10);
|
||||
|
||||
auto nodes = listModelNode.defaultNodeListProperty().toModelNodeList();
|
||||
|
||||
for (const ModelNode &node : nodes)
|
||||
properties.push_back(node.variantProperties());
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<QmlDesigner::Model> designerModel{QmlDesigner::Model::create("QtQuick.Item", 1, 1)};
|
||||
QmlDesigner::ListModelEditorView view;
|
||||
NiceMock<MockListModelEditorView> mockView;
|
||||
QmlDesigner::ListModelEditorModel model;
|
||||
ModelNode listModelNode;
|
||||
ModelNode emptyListModelNode;
|
||||
ModelNode element1;
|
||||
ModelNode element2;
|
||||
ModelNode element3;
|
||||
};
|
||||
|
||||
TEST_F(ListModelEditor, CreatePropertyNameSet)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("image", "name", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, CreatePropertyNameSetForEmptyList)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, HorizontalLabels)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("image", "name", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, HorizontalLabelsForEmptyList)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
|
||||
ASSERT_THAT(headerLabels(model), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, DisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ChangeValueChangesDisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(0, 1, "hello");
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "hello", 1, 42),
|
||||
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, EditValueCallVariantPropertiesChanged)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
EXPECT_CALL(mockView,
|
||||
variantPropertiesChanged(ElementsAre(IsVariantProperty(element1, "name", "hello")),
|
||||
Eq(AbstractView::NoAdditionalChanges)));
|
||||
|
||||
model.setValue(0, 1, "hello");
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ChangeDisplayValueCallsVariantPropertiesChanged)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
EXPECT_CALL(mockView,
|
||||
variantPropertiesChanged(ElementsAre(IsVariantProperty(element1, "name", "hello")),
|
||||
Eq(AbstractView::NoAdditionalChanges)))
|
||||
.Times(0);
|
||||
|
||||
model.setValue(0, 1, "hello", Qt::DisplayRole);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddRowAddedInvalidRow)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.addRow();
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid()),
|
||||
ElementsAre(IsInvalid(), IsInvalid(), IsInvalid(), IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddRowCreatesNewModelNodeAndReparents)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
EXPECT_CALL(mockView, nodeCreated(Property(&ModelNode::type, Eq("QtQml.Models.ListElement"))));
|
||||
EXPECT_CALL(mockView,
|
||||
nodeReparented(Property(&ModelNode::type, Eq("QtQml.Models.ListElement")),
|
||||
Property(&AbstractProperty::parentModelNode, Eq(listModelNode)),
|
||||
_,
|
||||
_));
|
||||
|
||||
model.addRow();
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ChangeAddedRowPropery)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
model.addRow();
|
||||
|
||||
model.setValue(3, 2, 22);
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid()),
|
||||
ElementsAre(IsInvalid(), IsInvalid(), 22, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ChangeAddedRowProperyCallsVariantPropertiesChanged)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
ModelNode element4;
|
||||
ON_CALL(mockView, nodeReparented(_, _, _, _)).WillByDefault(SaveArg<0>(&element4));
|
||||
model.addRow();
|
||||
|
||||
EXPECT_CALL(mockView,
|
||||
variantPropertiesChanged(ElementsAre(IsVariantProperty(element4, "value", 22)),
|
||||
Eq(AbstractView::PropertiesAdded)));
|
||||
|
||||
model.setValue(3, 2, 22);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddColumnInsertsPropertyName)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.addColumn("other");
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("image", "name", "other", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddColumnInsertsPropertyNameToEmptyModel)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
|
||||
model.addColumn("foo");
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("foo"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddTwiceColumnInsertsPropertyNameToEmptyModel)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
model.addColumn("foo");
|
||||
|
||||
model.addColumn("foo2");
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("foo", "foo2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddSameColumnInsertsPropertyName)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
model.addColumn("foo");
|
||||
|
||||
model.addColumn("foo");
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("foo"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddColumnInsertsHeaderLabel)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.addColumn("other");
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("image", "name", "other", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddColumnInsertsHeaderLabelToEmptyModel)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
|
||||
model.addColumn("foo");
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("foo"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddTwiceColumnInsertsHeaderLabelToEmptyModel)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
model.addColumn("foo");
|
||||
|
||||
model.addColumn("foo2");
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("foo", "foo2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddSameColumnInsertsHeaderLabel)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
model.addColumn("foo");
|
||||
|
||||
model.addColumn("foo");
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("foo"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, AddColumnInsertsDisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.addColumn("other");
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", IsInvalid(), 1, 42),
|
||||
ElementsAre("pic.png", "bar", IsInvalid(), 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", IsInvalid(), 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ChangeAddColumnPropertyDisplayValue)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
model.addColumn("other");
|
||||
|
||||
model.setValue(1, 2, 22);
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", IsInvalid(), 1, 42),
|
||||
ElementsAre("pic.png", "bar", 22, 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", IsInvalid(), 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ChangeAddColumnPropertyCallsVariantPropertiesChanged)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
model.addColumn("other");
|
||||
|
||||
EXPECT_CALL(mockView,
|
||||
variantPropertiesChanged(ElementsAre(IsVariantProperty(element2, "other", 434)), _));
|
||||
|
||||
model.setValue(1, 2, 434);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveColumnRemovesDisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.removeColumn(2);
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 42),
|
||||
ElementsAre("pic.png", "bar", IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveColumnRemovesProperties)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
EXPECT_CALL(mockView, propertiesRemoved(ElementsAre(IsAbstractProperty(element2, "image"))));
|
||||
EXPECT_CALL(mockView, propertiesRemoved(ElementsAre(IsAbstractProperty(element3, "image"))));
|
||||
|
||||
model.removeColumn(0);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveColumnRemovesPropertyName)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.removeColumn(1);
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("image", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveRowRemovesDisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.removeRow(1);
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveRowRemovesElementInListModel)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
EXPECT_CALL(mockView, nodeRemoved(Eq(element2), _, _));
|
||||
|
||||
model.removeRow(1);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ConvertStringFloatToFloat)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, "25.5");
|
||||
|
||||
ASSERT_THAT(element2.variantProperty("name").value().value<double>(), 25.5);
|
||||
ASSERT_THAT(element2.variantProperty("name").value().type(), QVariant::Double);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ConvertStringIntegerToDouble)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, "25");
|
||||
|
||||
ASSERT_THAT(element2.variantProperty("name").value().value<double>(), 25);
|
||||
ASSERT_THAT(element2.variantProperty("name").value().type(), QVariant::Double);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, DontConvertStringToNumber)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, "hello");
|
||||
|
||||
ASSERT_THAT(element2.variantProperty("name").value().value<QString>(), "hello");
|
||||
ASSERT_THAT(element2.variantProperty("name").value().type(), QVariant::String);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, EmptyStringsRemovesProperty)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, "");
|
||||
|
||||
ASSERT_THAT(element2.variantProperty("name").value().value<QString>(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, InvalidVariantRemovesProperty)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, QVariant());
|
||||
|
||||
ASSERT_FALSE(element2.hasProperty("name"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, DispayValueIsChangedToDouble)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, "25.5");
|
||||
|
||||
ASSERT_THAT(displayValues()[1][1].type(), QVariant::Double);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, StringDispayValueIsNotChanged)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, "25.5a");
|
||||
|
||||
ASSERT_THAT(displayValues()[1][1].type(), QVariant::String);
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, SetInvalidToDarkYellowBackgroundColor)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
ASSERT_THAT(
|
||||
backgroundColors(),
|
||||
ElementsAre(
|
||||
ElementsAre(Qt::darkYellow, Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow),
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, SettingValueChangesBackgroundColor)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(0, 0, "foo");
|
||||
|
||||
ASSERT_THAT(
|
||||
backgroundColors(),
|
||||
ElementsAre(
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow),
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, SettingValueChangesByDisplayRoleBackgroundColor)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(0, 0, "foo", Qt::DisplayRole);
|
||||
|
||||
ASSERT_THAT(
|
||||
backgroundColors(),
|
||||
ElementsAre(
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow),
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ResettingValueChangesBackgroundColor)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, QVariant{});
|
||||
|
||||
ASSERT_THAT(
|
||||
backgroundColors(),
|
||||
ElementsAre(
|
||||
ElementsAre(Qt::darkYellow, Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
|
||||
ElementsAre(Not(Qt::darkYellow), Qt::darkYellow, Not(Qt::darkYellow), Qt::darkYellow),
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ResettingValueChangesByDisplayRoleBackgroundColor)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(1, 1, QVariant{}, Qt::DisplayRole);
|
||||
|
||||
ASSERT_THAT(
|
||||
backgroundColors(),
|
||||
ElementsAre(
|
||||
ElementsAre(Qt::darkYellow, Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
|
||||
ElementsAre(Not(Qt::darkYellow), Qt::darkYellow, Not(Qt::darkYellow), Qt::darkYellow),
|
||||
ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, SettingNullValueChangesBackgroundColor)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.setValue(0, 0, 0);
|
||||
|
||||
ASSERT_THAT(backgroundColors(),
|
||||
ElementsAre(ElementsAre(_, _, _, _),
|
||||
ElementsAre(_, _, _, Qt::darkYellow),
|
||||
ElementsAre(_, _, _, Qt::darkYellow)));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, DontRenamePropertyIfColumnNameExists)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "value2");
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("image", "name", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, DontRenameColumnIfColumnNameExists)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "value2");
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("image", "name", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, DontRenameColumnIfColumnNameExistsDoesNotChangeDisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "value2");
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, DontRenameColumnIfColumnNameExistsDoesNotChangeProperties)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "value2");
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("name", "foo"),
|
||||
IsVariantProperty("value", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("name", "bar"),
|
||||
IsVariantProperty("value", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("name", "poo"),
|
||||
IsVariantProperty("value", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenamePropertyButDontChangeOrder)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "mood");
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("image", "mood", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameColumnButDontChangeOrder)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "mood");
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("image", "mood", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameColumnButDontChangeOrderDisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "mood");
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameColumnButDontChangeOrderProperies)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "mood");
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("mood", "foo"),
|
||||
IsVariantProperty("value", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("mood", "bar"),
|
||||
IsVariantProperty("value", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("mood", "poo"),
|
||||
IsVariantProperty("value", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveColumnAfterRenameColumn)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
model.renameColumn(1, "mood");
|
||||
|
||||
model.removeColumn(1);
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("value", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("value", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("value", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ChangeValueAfterRenameColumn)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
model.renameColumn(1, "mood");
|
||||
|
||||
model.setValue(1, 1, "taaa");
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("mood", "foo"),
|
||||
IsVariantProperty("value", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("mood", "taaa"),
|
||||
IsVariantProperty("value", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("mood", "poo"),
|
||||
IsVariantProperty("value", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemovePropertyAfterRenameColumn)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
model.renameColumn(1, "mood");
|
||||
|
||||
model.setValue(1, 1, {});
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("mood", "foo"),
|
||||
IsVariantProperty("value", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("value", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("mood", "poo"),
|
||||
IsVariantProperty("value", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameToPrecedingProperty)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "alpha");
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("alpha", "image", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameToPrecedingColumn)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "alpha");
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("alpha", "image", "value", "value2"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameToPrecedingColumnDisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "alpha");
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre("foo", IsInvalid(), 1, 42),
|
||||
ElementsAre("bar", "pic.png", 4, IsInvalid()),
|
||||
ElementsAre("poo", "pic.png", 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameToPrecedingColumnProperties)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(1, "alpha");
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("alpha", "foo"),
|
||||
IsVariantProperty("value", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("alpha", "bar"),
|
||||
IsVariantProperty("value", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("alpha", "poo"),
|
||||
IsVariantProperty("value", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameToFollowingProperty)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(2, "zoo");
|
||||
|
||||
ASSERT_THAT(model.propertyNames(), ElementsAre("image", "name", "value2", "zoo"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameToFollowingColumn)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(2, "zoo");
|
||||
|
||||
ASSERT_THAT(headerLabels(model), ElementsAre("image", "name", "value2", "zoo"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameToFollowingColumnDisplayValues)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(2, "zoo");
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 42, 1),
|
||||
ElementsAre("pic.png", "bar", IsInvalid(), 4),
|
||||
ElementsAre("pic.png", "poo", IsInvalid(), 111)));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenameToFollowingColumnProperties)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(2, "zoo");
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("name", "foo"),
|
||||
IsVariantProperty("zoo", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("name", "bar"),
|
||||
IsVariantProperty("zoo", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
|
||||
IsVariantProperty("name", "poo"),
|
||||
IsVariantProperty("zoo", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RenamePropertiesWithInvalidValue)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
|
||||
model.renameColumn(0, "mood");
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("name", "foo"),
|
||||
IsVariantProperty("value", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("mood", "pic.png"),
|
||||
IsVariantProperty("name", "bar"),
|
||||
IsVariantProperty("value", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("mood", "pic.png"),
|
||||
IsVariantProperty("name", "poo"),
|
||||
IsVariantProperty("value", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ChangeValueAfterRenamePropertiesWithInvalidValue)
|
||||
{
|
||||
model.setListModel(listModelNode);
|
||||
model.renameColumn(0, "mood");
|
||||
|
||||
model.setValue(0, 0, "haaa");
|
||||
|
||||
ASSERT_THAT(properties(),
|
||||
ElementsAre(UnorderedElementsAre(IsVariantProperty("mood", "haaa"),
|
||||
IsVariantProperty("name", "foo"),
|
||||
IsVariantProperty("value", 1),
|
||||
IsVariantProperty("value2", 42)),
|
||||
UnorderedElementsAre(IsVariantProperty("mood", "pic.png"),
|
||||
IsVariantProperty("name", "bar"),
|
||||
IsVariantProperty("value", 4)),
|
||||
UnorderedElementsAre(IsVariantProperty("mood", "pic.png"),
|
||||
IsVariantProperty("name", "poo"),
|
||||
IsVariantProperty("value", 111))));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveLastRow)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
model.addColumn("mood");
|
||||
model.addRow();
|
||||
|
||||
model.removeRow(0);
|
||||
|
||||
ASSERT_THAT(displayValues(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveLastColumn)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
model.addColumn("mood");
|
||||
model.addRow();
|
||||
|
||||
model.removeColumn(0);
|
||||
|
||||
ASSERT_THAT(displayValues(), ElementsAre(IsEmpty()));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveLastEmptyColumn)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
model.addColumn("mood");
|
||||
model.addRow();
|
||||
model.removeRow(0);
|
||||
|
||||
model.removeColumn(0);
|
||||
|
||||
ASSERT_THAT(displayValues(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, RemoveLastEmptyRow)
|
||||
{
|
||||
model.setListModel(emptyListModelNode);
|
||||
model.addColumn("mood");
|
||||
model.addRow();
|
||||
model.removeColumn(0);
|
||||
|
||||
model.removeRow(0);
|
||||
|
||||
ASSERT_THAT(displayValues(), IsEmpty());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
59
tests/unit/unittest/mocklistmodeleditorview.h
Normal file
59
tests/unit/unittest/mocklistmodeleditorview.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <googletest.h>
|
||||
|
||||
#include <qmldesigner/designercore/include/abstractview.h>
|
||||
|
||||
class MockListModelEditorView : public QmlDesigner::AbstractView
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD(void,
|
||||
variantPropertiesChanged,
|
||||
(const QList<QmlDesigner::VariantProperty> &propertyList,
|
||||
PropertyChangeFlags propertyChange),
|
||||
(override));
|
||||
MOCK_METHOD(void, nodeCreated, (const QmlDesigner::ModelNode &createdNode), (override));
|
||||
MOCK_METHOD(void,
|
||||
nodeReparented,
|
||||
(const QmlDesigner::ModelNode &node,
|
||||
const QmlDesigner::NodeAbstractProperty &newPropertyParent,
|
||||
const QmlDesigner::NodeAbstractProperty &oldPropertyParent,
|
||||
AbstractView::PropertyChangeFlags propertyChange),
|
||||
(override));
|
||||
MOCK_METHOD(void,
|
||||
propertiesRemoved,
|
||||
(const QList<QmlDesigner::AbstractProperty> &propertyList),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
nodeRemoved,
|
||||
(const QmlDesigner::ModelNode &removedNode,
|
||||
const QmlDesigner::NodeAbstractProperty &parentProperty,
|
||||
AbstractView::PropertyChangeFlags propertyChange),
|
||||
(override));
|
||||
};
|
@@ -39,8 +39,11 @@ CONFIG(release, debug|release):QMAKE_LFLAGS += -Wl,--strip-debug
|
||||
}
|
||||
|
||||
gcc:!clang: QMAKE_CXXFLAGS += -Wno-noexcept-type
|
||||
msvc: QMAKE_CXXFLAGS += /bigobj /wd4267 /wd4141 /wd4146 /wd4624
|
||||
msvc{
|
||||
QMAKE_CXXFLAGS += /bigobj /wd4267 /wd4141 /wd4146 /wd4624
|
||||
QMAKE_LFLAGS += /INCREMENTAL
|
||||
|
||||
}
|
||||
# create fake CppTools.json for the mime type definitions
|
||||
dependencyList = "\"Dependencies\" : []"
|
||||
cpptoolsjson.input = $$PWD/../../../src/plugins/cpptools/CppTools.json.in
|
||||
@@ -244,6 +247,7 @@ HEADERS += \
|
||||
mockclangpathwatcher.h \
|
||||
mockclangpathwatchernotifier.h \
|
||||
mockfilesystem.h \
|
||||
mocklistmodeleditorview.h \
|
||||
mockpchcreator.h \
|
||||
mockpchmanagerclient.h \
|
||||
mockpchmanagernotifier.h \
|
||||
|
Reference in New Issue
Block a user