mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-24 07:16:53 -06:00
581 lines
20 KiB
C++
581 lines
20 KiB
C++
//##################################################################################################
|
|
//
|
|
// Custom Visualization Core library
|
|
//
|
|
// This library may be used under the terms of either the GNU General Public License or
|
|
// the GNU Lesser General Public License as follows:
|
|
//
|
|
// GNU General Public License Usage
|
|
// This library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
|
// for more details.
|
|
//
|
|
// GNU Lesser General Public License Usage
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation; either version 2.1 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
|
// for more details.
|
|
//
|
|
//##################################################################################################
|
|
|
|
|
|
#include "cafPdmUiTreeSelectionQModel.h"
|
|
|
|
#include "cafPdmObject.h"
|
|
#include "cafPdmUiCommandSystemProxy.h"
|
|
#include "cafPdmUiTreeViewQModel.h"
|
|
|
|
#include <QAbstractItemModel>
|
|
#include <QLabel>
|
|
#include <QTreeView>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <QDebug>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
caf::PdmUiTreeSelectionQModel::PdmUiTreeSelectionQModel(QObject *parent /*= 0*/)
|
|
: QAbstractItemModel(parent),
|
|
m_uiValueCache(nullptr)
|
|
{
|
|
m_uiFieldHandle = nullptr;
|
|
m_tree = nullptr;
|
|
m_singleSelectionMode = false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
caf::PdmUiTreeSelectionQModel::~PdmUiTreeSelectionQModel()
|
|
{
|
|
m_uiFieldHandle = nullptr;
|
|
|
|
delete m_tree;
|
|
m_tree = nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
int caf::PdmUiTreeSelectionQModel::headingRole()
|
|
{
|
|
return Qt::UserRole + 1;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
int caf::PdmUiTreeSelectionQModel::optionItemValueRole()
|
|
{
|
|
return Qt::UserRole + 2;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void caf::PdmUiTreeSelectionQModel::setCheckedStateForItems(const QModelIndexList& sourceModelIndices, bool checked)
|
|
{
|
|
if (!m_uiFieldHandle || !m_uiFieldHandle->uiField()) return;
|
|
|
|
std::set<unsigned int> selectedIndices;
|
|
{
|
|
QVariant fieldValue = m_uiFieldHandle->uiField()->uiValue();
|
|
QList<QVariant> fieldValueSelection = fieldValue.toList();
|
|
|
|
for (auto v : fieldValueSelection)
|
|
{
|
|
selectedIndices.insert(v.toUInt());
|
|
}
|
|
}
|
|
|
|
if (checked)
|
|
{
|
|
for (auto mi : sourceModelIndices)
|
|
{
|
|
const caf::PdmOptionItemInfo* optionItemInfo = optionItem(mi);
|
|
if (!optionItemInfo->isReadOnly())
|
|
{
|
|
selectedIndices.insert(static_cast<unsigned int>(optionIndex(mi)));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (auto mi : sourceModelIndices)
|
|
{
|
|
const caf::PdmOptionItemInfo* optionItemInfo = optionItem(mi);
|
|
if (!optionItemInfo->isReadOnly())
|
|
{
|
|
selectedIndices.erase(static_cast<unsigned int>(optionIndex(mi)));
|
|
}
|
|
}
|
|
}
|
|
|
|
QList<QVariant> fieldValueSelection;
|
|
for (auto v : selectedIndices)
|
|
{
|
|
fieldValueSelection.push_back(QVariant(v));
|
|
}
|
|
|
|
PdmUiCommandSystemProxy::instance()->setUiValueToField(m_uiFieldHandle->uiField(), fieldValueSelection);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void caf::PdmUiTreeSelectionQModel::enableSingleSelectionMode(bool enable)
|
|
{
|
|
m_singleSelectionMode = enable;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
int caf::PdmUiTreeSelectionQModel::optionItemCount() const
|
|
{
|
|
return m_options.size();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void caf::PdmUiTreeSelectionQModel::setOptions(caf::PdmUiFieldEditorHandle* field, const QList<caf::PdmOptionItemInfo>& options)
|
|
{
|
|
m_uiFieldHandle = field;
|
|
|
|
bool mustRebuildOptionItemTree = m_options.size() != options.size();
|
|
|
|
m_options = options;
|
|
|
|
if (mustRebuildOptionItemTree)
|
|
{
|
|
beginResetModel();
|
|
|
|
if (m_tree)
|
|
{
|
|
delete m_tree;
|
|
m_tree = nullptr;
|
|
}
|
|
|
|
m_tree = new TreeItemType(nullptr, -1, 0);
|
|
buildOptionItemTree(0, m_tree);
|
|
|
|
endResetModel();
|
|
}
|
|
else
|
|
{
|
|
// Notify changed for all items in the model as UI can change even if the option item count is identical
|
|
// It is possible to use beginResetModel and endResetModel, but this will also invalidate tree expand state
|
|
notifyChangedForAllModelIndices();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void caf::PdmUiTreeSelectionQModel::setUiValueCache(const QVariant* uiValuesCache)
|
|
{
|
|
m_uiValueCache = uiValuesCache;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void caf::PdmUiTreeSelectionQModel::resetUiValueCache()
|
|
{
|
|
m_uiValueCache = nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool caf::PdmUiTreeSelectionQModel::isReadOnly(const QModelIndex& index) const
|
|
{
|
|
return optionItem(index)->isReadOnly();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool caf::PdmUiTreeSelectionQModel::isChecked(const QModelIndex& index) const
|
|
{
|
|
return data(index, Qt::CheckStateRole).toBool();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Checks if this is a real tree with grand children or just a list of children.
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool caf::PdmUiTreeSelectionQModel::hasGrandChildren() const
|
|
{
|
|
return m_tree && m_tree->hasGrandChildren();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const caf::PdmOptionItemInfo* caf::PdmUiTreeSelectionQModel::optionItem(const QModelIndex &index) const
|
|
{
|
|
int opIndex = optionIndex(index);
|
|
|
|
return &m_options[opIndex];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
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;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
Qt::ItemFlags caf::PdmUiTreeSelectionQModel::flags(const QModelIndex &index) const
|
|
{
|
|
if (index.isValid())
|
|
{
|
|
const caf::PdmOptionItemInfo* optionItemInfo = optionItem(index);
|
|
|
|
if (!optionItemInfo->isHeading())
|
|
{
|
|
if (optionItemInfo->isReadOnly())
|
|
{
|
|
return QAbstractItemModel::flags(index)^Qt::ItemIsEnabled;
|
|
}
|
|
|
|
return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
|
|
}
|
|
}
|
|
|
|
return QAbstractItemModel::flags(index);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QModelIndex caf::PdmUiTreeSelectionQModel::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const
|
|
{
|
|
if (!hasIndex(row, column, parent))
|
|
return QModelIndex();
|
|
|
|
TreeItemType* parentItem;
|
|
|
|
if (!parent.isValid())
|
|
parentItem = m_tree;
|
|
else
|
|
parentItem = static_cast<TreeItemType*>(parent.internalPointer());
|
|
|
|
TreeItemType* childItem = parentItem->child(row);
|
|
if (childItem)
|
|
return createIndex(row, column, childItem);
|
|
else
|
|
return QModelIndex();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
int caf::PdmUiTreeSelectionQModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QModelIndex caf::PdmUiTreeSelectionQModel::parent(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
return QModelIndex();
|
|
|
|
TreeItemType* childItem = static_cast<TreeItemType*>(index.internalPointer());
|
|
TreeItemType* parentItem = childItem->parent();
|
|
|
|
if (parentItem == m_tree)
|
|
return QModelIndex();
|
|
|
|
return createIndex(parentItem->row(), 0, parentItem);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
int caf::PdmUiTreeSelectionQModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const
|
|
{
|
|
if (!m_tree) return 0;
|
|
|
|
if (parent.column() > 0)
|
|
return 0;
|
|
|
|
TreeItemType* parentItem;
|
|
if (!parent.isValid())
|
|
parentItem = m_tree;
|
|
else
|
|
parentItem = static_cast<TreeItemType*>(parent.internalPointer());
|
|
|
|
return parentItem->childCount();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QVariant caf::PdmUiTreeSelectionQModel::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
|
|
{
|
|
if (index.isValid())
|
|
{
|
|
const caf::PdmOptionItemInfo* optionItemInfo = optionItem(index);
|
|
|
|
if (role == Qt::DisplayRole)
|
|
{
|
|
return optionItemInfo->optionUiText();
|
|
}
|
|
else if (role == Qt::DecorationRole)
|
|
{
|
|
return optionItemInfo->icon();
|
|
}
|
|
else if (role == Qt::CheckStateRole && !optionItemInfo->isHeading())
|
|
{
|
|
if (m_uiFieldHandle && m_uiFieldHandle->uiField())
|
|
{
|
|
// Avoid calling the seriously heavy uiValue method if we have a temporary valid cache.
|
|
|
|
QVariant fieldValue = m_uiValueCache ? *m_uiValueCache : m_uiFieldHandle->uiField()->uiValue();
|
|
if (isSingleValueField(fieldValue))
|
|
{
|
|
int row = fieldValue.toInt();
|
|
|
|
if (row == optionIndex(index))
|
|
{
|
|
return Qt::Checked;
|
|
}
|
|
}
|
|
else if (isMultipleValueField(fieldValue))
|
|
{
|
|
QList<QVariant> valuesSelectedInField = fieldValue.toList();
|
|
|
|
int opIndex = optionIndex(index);
|
|
|
|
for (QVariant v : valuesSelectedInField)
|
|
{
|
|
int indexInField = v.toInt();
|
|
if (indexInField == opIndex)
|
|
{
|
|
return Qt::Checked;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Qt::Unchecked;
|
|
}
|
|
else if (role == Qt::FontRole)
|
|
{
|
|
if (optionItemInfo->isHeading())
|
|
{
|
|
QFont font;
|
|
font.setBold(true);
|
|
|
|
return font;
|
|
}
|
|
}
|
|
else if (role == headingRole())
|
|
{
|
|
return optionItemInfo->isHeading();
|
|
}
|
|
else if (role == optionItemValueRole())
|
|
{
|
|
QVariant v = optionItemInfo->value();
|
|
|
|
return v;
|
|
}
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool caf::PdmUiTreeSelectionQModel::setData(const QModelIndex &index, const QVariant &value, int role /*= Qt::EditRole*/)
|
|
{
|
|
if (!m_uiFieldHandle || !m_uiFieldHandle->uiField()) return false;
|
|
|
|
if (role == Qt::CheckStateRole)
|
|
{
|
|
QVariant fieldValue = m_uiFieldHandle->uiField()->uiValue();
|
|
if (isSingleValueField(fieldValue))
|
|
{
|
|
if (value.toBool() == true)
|
|
{
|
|
QVariant v = static_cast<unsigned int>(optionIndex(index));
|
|
PdmUiCommandSystemProxy::instance()->setUiValueToField(m_uiFieldHandle->uiField(), v);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
else if (isMultipleValueField(fieldValue))
|
|
{
|
|
std::vector<unsigned int> selectedIndices;
|
|
|
|
if (!m_singleSelectionMode)
|
|
{
|
|
QList<QVariant> fieldValueSelection = fieldValue.toList();
|
|
|
|
for (auto v : fieldValueSelection)
|
|
{
|
|
selectedIndices.push_back(v.toUInt());
|
|
}
|
|
}
|
|
|
|
bool setSelected = value.toBool();
|
|
|
|
// Do not allow empty selection in single selection mode
|
|
if (m_singleSelectionMode) setSelected = true;
|
|
|
|
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->uiField(), fieldValueSelection);
|
|
emit dataChanged(index, index);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void caf::PdmUiTreeSelectionQModel::buildOptionItemTree(int parentOptionIndex, TreeItemType* parentNode)
|
|
{
|
|
if (parentNode == m_tree)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int currentOptionIndex = parentOptionIndex + 1;
|
|
while (currentOptionIndex < m_options.size() && m_options[currentOptionIndex].level() > m_options[parentNode->dataObject()].level())
|
|
{
|
|
if (m_options[currentOptionIndex].level() == m_options[parentNode->dataObject()].level() + 1)
|
|
{
|
|
TreeItemType* node = new TreeItemType(parentNode, -1, currentOptionIndex);
|
|
|
|
buildOptionItemTree(currentOptionIndex, node);
|
|
}
|
|
currentOptionIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void caf::PdmUiTreeSelectionQModel::notifyChangedForAllModelIndices()
|
|
{
|
|
recursiveNotifyChildren(QModelIndex());
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void caf::PdmUiTreeSelectionQModel::recursiveNotifyChildren(const QModelIndex& index)
|
|
{
|
|
for (int r = 0; r < rowCount(index); r++)
|
|
{
|
|
QModelIndex mi = this->index(r, 0, index);
|
|
recursiveNotifyChildren(mi);
|
|
}
|
|
|
|
if (index.isValid())
|
|
{
|
|
emit dataChanged(index, index);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool caf::PdmUiTreeSelectionQModel::isSingleValueField(const QVariant& fieldValue)
|
|
{
|
|
if (fieldValue.type() == QVariant::Int || fieldValue.type() == QVariant::UInt)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool caf::PdmUiTreeSelectionQModel::isMultipleValueField(const QVariant& fieldValue)
|
|
{
|
|
if (fieldValue.type() == QVariant::List)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|