Commit 8c2467d4 authored by Thomas Hartmann's avatar Thomas Hartmann

QmlDesigner: Reimplement navigator model

This patch gets rid of of QStandardItemModel.
Instead we implement a simple tree model without
any explicit structure. The model simply maps
the generic Model to a tree.

The advantage of the new model is that is does not use
a shadow data structure (QStandardItemModel) anymore.
The original model is always directly mapped to the tree model.
This makes initialization a lot faster and and there cannot
be any synchronization issues anymore.

Change-Id: I0e71ff2d4067f29a4c25c78ad3d626a5daf206a4
Reviewed-by: Tim Jenssen's avatarTim Jenssen <tim.jenssen@qt.io>
parent d79dde6d
......@@ -51,23 +51,15 @@ IconCheckboxItemDelegate::IconCheckboxItemDelegate(QObject *parent,
m_navigatorTreeModel(treeModel)
{}
static bool indexIsHolingModelNode(const QModelIndex &modelIndex)
{
return modelIndex.data(NavigatorTreeModel::InternalIdRole).isValid();
}
QSize IconCheckboxItemDelegate::sizeHint(const QStyleOptionViewItem & /*option*/,
const QModelIndex &modelIndex) const
const QModelIndex & /*modelIndex*/) const
{
if (indexIsHolingModelNode(modelIndex))
return QSize(15, 20);
return QSize();
return QSize(15, 20);
}
static bool isChecked(NavigatorTreeModel *navigatorTreeMode, const QModelIndex &modelIndex)
static bool isChecked(NavigatorTreeModel *navigatorTreeModel, const QModelIndex &modelIndex)
{
return navigatorTreeMode->itemFromIndex(modelIndex)->checkState() == Qt::Checked;
return navigatorTreeModel->data(modelIndex, Qt::CheckStateRole) == Qt::Checked;
}
void IconCheckboxItemDelegate::paint(QPainter *painter,
......@@ -77,23 +69,22 @@ void IconCheckboxItemDelegate::paint(QPainter *painter,
const int yOffset = (styleOption.rect.height()
- (m_checkedPixmap.height() / painter->device()->devicePixelRatio())) / 2;
const int xOffset = 2;
if (indexIsHolingModelNode(modelIndex)) {
painter->save();
if (styleOption.state & QStyle::State_Selected)
NavigatorTreeView::drawSelectionBackground(painter, styleOption);
if (!m_navigatorTreeModel->nodeForIndex(modelIndex).isRootNode()) {
painter->save();
if (styleOption.state & QStyle::State_Selected)
NavigatorTreeView::drawSelectionBackground(painter, styleOption);
if (m_navigatorTreeModel->isNodeInvisible(modelIndex))
painter->setOpacity(0.5);
if (!m_navigatorTreeModel->modelNodeForIndex(modelIndex).isRootNode()) {
const bool checked = isChecked(m_navigatorTreeModel, modelIndex);
painter->drawPixmap(styleOption.rect.x() + xOffset, styleOption.rect.y() + yOffset,
checked ? m_checkedPixmap : m_uncheckedPixmap);
}
if (m_navigatorTreeModel->isNodeVisible(modelIndex))
painter->setOpacity(0.5);
painter->restore();
const bool checked = isChecked(m_navigatorTreeModel, modelIndex);
painter->drawPixmap(styleOption.rect.x() + xOffset, styleOption.rect.y() + yOffset,
checked ? m_checkedPixmap : m_uncheckedPixmap);
}
painter->restore();
}
} // namespace QmlDesigner
......@@ -116,19 +116,16 @@ static int drawIcon(QPainter *painter, const QStyleOptionViewItem &styleOption,
}
static QRect drawText(QPainter *painter,
const QStyleOptionViewItem &styleOption,
const QModelIndex &modelIndex,
int iconOffset)
const QStyleOptionViewItem &styleOption,
const QModelIndex &modelIndex,
int iconOffset)
{
QString displayString = modelIndex.data(Qt::DisplayRole).toString();
if (displayString.isEmpty())
displayString = modelIndex.data(NavigatorTreeModel::SimplifiedTypeNameRole).toString();
displayString = modelIndex.data(Qt::DisplayRole).toString();
QPoint displayStringOffset;
int width = 0;
if (modelIndex.data(NavigatorTreeModel::InvisibleRole).toBool())
painter->setOpacity(0.5);
// Check text length does not exceed available space
int extraSpace = 12 + iconOffset;
......@@ -171,9 +168,12 @@ void NameItemDelegate::paint(QPainter *painter,
int iconOffset = drawIcon(painter, styleOption, modelIndex);
if (m_navigatorTreeModel->isNodeVisible(modelIndex))
painter->setOpacity(0.5);
QRect textFrame = drawText(painter, styleOption, modelIndex, iconOffset);
if (modelIndex.data(NavigatorTreeModel::ErrorRole).toBool())
if (m_navigatorTreeModel->hasError(modelIndex))
drawRedWavyUnderLine(painter, styleOption, textFrame);
painter->restore();
......@@ -196,7 +196,7 @@ QWidget *NameItemDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem & /*option*/,
const QModelIndex &index) const
{
if (!m_navigatorTreeModel->hasNodeForIndex(index))
if (!m_navigatorTreeModel->hasModelNodeForIndex(index))
return 0;
return new QLineEdit(parent);
......@@ -204,8 +204,8 @@ QWidget *NameItemDelegate::createEditor(QWidget *parent,
void NameItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
ModelNode node = m_navigatorTreeModel->nodeForIndex(index);
QString value = node.id();
const ModelNode node = m_navigatorTreeModel->modelNodeForIndex(index);
const QString value = node.id();
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
lineEdit->setText(value);
......
......@@ -38,110 +38,71 @@ class Model;
class AbstractView;
class ModelNode;
#ifdef _LOCK_ITEMS_
struct ItemRow {
ItemRow()
: idItem(0), lockItem(0), visibilityItem(0) {}
ItemRow(QStandardItem *id, QStandardItem *lock, QStandardItem *visibility, const QMap<QString, QStandardItem *> &properties)
: idItem(id), lockItem(lock), visibilityItem(visibility), propertyItems(properties) {}
QList<QStandardItem*> toList() const {
return {idItem, lockItem, visibilityItem};
}
QStandardItem *idItem;
QStandardItem *lockItem;
QStandardItem *visibilityItem;
QMap<QString, QStandardItem *> propertyItems;
};
#else
struct ItemRow {
ItemRow()
: idItem(0), visibilityItem(0) {}
ItemRow(QStandardItem *id, QStandardItem *exportI, QStandardItem *visibility, const QMap<QString, QStandardItem *> &properties)
: idItem(id), exportItem(exportI), visibilityItem(visibility), propertyItems(properties) {}
QList<QStandardItem*> toList() const {
return {idItem, exportItem, visibilityItem};
}
QStandardItem *idItem;
QStandardItem *exportItem;
QStandardItem *visibilityItem;
QMap<QString, QStandardItem *> propertyItems;
};
#endif
class NavigatorTreeModel : public QStandardItemModel
class NavigatorTreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum {
InternalIdRole = Qt::UserRole
,InvisibleRole = Qt::UserRole + 1
,SimplifiedTypeNameRole = Qt::UserRole + 2
,ErrorRole = Qt::UserRole + 3
};
NavigatorTreeModel(QObject *parent = 0);
explicit NavigatorTreeModel(QObject *parent = 0);
~NavigatorTreeModel();
Qt::DropActions supportedDropActions() const;
Qt::DropActions supportedDragActions() const;
QVariant data(const QModelIndex &index, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
void setView(AbstractView *view);
ModelNode modelNodeForIndex(const QModelIndex &index) const;
bool hasModelNodeForIndex(const QModelIndex &index) const;
QStringList mimeTypes() const;
QMimeData *mimeData(const QModelIndexList &indexes) const;
QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override;
bool dropMimeData(const QMimeData *data,
Qt::DropAction action,
int row,
int column,
const QModelIndex &parent);
const QModelIndex &parent) override;
void setView(AbstractView *view);
void clearView();
QModelIndex indexForNode(const ModelNode &node) const;
ModelNode nodeForIndex(const QModelIndex &index) const;
bool hasNodeForIndex(const QModelIndex &index) const;
bool isInTree(const ModelNode &node) const;
bool isNodeInvisible(const QModelIndex &index) const;
bool isNodeInvisible(const ModelNode &node) const;
QModelIndex indexForModelNode(const ModelNode &node) const;
void addSubTree(const ModelNode &node);
void removeSubTree(const ModelNode &node);
void updateItemRow(const ModelNode &node);
QModelIndex createIndexFromModelNode(int row, int column, const ModelNode &modelNode) const;
void setId(const QModelIndex &index, const QString &id);
void setExported(const QModelIndex &index, bool exported);
void setVisible(const QModelIndex &index, bool visible);
void setId(const QModelIndex &index, const QString &newId);
void openContextMenu(const QPoint &position);
void openContextMenu(const QPoint &p);
Qt::DropActions supportedDropActions() const override;
Qt::DropActions supportedDragActions() const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
ItemRow itemRowForNode(const ModelNode &node);
bool blockItemChangedSignal(bool block);
void notifyDataChanged(const ModelNode &modelNode);
void notifyModelNodesRemoved(const QList<ModelNode> &modelNodes);
void notifyModelNodesInserted(const QList<ModelNode> &modelNodes);
void notifyModelNodesMoved(const QList<ModelNode> &modelNodes);
bool isNodeVisible(const ModelNode &modelNode) const;
bool isNodeVisible(const QModelIndex &index) const;
bool hasError(const QModelIndex &index) const;
private:
void handleChangedItem(QStandardItem *item);
ItemRow createItemRow(const ModelNode &node);
void updateItemRow(const ModelNode &node, ItemRow row);
void handleChangedIdItem(QStandardItem *idItem, ModelNode &modelNode);
void handleChangedExportItem(QStandardItem *exportItem, ModelNode &modelNode);
void handleChangedVisibilityItem(QStandardItem *visibilityItem, ModelNode &modelNode);
void handleChangedExport(const ModelNode &modelNode, bool exportItem);
void moveNodesInteractive(NodeAbstractProperty &parentProperty, const QList<ModelNode> &modelNodes, int targetIndex);
void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryImageDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
QList<QPersistentModelIndex> nodesToPersistentIndex(const QList<ModelNode> &modelNodes);
private:
QHash<ModelNode, ItemRow> m_nodeItemHash;
QPointer<AbstractView> m_view;
bool m_blockItemChangedSignal;
mutable QHash<ModelNode, QModelIndex> m_nodeIndexHash;
};
} // namespace QmlDesigner
......@@ -31,10 +31,10 @@
#include "navigatortreemodel.h"
#include "qproxystyle.h"
#include "metainfo.h"
#include <metainfo.h>
#include <utils/stylehelper.h>
#include <utils/theme/theme.h>
#include <utils/icon.h>
#include <utils/utilsicons.h>
#include <QLineEdit>
#include <QPen>
......@@ -67,17 +67,9 @@ public:
if (option->state & QStyle::State_MouseOver)
mouseOverStateSavedFrameRectangle = option->rect;
if (option->state & QStyle::State_Selected) {
if (option->state & QStyle::State_Selected)
NavigatorTreeView::drawSelectionBackground(painter, *option);
} else {
// // 3D shadows
// painter->save();
// painter->setPen(QColor(255, 255, 255, 15));
// painter->drawLine(option->rect.topLeft(), option->rect.topRight());
// painter->setPen(QColor(0, 0, 0, 25));
// painter->drawLine(option->rect.bottomLeft(),option->rect.bottomRight());
// painter->restore();
}
} else if (element == PE_IndicatorItemViewItemDrop) {
// between elements and on elements we have a width
if (option->rect.width() > 0) {
......@@ -171,6 +163,8 @@ NavigatorTreeView::NavigatorTreeView(QWidget *parent)
{
setStyle(new TableViewStyle(this));
setMinimumWidth(240);
setRootIsDecorated(false);
setIndentation(indentation() * 0.5);
}
void NavigatorTreeView::drawSelectionBackground(QPainter *painter, const QStyleOption &option)
......
......@@ -58,6 +58,7 @@ public:
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty, PropertyChangeFlags propertyChange);
void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override;
......
......@@ -60,8 +60,10 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view) :
setWindowTitle(tr("Navigator", "Title of navigator view"));
#ifndef QMLDESIGNER_TEST
setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/stylesheet.css")))));
m_treeView->setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/scrollbar.css")))));
#endif
}
void NavigatorWidget::setTreeModel(QAbstractItemModel* model)
......
......@@ -93,6 +93,7 @@ public:
ModelNode& operator=(const ModelNode &other);
TypeName type() const;
QString simplifiedTypeName() const;
QString displayName() const;
int minorVersion() const;
int majorVersion() const;
......
......@@ -313,6 +313,13 @@ QString ModelNode::simplifiedTypeName() const
return QString::fromUtf8(type().split('.').last());
}
QString ModelNode::displayName() const
{
if (hasId())
return id();
return simplifiedTypeName();
}
/*! \brief Returns whether the node is valid
A node is valid if its model still exists, and contains this node.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment