(#1883) AppFwk : Refactor of WidgetBasedObjectEditor and friends

This commit is contained in:
Magne Sjaastad 2017-09-12 10:18:40 +02:00
parent 7f72dcbb4a
commit 9d7dcefc78
7 changed files with 153 additions and 191 deletions

View File

@ -69,7 +69,9 @@ public:
const PdmObjectHandle* pdmObject() const;
protected:
/// Supposed to create the top level widget of the editor with a suitable QLayout
virtual QWidget* createWidget(QWidget* parent) = 0;
virtual void cleanupBeforeSettingPdmObject() {};
protected:

View File

@ -93,26 +93,25 @@ void CustomObjectEditor::defineGridLayout(int rowCount, int columnCount)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void CustomObjectEditor::addWidget(QWidget* w, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment /*= 0*/)
void CustomObjectEditor::addWidget(QWidget* widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment /*= 0*/)
{
CAF_ASSERT(isAreaAvailable(row, column, rowSpan, columnSpan));
m_customWidgetAreas.push_back(WidgetCellIds(widget, CustomObjectEditor::cellIds(row, column, rowSpan, columnSpan)));
// The ownership of item is transferred to the layout, and it's the layout's responsibility to delete it.
m_customWidgetAreas.push_back(WidgetCellIds(w, CustomObjectEditor::cellIds(row, column, rowSpan, columnSpan)));
m_layout->addWidget(w, row, column, rowSpan, columnSpan, alignment);
m_layout->addWidget(widget, row, column, rowSpan, columnSpan, alignment);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void CustomObjectEditor::removeWidget(QWidget* w)
void CustomObjectEditor::removeWidget(QWidget* widget)
{
size_t indexToRemove = size_t(-1);
for (size_t i = 0; i < m_customWidgetAreas.size(); i++)
{
if (w == m_customWidgetAreas[i].m_customWidget)
if (widget == m_customWidgetAreas[i].m_customWidget)
{
indexToRemove = i;
break;
@ -121,7 +120,7 @@ void CustomObjectEditor::removeWidget(QWidget* w)
if (indexToRemove != size_t(-1))
{
m_layout->removeWidget(w);
m_layout->removeWidget(widget);
m_customWidgetAreas.erase(m_customWidgetAreas.begin() + indexToRemove);
}
@ -140,50 +139,40 @@ void CustomObjectEditor::addBlankCell(int row, int column)
//--------------------------------------------------------------------------------------------------
QWidget* CustomObjectEditor::createWidget(QWidget* parent)
{
QWidget* m_mainWidget = PdmUiWidgetBasedObjectEditor::createWidget(parent);
QWidget* widget = new QWidget(parent);
m_layout = new QGridLayout();
m_layout->setContentsMargins(0, 0, 0, 0);
m_mainWidget->setLayout(m_layout);
widget->setLayout(m_layout);
return m_mainWidget;
return widget;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void CustomObjectEditor::setupFieldsAndGroups(const std::vector<PdmUiItem *>& uiItems, QWidget* parent, const QString& uiConfigName)
{
setupTopLevelGroupsInGridLayout(uiItems, parent, m_layout, uiConfigName);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void CustomObjectEditor::setupTopLevelGroupsInGridLayout(const std::vector<PdmUiItem*>& uiItems, QWidget* parent, QGridLayout* parentLayout, const QString& uiConfigName)
void CustomObjectEditor::recursivelyConfigureAndUpdateTopLevelUiItems(const std::vector<PdmUiItem*>& topLevelUiItems, const QString& uiConfigName)
{
resetCellId();
QWidget* previousTabOrderWidget = NULL;
for (size_t i = 0; i < uiItems.size(); ++i)
for (size_t i = 0; i < topLevelUiItems.size(); ++i)
{
if (uiItems[i]->isUiHidden(uiConfigName)) continue;
if (topLevelUiItems[i]->isUiHidden(uiConfigName)) continue;
if (uiItems[i]->isUiGroup())
if (topLevelUiItems[i]->isUiGroup())
{
PdmUiGroup* group = static_cast<PdmUiGroup*>(uiItems[i]);
QMinimizePanel* groupBox = findOrCreateGroupBox(group, parent, uiConfigName);
PdmUiGroup* group = static_cast<PdmUiGroup*>(topLevelUiItems[i]);
QMinimizePanel* groupBox = findOrCreateGroupBox(this->widget(), group, uiConfigName);
/// Insert the group box at the correct position of the parent layout
int nextCellId = getNextAvailableCellId();
std::pair<int, int> rowCol = rowAndColumn(nextCellId);
parentLayout->addWidget(groupBox, rowCol.first, rowCol.second, 1, 1);
QGridLayout* groupBoxLayout = this->groupBoxLayout(groupBox);
m_layout->addWidget(groupBox, rowCol.first, rowCol.second, 1, 1);
const std::vector<PdmUiItem*>& groupChildren = group->uiItems();
recursiveSetupFieldsAndGroups(groupChildren, groupBox->contentFrame(), groupBoxLayout, uiConfigName);
recursivelyConfigureAndUpdateUiItemsInGridLayoutColumn(groupChildren, groupBox->contentFrame(), uiConfigName);
}
// NB! Only groups at top level are handled, fields at top level are not added to layout

View File

@ -71,15 +71,15 @@ public:
void defineGridLayout(int rowCount, int columnCount);
// See QGridLayout::addWidget
void addWidget(QWidget* w, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = 0);
void removeWidget(QWidget* w);
void addWidget(QWidget* widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = 0);
void removeWidget(QWidget* widget);
void addBlankCell(int row, int column);
private:
virtual QWidget* createWidget(QWidget* parent) override;
virtual void setupFieldsAndGroups(const std::vector<PdmUiItem *>& uiItems, QWidget* parent, const QString& uiConfigName) override;
void setupTopLevelGroupsInGridLayout(const std::vector<PdmUiItem*>& uiItems, QWidget* parent, QGridLayout* parentLayout, const QString& uiConfigName);
virtual void recursivelyConfigureAndUpdateTopLevelUiItems(const std::vector<PdmUiItem*>& topLevelUiItems,
const QString& uiConfigName) override;
bool isAreaAvailable(int row, int column, int rowSpan, int columnSpan) const;
bool isCellIdAvailable(int cellId) const;

View File

@ -38,21 +38,12 @@
#include "cafPdmProxyValueField.h"
#include "cafPdmUiCheckBoxEditor.h"
#include "cafPdmUiComboBoxEditor.h"
#include "cafPdmUiDateEditor.h"
#include "cafPdmUiFieldEditorHandle.h"
#include "cafPdmUiFieldHandle.h"
#include "cafPdmUiGroup.h"
#include "cafPdmUiLineEditor.h"
#include "cafPdmUiListEditor.h"
#include "QMinimizePanel.h"
#include <QDate>
#include <QDateTime>
#include <QGridLayout>
#include <QWidget>
namespace caf
{
@ -93,11 +84,11 @@ PdmUiDefaultObjectEditor::~PdmUiDefaultObjectEditor()
//--------------------------------------------------------------------------------------------------
QWidget* PdmUiDefaultObjectEditor::createWidget(QWidget* parent)
{
QWidget* widget = PdmUiWidgetBasedObjectEditor::createWidget(parent);
QWidget* widget = new QWidget(parent);
m_layout = new QGridLayout();
m_layout->setContentsMargins(0, 0, 0, 0);
widget->setLayout(m_layout);
QGridLayout* gridLayout = new QGridLayout();
gridLayout->setContentsMargins(0, 0, 0, 0);
widget->setLayout(gridLayout);
return widget;
}
@ -105,9 +96,11 @@ QWidget* PdmUiDefaultObjectEditor::createWidget(QWidget* parent)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiDefaultObjectEditor::setupFieldsAndGroups(const std::vector<PdmUiItem *>& uiItems, QWidget* parent, const QString& uiConfigName)
void PdmUiDefaultObjectEditor::recursivelyConfigureAndUpdateTopLevelUiItems(const std::vector<PdmUiItem*>& topLevelUiItems, const QString& uiConfigName)
{
recursiveSetupFieldsAndGroups(uiItems, parent, m_layout, uiConfigName);
CAF_ASSERT(this->widget());
recursivelyConfigureAndUpdateUiItemsInGridLayoutColumn(topLevelUiItems, this->widget(), uiConfigName);
}
} // end namespace caf

View File

@ -53,7 +53,7 @@ class PdmUiGroup;
//==================================================================================================
/// The default editor for PdmObjects. Manages the field editors in a gridlayout vertically
/// The default editor for PdmObjects. Manages the field editors in a grid layout vertically
//==================================================================================================
class PdmUiDefaultObjectEditor : public PdmUiWidgetBasedObjectEditor
{
@ -63,11 +63,10 @@ public:
~PdmUiDefaultObjectEditor();
private:
virtual QWidget* createWidget(QWidget* parent) override;
virtual void setupFieldsAndGroups(const std::vector<PdmUiItem *>& uiItems, QWidget* parent, const QString& uiConfigName) override;
virtual QWidget* createWidget(QWidget* parent) override;
virtual void recursivelyConfigureAndUpdateTopLevelUiItems(const std::vector<PdmUiItem*>& topLevelUiItems,
const QString& uiConfigName) override;
private:
QPointer<QGridLayout> m_layout;
};

View File

@ -71,11 +71,109 @@ caf::PdmUiWidgetBasedObjectEditor::~PdmUiWidgetBasedObjectEditor()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* caf::PdmUiWidgetBasedObjectEditor::createWidget(QWidget* parent)
void caf::PdmUiWidgetBasedObjectEditor::recursivelyConfigureAndUpdateUiItemsInGridLayoutColumn(const std::vector<PdmUiItem*>& uiItems, QWidget* containerWidgetWithGridLayout, const QString& uiConfigName)
{
m_mainWidget = new QWidget(parent);
CAF_ASSERT(containerWidgetWithGridLayout);
return m_mainWidget;
int currentRowIndex = 0;
QWidget* previousTabOrderWidget = NULL;
// Currently, only QGridLayout is supported
QGridLayout* parentLayout = dynamic_cast<QGridLayout*>(containerWidgetWithGridLayout->layout());
CAF_ASSERT(parentLayout);
for (size_t i = 0; i < uiItems.size(); ++i)
{
if (uiItems[i]->isUiHidden(uiConfigName)) continue;
if (uiItems[i]->isUiGroup())
{
PdmUiGroup* group = static_cast<PdmUiGroup*>(uiItems[i]);
QMinimizePanel* groupBox = findOrCreateGroupBox(containerWidgetWithGridLayout, group, uiConfigName);
/// Insert the group box at the correct position of the parent layout
parentLayout->addWidget(groupBox, currentRowIndex, 0, 1, 2);
const std::vector<PdmUiItem*>& groupChildren = group->uiItems();
recursivelyConfigureAndUpdateUiItemsInGridLayoutColumn(groupChildren, groupBox->contentFrame(), uiConfigName);
currentRowIndex++;
}
else
{
PdmUiFieldHandle* field = dynamic_cast<PdmUiFieldHandle*>(uiItems[i]);
PdmUiFieldEditorHandle* fieldEditor = findOrCreateFieldEditor(containerWidgetWithGridLayout, field, uiConfigName);
if (fieldEditor)
{
fieldEditor->setField(field);
// Place the widget(s) into the correct parent and layout
QWidget* fieldCombinedWidget = fieldEditor->combinedWidget();
if (fieldCombinedWidget)
{
fieldCombinedWidget->setParent(containerWidgetWithGridLayout);
parentLayout->addWidget(fieldCombinedWidget, currentRowIndex, 0, 1, 2);
}
else
{
PdmUiItemInfo::LabelPosType labelPos = field->uiLabelPosition(uiConfigName);
bool labelOnTop = (labelPos == PdmUiItemInfo::TOP);
bool editorSpanBoth = labelOnTop;
QWidget* fieldEditorWidget = fieldEditor->editorWidget();
if (labelPos != PdmUiItemInfo::HIDDEN)
{
QWidget* fieldLabelWidget = fieldEditor->labelWidget();
if (fieldLabelWidget)
{
fieldLabelWidget->setParent(containerWidgetWithGridLayout);
// Label widget will span two columns if aligned on top
int colSpan = labelOnTop ? 2 : 1;
// If the label is on the side, and the editor can expand vertically, allign the label with the top edge of the editor
if (!labelOnTop && (fieldEditorWidget->sizePolicy().verticalPolicy() & QSizePolicy::ExpandFlag))
parentLayout->addWidget(fieldLabelWidget, currentRowIndex, 0, 1, colSpan, Qt::AlignTop);
else
parentLayout->addWidget(fieldLabelWidget, currentRowIndex, 0, 1, colSpan, Qt::AlignVCenter);
fieldLabelWidget->show();
if (labelOnTop) currentRowIndex++;
}
}
else
{
QWidget* fieldLabelWidget = fieldEditor->labelWidget();
if (fieldLabelWidget) fieldLabelWidget->hide();
editorSpanBoth = true; // To span both columns when there is no label
}
if (fieldEditorWidget)
{
fieldEditorWidget->setParent(containerWidgetWithGridLayout); // To make sure this widget has the current group box as parent.
// Label widget will span two columns if aligned on top
int colSpan = editorSpanBoth ? 2 : 1;
int colIndex = editorSpanBoth ? 0 : 1;
parentLayout->addWidget(fieldEditorWidget, currentRowIndex, colIndex, 1, colSpan, Qt::AlignTop);
if (previousTabOrderWidget) QWidget::setTabOrder(previousTabOrderWidget, fieldEditorWidget);
previousTabOrderWidget = fieldEditorWidget;
}
}
fieldEditor->updateUi(uiConfigName);
currentRowIndex++;
}
}
}
}
//--------------------------------------------------------------------------------------------------
@ -103,7 +201,7 @@ bool caf::PdmUiWidgetBasedObjectEditor::isUiGroupExpanded(const PdmUiGroup* uiGr
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QMinimizePanel* caf::PdmUiWidgetBasedObjectEditor::findOrCreateGroupBox(PdmUiGroup* group, QWidget* parent, const QString& uiConfigName)
QMinimizePanel* caf::PdmUiWidgetBasedObjectEditor::findOrCreateGroupBox(QWidget* parent, PdmUiGroup* group, const QString& uiConfigName)
{
QString groupBoxKey = group->keyword();
QMinimizePanel* groupBox = NULL;
@ -142,118 +240,6 @@ QMinimizePanel* caf::PdmUiWidgetBasedObjectEditor::findOrCreateGroupBox(PdmUiGro
return groupBox;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QGridLayout* caf::PdmUiWidgetBasedObjectEditor::groupBoxLayout(QMinimizePanel* groupBox)
{
return dynamic_cast<QGridLayout*>(groupBox->contentFrame()->layout());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void caf::PdmUiWidgetBasedObjectEditor::recursiveSetupFieldsAndGroups(const std::vector<PdmUiItem*>& uiItems, QWidget* parent, QGridLayout* parentLayout, const QString& uiConfigName)
{
int currentRowIndex = 0;
QWidget* previousTabOrderWidget = NULL;
for (size_t i = 0; i < uiItems.size(); ++i)
{
if (uiItems[i]->isUiHidden(uiConfigName)) continue;
if (uiItems[i]->isUiGroup())
{
PdmUiGroup* group = static_cast<PdmUiGroup*>(uiItems[i]);
QMinimizePanel* groupBox = findOrCreateGroupBox(group, parent, uiConfigName);
/// Insert the group box at the correct position of the parent layout
parentLayout->addWidget(groupBox, currentRowIndex, 0, 1, 2);
QGridLayout* groupBoxLayout = this->groupBoxLayout(groupBox);
const std::vector<PdmUiItem*>& groupChildren = group->uiItems();
recursiveSetupFieldsAndGroups(groupChildren, groupBox->contentFrame(), groupBoxLayout, uiConfigName);
currentRowIndex++;
}
else
{
PdmUiFieldHandle* field = dynamic_cast<PdmUiFieldHandle*>(uiItems[i]);
PdmUiFieldEditorHandle* fieldEditor = findOrCreateFieldEditor(parent, field, uiConfigName);
if (fieldEditor)
{
fieldEditor->setField(field);
// Place the widget(s) into the correct parent and layout
QWidget* fieldCombinedWidget = fieldEditor->combinedWidget();
if (fieldCombinedWidget)
{
fieldCombinedWidget->setParent(parent);
parentLayout->addWidget(fieldCombinedWidget, currentRowIndex, 0, 1, 2);
}
else
{
PdmUiItemInfo::LabelPosType labelPos = field->uiLabelPosition(uiConfigName);
bool labelOnTop = (labelPos == PdmUiItemInfo::TOP);
bool editorSpanBoth = labelOnTop;
QWidget* fieldEditorWidget = fieldEditor->editorWidget();
if (labelPos != PdmUiItemInfo::HIDDEN)
{
QWidget* fieldLabelWidget = fieldEditor->labelWidget();
if (fieldLabelWidget)
{
fieldLabelWidget->setParent(parent);
// Label widget will span two columns if aligned on top
int colSpan = labelOnTop ? 2 : 1;
// If the label is on the side, and the editor can expand vertically, allign the label with the top edge of the editor
if (!labelOnTop && (fieldEditorWidget->sizePolicy().verticalPolicy() & QSizePolicy::ExpandFlag))
parentLayout->addWidget(fieldLabelWidget, currentRowIndex, 0, 1, colSpan, Qt::AlignTop);
else
parentLayout->addWidget(fieldLabelWidget, currentRowIndex, 0, 1, colSpan, Qt::AlignVCenter);
fieldLabelWidget->show();
if (labelOnTop) currentRowIndex++;
}
}
else
{
QWidget* fieldLabelWidget = fieldEditor->labelWidget();
if (fieldLabelWidget) fieldLabelWidget->hide();
editorSpanBoth = true; // To span both columns when there is no label
}
if (fieldEditorWidget)
{
fieldEditorWidget->setParent(parent); // To make sure this widget has the current group box as parent.
// Label widget will span two columns if aligned on top
int colSpan = editorSpanBoth ? 2 : 1;
int colIndex = editorSpanBoth ? 0 : 1;
parentLayout->addWidget(fieldEditorWidget, currentRowIndex, colIndex, 1, colSpan, Qt::AlignTop);
if (previousTabOrderWidget) QWidget::setTabOrder(previousTabOrderWidget, fieldEditorWidget);
previousTabOrderWidget = fieldEditorWidget;
}
}
fieldEditor->updateUi(uiConfigName);
currentRowIndex++;
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -359,17 +345,7 @@ void caf::PdmUiWidgetBasedObjectEditor::configureAndUpdateUi(const QString& uiCo
m_newGroupBoxes.clear();
const std::vector<PdmUiItem*>& uiItems = config.uiItems();
// TODO: Review that is it not breaking anything to have fields with identical keywords
// {
// std::set<QString> fieldKeywordNames;
// std::set<QString> groupNames;
//
// recursiveVerifyUniqueNames(uiItems, uiConfigName, &fieldKeywordNames, &groupNames);
// }
//recursiveSetupFieldsAndGroups(uiItems, m_mainWidget, m_layout, uiConfigName);
setupFieldsAndGroups(uiItems, m_mainWidget, uiConfigName);
recursivelyConfigureAndUpdateTopLevelUiItems(uiItems, uiConfigName);
// Remove all fieldViews not mentioned by the configuration from the layout

View File

@ -64,29 +64,32 @@ public:
~PdmUiWidgetBasedObjectEditor();
protected:
virtual void setupFieldsAndGroups(const std::vector<PdmUiItem*>& uiItems, QWidget* parent, const QString& uiConfigName) = 0;
virtual QWidget* createWidget(QWidget* parent) override;
/// When overriding this function, use findOrCreateGroupBox() or findOrCreateFieldEditor() for detailed control
/// Use recursivelyConfigureAndUpdateUiItemsInGridLayoutColumn() for automatic layout of group and field widgets
virtual void recursivelyConfigureAndUpdateTopLevelUiItems(const std::vector<PdmUiItem*>& topLevelUiItems,
const QString& uiConfigName) = 0;
bool isUiGroupExpanded(const PdmUiGroup* uiGroup) const;
QMinimizePanel* findOrCreateGroupBox(PdmUiGroup* group, QWidget* parent, const QString& uiConfigName);
PdmUiFieldEditorHandle* findOrCreateFieldEditor(QWidget* parent, PdmUiFieldHandle* field, const QString& uiConfigName);
void recursivelyConfigureAndUpdateUiItemsInGridLayoutColumn(const std::vector<PdmUiItem*>& uiItems,
QWidget* containerWidgetWithGridLayout,
const QString& uiConfigName);
static QGridLayout* groupBoxLayout(QMinimizePanel* groupBox);
void recursiveSetupFieldsAndGroups(const std::vector<PdmUiItem*>& uiItems, QWidget* parent, QGridLayout* parentLayout, const QString& uiConfigName);
QMinimizePanel* findOrCreateGroupBox(QWidget* parent, PdmUiGroup* group, const QString& uiConfigName);
PdmUiFieldEditorHandle* findOrCreateFieldEditor(QWidget* parent, PdmUiFieldHandle* field, const QString& uiConfigName);
private slots:
void groupBoxExpandedStateToggled(bool isExpanded);
private:
bool isUiGroupExpanded(const PdmUiGroup* uiGroup) const;
virtual void cleanupBeforeSettingPdmObject() override;
virtual void configureAndUpdateUi(const QString& uiConfigName) override;
static void recursiveVerifyUniqueNames(const std::vector<PdmUiItem*>& uiItems, const QString& uiConfigName, std::set<QString>* fieldKeywordNames, std::set<QString>* groupNames);
static void recursiveVerifyUniqueNames(const std::vector<PdmUiItem*>& uiItems,
const QString& uiConfigName,
std::set<QString>* fieldKeywordNames,
std::set<QString>* groupNames);
private:
QPointer<QWidget> m_mainWidget;
std::map<PdmFieldHandle*, PdmUiFieldEditorHandle*> m_fieldViews;
std::map<QString, QPointer<QMinimizePanel> > m_groupBoxes;
std::map<QString, QPointer<QMinimizePanel> > m_newGroupBoxes; ///< used temporarily to store the new(complete) set of group boxes