diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/Main.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/Main.cpp index 5fe2f4f22c..07e435c16d 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/Main.cpp +++ b/Fwk/AppFwk/cafTests/cafTestApplication/Main.cpp @@ -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(); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.cpp index 6a1f6a02b0..666b662960 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.cpp @@ -40,10 +40,9 @@ #include "cafPdmObject.h" #include "cafPdmUiTreeSelectionQModel.h" -#include "cafQTreeViewStateSerializer.h" - -#include #include +#include +#include namespace caf @@ -111,36 +110,225 @@ 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(index); + std::vector indices; + indices.push_back(index); - QVariant fieldValue = field()->uiValue(); - QList valuesSelectedInField = fieldValue.toList(); + setSelectionStateForIndices(indices, setSelected); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeSelectionEditor::customMenuRequested(const QPoint& pos) +{ + QMenu menu; - if (!isSelected) { - valuesSelectedInField.removeAll(QVariant(unsignedValue)); - } - else - { - bool isIndexPresent = false; - for (QVariant v : valuesSelectedInField) + std::vector items = selectedCheckableItems(); + if (items.size() > 0) { - unsigned int indexInField = v.toUInt(); - if (indexInField == unsignedValue) { - isIndexPresent = true; + 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); } } + } - if (!isIndexPresent) + { + std::vector items = selectedHeaderItems(); + if (items.size() > 0) { - valuesSelectedInField.push_back(QVariant(unsignedValue)); + { + 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); + } } } - this->setValueToField(valuesSelectedInField); + 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 items = selectedCheckableItems(); + if (items.size() > 0) + { + setSelectionStateForIndices(items, true); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeSelectionEditor::slotSetSelectedOff() +{ + std::vector items = selectedCheckableItems(); + if (items.size() > 0) + { + setSelectionStateForIndices(items, false); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeSelectionEditor::slotSetSubItemsOn() +{ + caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast(m_treeView->model()); + + std::vector items = selectedHeaderItems(); + for (auto i : items) + { + std::vector children = treeSelectionQModel->allSubItemIndices(i); + + setSelectionStateForIndices(children, true); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeSelectionEditor::slotSetSubItemsOff() +{ + caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast(m_treeView->model()); + + std::vector items = selectedHeaderItems(); + for (auto i : items) + { + std::vector children = treeSelectionQModel->allSubItemIndices(i); + + setSelectionStateForIndices(children, false); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector PdmUiTreeSelectionEditor::selectedCheckableItems() const +{ + std::vector items; + + caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast(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 PdmUiTreeSelectionEditor::selectedHeaderItems() const +{ + std::vector items; + + caf::PdmUiTreeSelectionQModel* treeSelectionQModel = dynamic_cast(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& indices, bool setSelected) +{ + std::vector selectedIndices; + { + QVariant fieldValue = field()->uiValue(); + QList fieldValueSelection = fieldValue.toList(); + + for (auto v : fieldValueSelection) + { + selectedIndices.push_back(v.toUInt()); + } + } + + for (auto index : indices) + { + unsigned int unsignedIndex = static_cast(index); + + if (setSelected) + { + bool isIndexPresent = false; + for (auto indexInField : selectedIndices) + { + if (indexInField == unsignedIndex) + { + isIndexPresent = true; + } + } + + if (!isIndexPresent) + { + selectedIndices.push_back(unsignedIndex); + } + } + else + { + selectedIndices.erase(std::remove(selectedIndices.begin(), selectedIndices.end(), unsignedIndex), selectedIndices.end()); + } + } + + QList 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; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.h index 42f25f4379..64bc1d83e8 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.h @@ -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 selectedCheckableItems() const; + std::vector selectedHeaderItems() const; + void setSelectionStateForIndices(const std::vector& indices, bool setSelected); private: QPointer m_treeView; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.cpp index e873740d3d..2d89f88825 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.cpp @@ -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 caf::PdmUiTreeSelectionQModel::allSubItemIndices(int headingIndex) const +{ + std::vector 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(); -} diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h index f4f7b1fece..d5ccc6d615 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h @@ -72,7 +72,10 @@ public: void setOptions(caf::PdmUiFieldEditorHandle* field, const QList& options); - int optionItemCount() const; + int optionItemCount() const; + const caf::PdmOptionItemInfo* optionItem(const QModelIndex &index) const; + int optionItemIndex(const QModelIndex& modelIndex) const; + std::vector 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 m_options;