#1898 Curve Creator: Use tree structure internally in QModel

This commit is contained in:
Magne Sjaastad 2017-09-19 10:08:32 +02:00
parent da9421485e
commit 424c4b18a3
5 changed files with 446 additions and 345 deletions

View File

@ -121,6 +121,10 @@ QList<caf::PdmOptionItemInfo> ManyGroups::calculateValueOptions(const caf::PdmFi
//--------------------------------------------------------------------------------------------------
void ManyGroups::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering)
{
uiOrdering.add(&m_toggleField);
uiOrdering.add(&m_multiSelectList);
/*
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup("First");
@ -156,4 +160,5 @@ void ManyGroups::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOr
subGroup->add(&m_proxyDoubleField);
}
*/
}

View File

@ -40,8 +40,12 @@
#include "cafPdmObject.h"
#include "cafPdmUiTreeSelectionQModel.h"
#include <QBoxLayout>
#include <QCheckBox>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QSortFilterProxyModel>
#include <QTreeView>
#include <algorithm>
@ -99,6 +103,8 @@ CAF_PDM_UI_FIELD_EDITOR_SOURCE_INIT(PdmUiTreeSelectionEditor);
///
//--------------------------------------------------------------------------------------------------
PdmUiTreeSelectionEditor::PdmUiTreeSelectionEditor()
: m_model(nullptr),
m_proxyModel(nullptr)
{
}
@ -124,39 +130,89 @@ void PdmUiTreeSelectionEditor::configureAndUpdateUi(const QString& uiConfigName)
bool optionsOnly = true;
QList<PdmOptionItemInfo> options = field()->valueOptions(&optionsOnly);
if (!m_treeView->model())
if (!m_model)
{
caf::PdmUiTreeSelectionQModel* model = new caf::PdmUiTreeSelectionQModel(m_treeView);
m_treeView->setModel(model);
connect(model, SIGNAL(signalSelectionStateForIndexHasChanged(int, bool)), this, SLOT(slotSetSelectionStateForIndex(int, bool)));
m_model = new caf::PdmUiTreeSelectionQModel(m_treeView);
m_proxyModel = new QSortFilterProxyModel;
m_proxyModel->setSourceModel(m_model);
m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_treeView->setModel(m_proxyModel);
}
caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast<caf::PdmUiTreeSelectionQModel*>(m_treeView->model());
if (treeSelectionQModel)
bool itemCountHasChaged = false;
if (m_model->optionItemCount() != options.size()) itemCountHasChaged = true;
// TODO: If the count is different between incoming and current list of items,
// use cafQTreeViewStateSerializer to restore collapsed state
m_model->setOptions(this, options);
if (itemCountHasChaged)
{
bool itemCountHasChaged = false;
if (treeSelectionQModel->optionItemCount() != options.size()) itemCountHasChaged = true;
m_treeView->expandAll();
}
// TODO: If the count is different between incoming and current list of items,
// use cafQTreeViewStateSerializer to restore collapsed state
treeSelectionQModel->setOptions(this, options);
if (itemCountHasChaged)
bool allItemsChecked = true;
QModelIndexList indices = allVisibleSourceModelIndices();
for (auto mi : indices)
{
if (m_model->data(mi, Qt::CheckStateRole).toBool() == false)
{
m_treeView->expandAll();
allItemsChecked = false;
}
}
//m_toggleAllCheckBox->setChecked(allItemsChecked);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSelectionStateForIndex(int index, bool setSelected)
QWidget* PdmUiTreeSelectionEditor::createEditorWidget(QWidget* parent)
{
std::vector<int> indices;
indices.push_back(index);
QFrame* frame = new QFrame(parent);
QVBoxLayout* layout = new QVBoxLayout;
frame->setLayout(layout);
setSelectionStateForIndices(indices, setSelected);
{
QHBoxLayout* headerLayout = new QHBoxLayout;
layout->addLayout(headerLayout);
// m_toggleAllCheckBox = new QCheckBox();
// headerLayout->addWidget(m_toggleAllCheckBox);
//
// connect(m_toggleAllCheckBox, SIGNAL(clicked(bool)), this, SLOT(slotToggleAll()));
// m_textFilterLineEdit = new QLineEdit();
// headerLayout->addWidget(m_textFilterLineEdit);
//
// connect(m_textFilterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotTextFilterChanged()));
}
QTreeViewHeightHint* treeViewHeightHint = new QTreeViewHeightHint(parent);
treeViewHeightHint->setHeightHint(2000);
treeViewHeightHint->setHeaderHidden(true);
treeViewHeightHint->setSelectionMode(QAbstractItemView::ExtendedSelection);
treeViewHeightHint->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeViewHeightHint, SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint)));
m_treeView = treeViewHeightHint;
layout->addWidget(treeViewHeightHint);
return frame;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* PdmUiTreeSelectionEditor::createLabelWidget(QWidget * parent)
{
m_label = new QLabel(parent);
return m_label;
}
//--------------------------------------------------------------------------------------------------
@ -166,43 +222,48 @@ void PdmUiTreeSelectionEditor::customMenuRequested(const QPoint& pos)
{
QMenu menu;
QModelIndexList selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
bool onlyHeadersInSelection = true;
for (auto mi : selectedIndexes)
{
std::vector<int> items = selectedCheckableItems();
if (items.size() > 0)
QVariant v = m_proxyModel->data(mi, PdmUiTreeSelectionQModel::headingRole());
if (v.toBool() == false)
{
{
QAction* act = new QAction("Set Selected On", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSelectedOn()));
menu.addAction(act);
}
{
QAction* act = new QAction("Set Selected Off", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSelectedOff()));
menu.addAction(act);
}
onlyHeadersInSelection = false;
}
}
if (onlyHeadersInSelection)
{
std::vector<int> items = selectedHeaderItems();
if (items.size() > 0)
{
{
QAction* act = new QAction("Set Sub Items On", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSubItemsOn()));
QAction* act = new QAction("Sub Items On", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSubItemsOn()));
menu.addAction(act);
}
menu.addAction(act);
}
{
QAction* act = new QAction("Set Sub Items Off", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSubItemsOff()));
{
QAction* act = new QAction("Sub Items Off", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSubItemsOff()));
menu.addAction(act);
}
menu.addAction(act);
}
}
else if (selectedIndexes.size() > 0)
{
{
QAction* act = new QAction("Set Selected On", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSelectedOn()));
menu.addAction(act);
}
{
QAction* act = new QAction("Set Selected Off", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSelectedOff()));
menu.addAction(act);
}
}
@ -220,10 +281,12 @@ void PdmUiTreeSelectionEditor::customMenuRequested(const QPoint& pos)
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSelectedOn()
{
std::vector<int> items = selectedCheckableItems();
if (items.size() > 0)
if (!m_proxyModel) return;
QModelIndexList selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
for (auto mi : selectedIndexes)
{
setSelectionStateForIndices(items, true);
m_proxyModel->setData(mi, true, Qt::CheckStateRole);
}
}
@ -232,10 +295,12 @@ void PdmUiTreeSelectionEditor::slotSetSelectedOn()
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSelectedOff()
{
std::vector<int> items = selectedCheckableItems();
if (items.size() > 0)
if (!m_proxyModel) return;
QModelIndexList selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
for (auto mi : selectedIndexes)
{
setSelectionStateForIndices(items, false);
m_proxyModel->setData(mi, false, Qt::CheckStateRole);
}
}
@ -244,14 +309,14 @@ void PdmUiTreeSelectionEditor::slotSetSelectedOff()
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSubItemsOn()
{
caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast<caf::PdmUiTreeSelectionQModel*>(m_treeView->model());
std::vector<int> items = selectedHeaderItems();
for (auto i : items)
QModelIndexList selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
for (auto mi : selectedIndexes)
{
std::vector<int> children = treeSelectionQModel->allSubItemIndices(i);
setSelectionStateForIndices(children, true);
for (int i = 0; i < m_proxyModel->rowCount(mi); i++)
{
QModelIndex childIndex = m_proxyModel->index(i, 0, mi);
m_proxyModel->setData(childIndex, true, Qt::CheckStateRole);
}
}
}
@ -260,145 +325,99 @@ void PdmUiTreeSelectionEditor::slotSetSubItemsOn()
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSubItemsOff()
{
caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast<caf::PdmUiTreeSelectionQModel*>(m_treeView->model());
std::vector<int> items = selectedHeaderItems();
for (auto i : items)
QModelIndexList selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
for (auto mi : selectedIndexes)
{
std::vector<int> children = treeSelectionQModel->allSubItemIndices(i);
setSelectionStateForIndices(children, false);
for (int i = 0; i < m_proxyModel->rowCount(mi); i++)
{
QModelIndex childIndex = m_proxyModel->index(i, 0, mi);
m_proxyModel->setData(childIndex, false, Qt::CheckStateRole);
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> PdmUiTreeSelectionEditor::selectedCheckableItems() const
void PdmUiTreeSelectionEditor::slotToggleAll()
{
std::vector<int> items;
caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast<caf::PdmUiTreeSelectionQModel*>(m_treeView->model());
if (treeSelectionQModel)
if (m_toggleAllCheckBox->isChecked())
{
QModelIndexList selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
for (auto mi : selectedIndexes)
{
auto optionItem = treeSelectionQModel->optionItem(mi);
if (!optionItem->isHeading())
{
items.push_back(treeSelectionQModel->optionItemIndex(mi));
}
}
checkAllItems();
}
else
{
unCheckAllItems();
}
return items;
// Set focus back to the tree view to trigger a redraw
m_treeView->setFocus();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> PdmUiTreeSelectionEditor::selectedHeaderItems() const
void PdmUiTreeSelectionEditor::slotTextFilterChanged()
{
std::vector<int> items;
QString searchString = m_textFilterLineEdit->text();
searchString += "*";
caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast<caf::PdmUiTreeSelectionQModel*>(m_treeView->model());
if (treeSelectionQModel)
{
QModelIndexList selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
for (auto mi : selectedIndexes)
{
auto optionItem = treeSelectionQModel->optionItem(mi);
if (optionItem->isHeading())
{
items.push_back(treeSelectionQModel->optionItemIndex(mi));
}
}
}
return items;
m_proxyModel->setFilterWildcard(searchString);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::setSelectionStateForIndices(const std::vector<int>& indices, bool setSelected)
void PdmUiTreeSelectionEditor::checkAllItems()
{
std::vector<unsigned int> selectedIndices;
QModelIndexList indices = allVisibleSourceModelIndices();
m_model->setCheckedStateForItems(indices, true);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::unCheckAllItems()
{
QModelIndexList indices = allVisibleSourceModelIndices();
m_model->setCheckedStateForItems(indices, false);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QModelIndexList PdmUiTreeSelectionEditor::allVisibleSourceModelIndices() const
{
QModelIndexList indices;
recursiveAppendVisibleSourceModelIndices(QModelIndex(), &indices);
return indices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::recursiveAppendVisibleSourceModelIndices(const QModelIndex& parent, QModelIndexList* sourceModelIndices) const
{
for (int row = 0; row < m_proxyModel->rowCount(parent); row++)
{
QVariant fieldValue = field()->uiValue();
QList<QVariant> fieldValueSelection = fieldValue.toList();
for (auto v : fieldValueSelection)
QModelIndex mi = m_proxyModel->index(row, 0, parent);
if (mi.isValid())
{
selectedIndices.push_back(v.toUInt());
}
}
for (auto index : indices)
{
unsigned int unsignedIndex = static_cast<unsigned int>(index);
if (setSelected)
{
bool isIndexPresent = false;
for (auto indexInField : selectedIndices)
QVariant v = m_proxyModel->data(mi, PdmUiTreeSelectionQModel::headingRole());
if (v.toBool() == false)
{
if (indexInField == unsignedIndex)
{
isIndexPresent = true;
}
sourceModelIndices->push_back(m_proxyModel->mapToSource(mi));
}
if (!isIndexPresent)
{
selectedIndices.push_back(unsignedIndex);
}
}
else
{
selectedIndices.erase(std::remove(selectedIndices.begin(), selectedIndices.end(), unsignedIndex), selectedIndices.end());
recursiveAppendVisibleSourceModelIndices(mi, sourceModelIndices);
}
}
QList<QVariant> fieldValueSelection;
for (auto v : selectedIndices)
{
fieldValueSelection.push_back(QVariant(v));
}
this->setValueToField(fieldValueSelection);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* PdmUiTreeSelectionEditor::createEditorWidget(QWidget * parent)
{
QTreeViewHeightHint* treeViewHeightHint = new QTreeViewHeightHint(parent);
treeViewHeightHint->setHeightHint(2000);
treeViewHeightHint->setHeaderHidden(true);
treeViewHeightHint->setSelectionMode(QAbstractItemView::ExtendedSelection);
treeViewHeightHint->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeViewHeightHint, SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint)));
m_treeView = treeViewHeightHint;
return treeViewHeightHint;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* PdmUiTreeSelectionEditor::createLabelWidget(QWidget * parent)
{
m_label = new QLabel(parent);
return m_label;
}
} // end namespace caf

View File

@ -38,12 +38,34 @@
#include "cafPdmUiFieldEditorHandle.h"
#include <QAbstractItemModel>
class QLabel;
class QTreeView;
class QAbstractItemModel;
class QCheckBox;
class QLineEdit;
class QSortFilterProxyModel;
class QModelIndex;
namespace caf
{
class PdmUiTreeSelectionQModel;
//==================================================================================================
///
//==================================================================================================
class PdmUiTreeSelectionEditorAttribute : public PdmUiEditorAttribute
{
public:
bool showTextFilter;
public:
PdmUiTreeSelectionEditorAttribute()
{
showTextFilter = false;
}
};
//==================================================================================================
///
@ -54,16 +76,15 @@ class PdmUiTreeSelectionEditor : public PdmUiFieldEditorHandle
CAF_PDM_UI_FIELD_EDITOR_HEADER_INIT;
public:
PdmUiTreeSelectionEditor();
virtual ~PdmUiTreeSelectionEditor();
PdmUiTreeSelectionEditor();
virtual ~PdmUiTreeSelectionEditor();
protected:
virtual QWidget* createEditorWidget(QWidget * parent);
virtual QWidget* createLabelWidget(QWidget * parent);
virtual void configureAndUpdateUi(const QString& uiConfigName);
virtual QWidget* createEditorWidget(QWidget* parent);
virtual QWidget* createLabelWidget(QWidget* parent);
private slots:
void slotSetSelectionStateForIndex(int index, bool setSelected);
void customMenuRequested(const QPoint& pos);
void slotSetSelectedOn();
@ -71,14 +92,26 @@ private slots:
void slotSetSubItemsOn();
void slotSetSubItemsOff();
private:
std::vector<int> selectedCheckableItems() const;
std::vector<int> selectedHeaderItems() const;
void setSelectionStateForIndices(const std::vector<int>& indices, bool setSelected);
void slotToggleAll();
void slotTextFilterChanged();
private:
QPointer<QTreeView> m_treeView;
QPointer<QLabel> m_label;
void checkAllItems();
void unCheckAllItems();
QModelIndexList allVisibleSourceModelIndices() const;
void recursiveAppendVisibleSourceModelIndices(const QModelIndex& parent,
QModelIndexList* sourceModelIndices) const;
private:
QPointer<QTreeView> m_treeView;
QPointer<QLabel> m_label;
QPointer<QCheckBox> m_toggleAllCheckBox;
QPointer<QLineEdit> m_textFilterLineEdit;
PdmUiTreeSelectionQModel* m_model;
QSortFilterProxyModel* m_proxyModel;
};
} // end namespace caf

View File

@ -36,8 +36,9 @@
#include "cafPdmUiTreeSelectionQModel.h"
#include "cafPdmUiTreeViewModel.h"
#include "cafPdmObject.h"
#include "cafPdmUiCommandSystemProxy.h"
#include "cafPdmUiTreeViewModel.h"
#include <QAbstractItemModel>
#include <QLabel>
@ -50,29 +51,68 @@
caf::PdmUiTreeSelectionQModel::PdmUiTreeSelectionQModel(QObject *parent /*= 0*/) : QAbstractItemModel(parent)
{
m_uiFieldHandle = nullptr;
m_zeroLevelRowCount = 0;
m_tree = nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void caf::PdmUiTreeSelectionQModel::setOptions(caf::PdmUiFieldEditorHandle* field, const QList<caf::PdmOptionItemInfo>& options)
caf::PdmUiTreeSelectionQModel::~PdmUiTreeSelectionQModel()
{
bool itemCountHasChanged = false;
if (optionItemCount() != options.size())
m_uiFieldHandle = nullptr;
delete m_tree;
m_tree = nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int caf::PdmUiTreeSelectionQModel::headingRole()
{
return Qt::UserRole + 1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void caf::PdmUiTreeSelectionQModel::setCheckedStateForItems(const QModelIndexList& sourceModelIndices, bool checked)
{
std::set<unsigned int> selectedIndices;
{
itemCountHasChanged = true;
QVariant fieldValue = m_uiFieldHandle->field()->uiValue();
QList<QVariant> fieldValueSelection = fieldValue.toList();
for (auto v : fieldValueSelection)
{
selectedIndices.insert(v.toUInt());
}
}
m_uiFieldHandle = field;
m_options = options;
computeOptionItemTreeData();
if (itemCountHasChanged)
if (checked)
{
reset();
for (auto mi : sourceModelIndices)
{
selectedIndices.insert(static_cast<unsigned int>(optionIndex(mi)));
}
}
else
{
for (auto mi : sourceModelIndices)
{
selectedIndices.erase(static_cast<unsigned int>(optionIndex(mi)));
}
}
QList<QVariant> fieldValueSelection;
for (auto v : selectedIndices)
{
fieldValueSelection.push_back(QVariant(v));
}
beginResetModel();
PdmUiCommandSystemProxy::instance()->setUiValueToField(m_uiFieldHandle->field(), fieldValueSelection);
endResetModel();
}
//--------------------------------------------------------------------------------------------------
@ -83,19 +123,54 @@ int caf::PdmUiTreeSelectionQModel::optionItemCount() const
return m_options.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void caf::PdmUiTreeSelectionQModel::setOptions(caf::PdmUiFieldEditorHandle* field, const QList<caf::PdmOptionItemInfo>& options)
{
m_uiFieldHandle = field;
if (m_options.size() != options.size())
{
beginResetModel();
m_options = options;
if (m_tree)
{
delete m_tree;
m_tree = nullptr;
}
m_tree = new TreeItemType(nullptr, -1, 0);
buildOptionItemTree(0, m_tree);
endResetModel();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const caf::PdmOptionItemInfo* caf::PdmUiTreeSelectionQModel::optionItem(const QModelIndex &index) const
{
if (index.isValid())
{
int opIndex = optionItemIndex(index);
int opIndex = optionIndex(index);
return &(m_options[opIndex]);
}
return &m_options[opIndex];
}
return nullptr;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int caf::PdmUiTreeSelectionQModel::optionIndex(const QModelIndex &index) const
{
CAF_ASSERT(index.isValid());
TreeItemType* item = static_cast<TreeItemType*>(index.internalPointer());
int optionIndex = item->dataObject();
return optionIndex;
}
//--------------------------------------------------------------------------------------------------
@ -105,13 +180,13 @@ Qt::ItemFlags caf::PdmUiTreeSelectionQModel::flags(const QModelIndex &index) con
{
if (index.isValid())
{
int opIndex = optionItemIndex(index);
const caf::PdmOptionItemInfo* optionItemInfo = optionItem(index);
if (m_options[opIndex].isReadOnly())
if (optionItemInfo->isReadOnly())
{
return QAbstractItemModel::flags(index)^Qt::ItemIsEnabled;
}
else if (!m_options[opIndex].isHeading())
else if (!optionItemInfo->isHeading())
{
return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
}
@ -128,23 +203,18 @@ QModelIndex caf::PdmUiTreeSelectionQModel::index(int row, int column, const QMod
if (!hasIndex(row, column, parent))
return QModelIndex();
if (m_zeroLevelRowToOptionIndex.size() == 0)
return QModelIndex();
TreeItemType* parentItem;
int opIndex = -1;
if (parent.isValid())
{
opIndex = optionItemIndex(parent) + row + 1;
}
if (!parent.isValid())
parentItem = m_tree;
else
{
opIndex = m_zeroLevelRowToOptionIndex.at(row);
}
parentItem = static_cast<TreeItemType*>(parent.internalPointer());
CAF_ASSERT(opIndex > -1);
CAF_ASSERT(opIndex < m_options.size());
return createIndex(row, column, opIndex);
TreeItemType* childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
//--------------------------------------------------------------------------------------------------
@ -158,12 +228,18 @@ int caf::PdmUiTreeSelectionQModel::columnCount(const QModelIndex &parent /*= QMo
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QModelIndex caf::PdmUiTreeSelectionQModel::parent(const QModelIndex &child) const
QModelIndex caf::PdmUiTreeSelectionQModel::parent(const QModelIndex &index) const
{
if (!child.isValid())
if (!index.isValid())
return QModelIndex();
return m_optionsTreeData[optionItemIndex(child)].parentModelIndex;
TreeItemType* childItem = static_cast<TreeItemType*>(index.internalPointer());
TreeItemType* parentItem = childItem->parent();
if (parentItem == m_tree)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
//--------------------------------------------------------------------------------------------------
@ -171,12 +247,18 @@ QModelIndex caf::PdmUiTreeSelectionQModel::parent(const QModelIndex &child) cons
//--------------------------------------------------------------------------------------------------
int caf::PdmUiTreeSelectionQModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const
{
if (!parent.isValid())
{
return m_zeroLevelRowCount;
}
if (!m_tree) return 0;
return m_optionsTreeData[optionItemIndex(parent)].childCount;
if (parent.column() > 0)
return 0;
TreeItemType* parentItem;
if (!parent.isValid())
parentItem = m_tree;
else
parentItem = static_cast<TreeItemType*>(parent.internalPointer());
return parentItem->childCount();
}
//--------------------------------------------------------------------------------------------------
@ -186,19 +268,17 @@ QVariant caf::PdmUiTreeSelectionQModel::data(const QModelIndex &index, int role
{
if (index.isValid())
{
CAF_ASSERT(index.internalId() < m_options.size());
int opIndex = optionItemIndex(index);
const caf::PdmOptionItemInfo* optionItemInfo = optionItem(index);
if (role == Qt::DisplayRole)
{
return m_options[opIndex].optionUiText();
return optionItemInfo->optionUiText();
}
else if (role == Qt::DecorationRole)
{
return m_options[opIndex].icon();
return optionItemInfo->icon();
}
else if (role == Qt::CheckStateRole && !m_options[opIndex].isHeading())
else if (role == Qt::CheckStateRole && !optionItemInfo->isHeading())
{
CAF_ASSERT(m_uiFieldHandle);
@ -207,6 +287,8 @@ QVariant caf::PdmUiTreeSelectionQModel::data(const QModelIndex &index, int role
QVariant fieldValue = m_uiFieldHandle->field()->uiValue();
QList<QVariant> valuesSelectedInField = fieldValue.toList();
int opIndex = optionIndex(index);
for (QVariant v : valuesSelectedInField)
{
int indexInField = v.toInt();
@ -221,7 +303,7 @@ QVariant caf::PdmUiTreeSelectionQModel::data(const QModelIndex &index, int role
}
else if (role == Qt::FontRole)
{
if (m_options[opIndex].isHeading())
if (optionItemInfo->isHeading())
{
QFont font;
font.setBold(true);
@ -229,6 +311,10 @@ QVariant caf::PdmUiTreeSelectionQModel::data(const QModelIndex &index, int role
return font;
}
}
else if (role == headingRole())
{
return optionItemInfo->isHeading();
}
}
return QVariant();
@ -239,14 +325,54 @@ QVariant caf::PdmUiTreeSelectionQModel::data(const QModelIndex &index, int role
//--------------------------------------------------------------------------------------------------
bool caf::PdmUiTreeSelectionQModel::setData(const QModelIndex &index, const QVariant &value, int role /*= Qt::EditRole*/)
{
if (role == Qt::CheckStateRole)
{
bool isSelected = value.toBool();
if (role == Qt::CheckStateRole)
{
std::vector<unsigned int> selectedIndices;
{
QVariant fieldValue = m_uiFieldHandle->field()->uiValue();
QList<QVariant> fieldValueSelection = fieldValue.toList();
emit signalSelectionStateForIndexHasChanged(optionItemIndex(index), isSelected);
for (auto v : fieldValueSelection)
{
selectedIndices.push_back(v.toUInt());
}
}
return true;
}
bool setSelected = value.toBool();
unsigned int opIndex = static_cast<unsigned int>(optionIndex(index));
if (setSelected)
{
bool isIndexPresent = false;
for (auto indexInField : selectedIndices)
{
if (indexInField == opIndex)
{
isIndexPresent = true;
}
}
if (!isIndexPresent)
{
selectedIndices.push_back(opIndex);
}
}
else
{
selectedIndices.erase(std::remove(selectedIndices.begin(), selectedIndices.end(), opIndex), selectedIndices.end());
}
QList<QVariant> fieldValueSelection;
for (auto v : selectedIndices)
{
fieldValueSelection.push_back(QVariant(v));
}
PdmUiCommandSystemProxy::instance()->setUiValueToField(m_uiFieldHandle->field(), fieldValueSelection);
return true;
}
return false;
}
@ -254,106 +380,33 @@ bool caf::PdmUiTreeSelectionQModel::setData(const QModelIndex &index, const QVar
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int caf::PdmUiTreeSelectionQModel::optionItemIndex(const QModelIndex& modelIndex) const
void caf::PdmUiTreeSelectionQModel::buildOptionItemTree(int parentOptionIndex, TreeItemType* parentNode)
{
CAF_ASSERT(modelIndex.isValid());
CAF_ASSERT(modelIndex.internalId() < m_options.size());
return modelIndex.internalId();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> caf::PdmUiTreeSelectionQModel::allSubItemIndices(int headingIndex) const
{
std::vector<int> children;
int parentLevel = m_options[headingIndex].level();
int currentIndex = headingIndex + 1;
while (currentIndex < m_options.size() && m_options[currentIndex].level() > parentLevel)
if (parentNode == m_tree)
{
children.push_back(currentIndex);
currentIndex++;
for (int i = 0; i < m_options.size(); i++)
{
if (m_options[i].level() == 0)
{
TreeItemType* node = new TreeItemType(parentNode, -1, i);
buildOptionItemTree(i, node);
}
}
}
return children;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void caf::PdmUiTreeSelectionQModel::computeOptionItemTreeData()
{
m_optionsTreeData.clear();
m_zeroLevelRowToOptionIndex.clear();
if (m_options.size() == 0) return;
m_optionsTreeData.resize(m_options.size());
m_zeroLevelRowCount = 0;
for (int i = 0; i < m_options.size(); i++)
else
{
if (m_options[i].level() == 0)
int currentOptionIndex = parentOptionIndex + 1;
while (currentOptionIndex < m_options.size() && m_options[currentOptionIndex].level() > m_options[parentNode->dataObject()].level())
{
m_zeroLevelRowToOptionIndex[m_zeroLevelRowCount] = i;
m_zeroLevelRowCount++;
m_optionsTreeData[i].parentModelIndex = QModelIndex();
}
else if (m_options[i].level() > 0)
{
// Compute parent model index
int childLevel = m_options[i].level();
int parentOptionIndex = i - 1;
while (parentOptionIndex > -1)
if (m_options[currentOptionIndex].level() == m_options[parentNode->dataObject()].level() + 1)
{
if (m_options[parentOptionIndex].level() == childLevel - 1)
{
int parentRow = 0;
TreeItemType* node = new TreeItemType(parentNode, -1, currentOptionIndex);
int parentLevelOptionIndex = parentOptionIndex - 1;
while (parentLevelOptionIndex > -1 && m_options[parentLevelOptionIndex].level() > childLevel - 2)
{
if (m_options[parentLevelOptionIndex].level() == childLevel - 1)
{
parentRow++;
}
parentLevelOptionIndex--;
}
m_optionsTreeData[i].parentModelIndex = createIndex(parentRow, 0, parentOptionIndex);
break;
}
parentOptionIndex--;
buildOptionItemTree(currentOptionIndex, node);
}
currentOptionIndex++;
}
int childCount = 0;
{
int parentLevel = m_options[i].level();
int currentOptionIndex = i + 1;
while (currentOptionIndex < m_options.size() && m_options[currentOptionIndex].level() > parentLevel)
{
if (m_options[currentOptionIndex].level() == parentLevel + 1)
{
childCount++;
}
currentOptionIndex++;
}
}
m_optionsTreeData[i].childCount = childCount;
}
}

View File

@ -37,6 +37,7 @@
#pragma once
#include "cafPdmUiFieldEditorHandle.h"
#include "cafUiTreeItem.h"
#include <QAbstractItemModel>
@ -50,16 +51,6 @@ class PdmOptionItemInfo;
class PdmUiFieldHandle;
//==================================================================================================
///
//==================================================================================================
class OptionItemTreeData
{
public:
int childCount;
QModelIndex parentModelIndex;
};
//==================================================================================================
///
//==================================================================================================
@ -68,13 +59,14 @@ class PdmUiTreeSelectionQModel : public QAbstractItemModel
Q_OBJECT
public:
explicit PdmUiTreeSelectionQModel(QObject *parent = 0);
~PdmUiTreeSelectionQModel();
void setOptions(caf::PdmUiFieldEditorHandle* field, const QList<caf::PdmOptionItemInfo>& options);
static int headingRole();
int optionItemCount() const;
const caf::PdmOptionItemInfo* optionItem(const QModelIndex &index) const;
int optionItemIndex(const QModelIndex& modelIndex) const;
std::vector<int> allSubItemIndices(int headingIndex) const;
void setCheckedStateForItems(const QModelIndexList& indices, bool checked);
int optionItemCount() const;
void setOptions(caf::PdmUiFieldEditorHandle* field, const QList<caf::PdmOptionItemInfo>& options);
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
@ -84,19 +76,18 @@ public:
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
signals:
void signalSelectionStateForIndexHasChanged(int index, bool isSelected);
private:
void computeOptionItemTreeData();
typedef caf::UiTreeItem<int> TreeItemType;
const caf::PdmOptionItemInfo* optionItem(const QModelIndex &index) const;
int optionIndex(const QModelIndex &index) const;
void buildOptionItemTree(int optionIndex, TreeItemType* parentNode);
private:
QList<caf::PdmOptionItemInfo> m_options;
caf::PdmUiFieldEditorHandle* m_uiFieldHandle;
std::vector<OptionItemTreeData> m_optionsTreeData;
int m_zeroLevelRowCount;
std::map<int, int> m_zeroLevelRowToOptionIndex;
TreeItemType* m_tree;
};