#1830 AppFwk : Add context menu to control state for multiple items

This commit is contained in:
Magne Sjaastad 2017-09-07 14:24:30 +02:00
parent a0a28fee36
commit 5994ef1393
5 changed files with 289 additions and 48 deletions

View File

@ -9,6 +9,7 @@ int main(int argc, char *argv[])
MainWindow window;
window.setWindowTitle("Ceetron Application Framework Test Application");
window.resize(1000, 810);
window.show();
return app.exec();

View File

@ -40,10 +40,9 @@
#include "cafPdmObject.h"
#include "cafPdmUiTreeSelectionQModel.h"
#include "cafQTreeViewStateSerializer.h"
#include <QTreeView>
#include <QLabel>
#include <QMenu>
#include <QTreeView>
namespace caf
@ -111,24 +110,202 @@ void PdmUiTreeSelectionEditor::configureAndUpdateUi(const QString& uiConfigName)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSelectionStateForIndex(int index, bool isSelected)
void PdmUiTreeSelectionEditor::slotSetSelectionStateForIndex(int index, bool setSelected)
{
unsigned int unsignedValue = static_cast<unsigned int>(index);
std::vector<int> indices;
indices.push_back(index);
QVariant fieldValue = field()->uiValue();
QList<QVariant> valuesSelectedInField = fieldValue.toList();
if (!isSelected)
{
valuesSelectedInField.removeAll(QVariant(unsignedValue));
setSelectionStateForIndices(indices, setSelected);
}
else
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::customMenuRequested(const QPoint& pos)
{
QMenu menu;
{
std::vector<int> items = selectedCheckableItems();
if (items.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);
}
}
}
{
std::vector<int> items = selectedHeaderItems();
if (items.size() > 0)
{
{
QAction* act = new QAction("Set Sub Items On", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSubItemsOn()));
menu.addAction(act);
}
{
QAction* act = new QAction("Set Sub Items Off", this);
connect(act, SIGNAL(triggered()), SLOT(slotSetSubItemsOff()));
menu.addAction(act);
}
}
}
if (menu.actions().size() > 0)
{
// Qt doc: QAbstractScrollArea and its subclasses that map the context menu event to coordinates of the viewport().
QPoint globalPos = m_treeView->viewport()->mapToGlobal(pos);
menu.exec(globalPos);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSelectedOn()
{
std::vector<int> items = selectedCheckableItems();
if (items.size() > 0)
{
setSelectionStateForIndices(items, true);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSelectedOff()
{
std::vector<int> items = selectedCheckableItems();
if (items.size() > 0)
{
setSelectionStateForIndices(items, false);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSubItemsOn()
{
caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast<caf::PdmUiTreeSelectionQModel*>(m_treeView->model());
std::vector<int> items = selectedHeaderItems();
for (auto i : items)
{
std::vector<int> children = treeSelectionQModel->allSubItemIndices(i);
setSelectionStateForIndices(children, true);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::slotSetSubItemsOff()
{
caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast<caf::PdmUiTreeSelectionQModel*>(m_treeView->model());
std::vector<int> items = selectedHeaderItems();
for (auto i : items)
{
std::vector<int> children = treeSelectionQModel->allSubItemIndices(i);
setSelectionStateForIndices(children, false);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> PdmUiTreeSelectionEditor::selectedCheckableItems() const
{
std::vector<int> items;
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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> PdmUiTreeSelectionEditor::selectedHeaderItems() const
{
std::vector<int> items;
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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::setSelectionStateForIndices(const std::vector<int>& indices, bool setSelected)
{
std::vector<unsigned int> selectedIndices;
{
QVariant fieldValue = field()->uiValue();
QList<QVariant> fieldValueSelection = fieldValue.toList();
for (auto v : fieldValueSelection)
{
selectedIndices.push_back(v.toUInt());
}
}
for (auto index : indices)
{
unsigned int unsignedIndex = static_cast<unsigned int>(index);
if (setSelected)
{
bool isIndexPresent = false;
for (QVariant v : valuesSelectedInField)
for (auto indexInField : selectedIndices)
{
unsigned int indexInField = v.toUInt();
if (indexInField == unsignedValue)
if (indexInField == unsignedIndex)
{
isIndexPresent = true;
}
@ -136,11 +313,22 @@ void PdmUiTreeSelectionEditor::slotSetSelectionStateForIndex(int index, bool isS
if (!isIndexPresent)
{
valuesSelectedInField.push_back(QVariant(unsignedValue));
selectedIndices.push_back(unsignedIndex);
}
}
else
{
selectedIndices.erase(std::remove(selectedIndices.begin(), selectedIndices.end(), unsignedIndex), selectedIndices.end());
}
}
this->setValueToField(valuesSelectedInField);
QList<QVariant> fieldValueSelection;
for (auto v : selectedIndices)
{
fieldValueSelection.push_back(QVariant(v));
}
this->setValueToField(fieldValueSelection);
}
//--------------------------------------------------------------------------------------------------
@ -151,6 +339,10 @@ QWidget* PdmUiTreeSelectionEditor::createEditorWidget(QWidget * parent)
m_treeView = new QTreeView(parent);
m_treeView->setHeaderHidden(true);
m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_treeView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint)));
return m_treeView;
}

View File

@ -63,7 +63,18 @@ protected:
virtual void configureAndUpdateUi(const QString& uiConfigName);
private slots:
void slotSetSelectionStateForIndex(int index, bool isSelected);
void slotSetSelectionStateForIndex(int index, bool setSelected);
void customMenuRequested(const QPoint& pos);
void slotSetSelectedOn();
void slotSetSelectedOff();
void slotSetSubItemsOn();
void slotSetSubItemsOff();
private:
std::vector<int> selectedCheckableItems() const;
std::vector<int> selectedHeaderItems() const;
void setSelectionStateForIndices(const std::vector<int>& indices, bool setSelected);
private:
QPointer<QTreeView> m_treeView;

View File

@ -83,6 +83,21 @@ int caf::PdmUiTreeSelectionQModel::optionItemCount() const
return m_options.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const caf::PdmOptionItemInfo* caf::PdmUiTreeSelectionQModel::optionItem(const QModelIndex &index) const
{
if (index.isValid())
{
int opIndex = optionItemIndex(index);
return &(m_options[opIndex]);
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -90,9 +105,9 @@ Qt::ItemFlags caf::PdmUiTreeSelectionQModel::flags(const QModelIndex &index) con
{
if (index.isValid())
{
int optionItemIndex = toOptionItemIndex(index);
int opIndex = optionItemIndex(index);
if (!m_options[optionItemIndex].isHeading())
if (!m_options[opIndex].isHeading())
{
return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
}
@ -109,20 +124,20 @@ QModelIndex caf::PdmUiTreeSelectionQModel::index(int row, int column, const QMod
if (!hasIndex(row, column, parent))
return QModelIndex();
int optionItemIndex = -1;
int opIndex = -1;
if (parent.isValid())
{
optionItemIndex = toOptionItemIndex(parent) + row + 1;
opIndex = optionItemIndex(parent) + row + 1;
}
else
{
optionItemIndex = m_zeroLevelRowToOptionIndex.at(row);
opIndex = m_zeroLevelRowToOptionIndex.at(row);
}
CAF_ASSERT(optionItemIndex > -1);
CAF_ASSERT(optionItemIndex < m_options.size());
CAF_ASSERT(opIndex > -1);
CAF_ASSERT(opIndex < m_options.size());
return createIndex(row, column, optionItemIndex);
return createIndex(row, column, opIndex);
}
//--------------------------------------------------------------------------------------------------
@ -141,7 +156,7 @@ QModelIndex caf::PdmUiTreeSelectionQModel::parent(const QModelIndex &child) cons
if (!child.isValid())
return QModelIndex();
return m_optionsTreeData[toOptionItemIndex(child)].parentModelIndex;
return m_optionsTreeData[optionItemIndex(child)].parentModelIndex;
}
//--------------------------------------------------------------------------------------------------
@ -154,7 +169,7 @@ int caf::PdmUiTreeSelectionQModel::rowCount(const QModelIndex &parent /*= QModel
return m_zeroLevelRowCount;
}
return m_optionsTreeData[toOptionItemIndex(parent)].childCount;
return m_optionsTreeData[optionItemIndex(parent)].childCount;
}
//--------------------------------------------------------------------------------------------------
@ -166,13 +181,13 @@ QVariant caf::PdmUiTreeSelectionQModel::data(const QModelIndex &index, int role
{
CAF_ASSERT(index.internalId() < m_options.size());
int optionItemIndex = toOptionItemIndex(index);
int opIndex = optionItemIndex(index);
if (role == Qt::DisplayRole)
{
return m_options[optionItemIndex].optionUiText();
return m_options[opIndex].optionUiText();
}
else if (role == Qt::CheckStateRole && !m_options[optionItemIndex].isHeading())
else if (role == Qt::CheckStateRole && !m_options[opIndex].isHeading())
{
CAF_ASSERT(m_uiFieldHandle);
@ -182,7 +197,7 @@ QVariant caf::PdmUiTreeSelectionQModel::data(const QModelIndex &index, int role
for (QVariant v : valuesSelectedInField)
{
int indexInField = v.toInt();
if (indexInField == optionItemIndex)
if (indexInField == opIndex)
{
return Qt::Checked;
}
@ -204,7 +219,7 @@ bool caf::PdmUiTreeSelectionQModel::setData(const QModelIndex &index, const QVar
{
bool isSelected = value.toBool();
emit signalSelectionStateForIndexHasChanged(toOptionItemIndex(index), isSelected);
emit signalSelectionStateForIndexHasChanged(optionItemIndex(index), isSelected);
return true;
}
@ -212,6 +227,36 @@ bool caf::PdmUiTreeSelectionQModel::setData(const QModelIndex &index, const QVar
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int caf::PdmUiTreeSelectionQModel::optionItemIndex(const QModelIndex& modelIndex) const
{
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)
{
children.push_back(currentIndex);
currentIndex++;
}
return children;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -288,13 +333,3 @@ void caf::PdmUiTreeSelectionQModel::computeOptionItemTreeData()
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int caf::PdmUiTreeSelectionQModel::toOptionItemIndex(const QModelIndex& modelIndex) const
{
CAF_ASSERT(modelIndex.isValid());
CAF_ASSERT(modelIndex.internalId() < m_options.size());
return modelIndex.internalId();
}

View File

@ -73,6 +73,9 @@ public:
void setOptions(caf::PdmUiFieldEditorHandle* field, const QList<caf::PdmOptionItemInfo>& options);
int optionItemCount() const;
const caf::PdmOptionItemInfo* optionItem(const QModelIndex &index) const;
int optionItemIndex(const QModelIndex& modelIndex) const;
std::vector<int> allSubItemIndices(int headingIndex) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
@ -87,7 +90,6 @@ signals:
private:
void computeOptionItemTreeData();
int toOptionItemIndex(const QModelIndex& modelIndex) const;
private:
QList<caf::PdmOptionItemInfo> m_options;