1
0
Fork 0
libreoffice/vcl/qt5/QtBuilder.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

730 lines
25 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <QtBuilder.hxx>
#include <QtDoubleSpinBox.hxx>
#include <QtExpander.hxx>
#include <QtInstanceLinkButton.hxx>
#include <QtInstanceMessageDialog.hxx>
#include <QtInstanceNotebook.hxx>
#include <QtTools.hxx>
#include <rtl/ustrbuf.hxx>
#include <vcl/qt/QtUtils.hxx>
#include <QtGui/QStandardItemModel>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDialog>
#include <QtWidgets/QDialogButtonBox>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QLayout>
#include <QtWidgets/QPlainTextEdit>
#include <QtWidgets/QProgressBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QRadioButton>
#include <QtWidgets/QScrollArea>
#include <QtWidgets/QTabWidget>
#include <QtWidgets/QTreeView>
namespace
{
QString convertAccelerator(const OUString& rText)
{
// preserve literal '&'s and use '&' instead of '_' for the accelerator
return toQString(rText.replaceAll("&", "&&").replace('_', '&'));
}
}
QtBuilder::QtBuilder(QObject* pParent, std::u16string_view sUIRoot, const OUString& rUIFile)
: WidgetBuilder(sUIRoot, rUIFile, false)
{
processUIFile(pParent);
}
QtBuilder::~QtBuilder() {}
QObject* QtBuilder::get_by_name(std::u16string_view sID)
{
for (auto const& child : m_aChildren)
{
if (child.m_sID == sID)
return child.m_pWindow;
}
return nullptr;
}
void QtBuilder::insertComboBoxOrListBoxItems(QObject* pObject, stringmap& rMap,
const std::vector<ComboBoxTextItem>& rItems)
{
if (QComboBox* pComboBox = qobject_cast<QComboBox*>(pObject))
{
for (const ComboBoxTextItem& rItem : rItems)
{
QVariant aUserData;
if (!rItem.m_sId.isEmpty())
aUserData = QVariant::fromValue(toQString(rItem.m_sId));
pComboBox->addItem(toQString(rItem.m_sItem), aUserData);
}
const int nActiveId = BuilderBase::extractActive(rMap);
pComboBox->setCurrentIndex(nActiveId);
return;
}
assert(false && "list boxes are not supported yet");
}
QObject* QtBuilder::insertObject(QObject* pParent, const OUString& rClass, std::string_view sType,
const OUString& rID, stringmap& rProps, stringmap&, stringmap&)
{
QObject* pCurrentChild = nullptr;
pCurrentChild = makeObject(pParent, rClass, sType, rID, rProps);
setProperties(pCurrentChild, rProps);
rProps.clear();
return pCurrentChild;
}
QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std::string_view sType,
const OUString& sID, stringmap& rMap)
{
// ignore placeholders
if (sName.empty())
return nullptr;
// nothing to do for these
if (sName == u"GtkCellRendererText" || sName == u"GtkTreeSelection")
return nullptr;
QWidget* pParentWidget = qobject_cast<QWidget*>(pParent);
QLayout* pParentLayout = qobject_cast<QLayout*>(pParent);
QObject* pObject = nullptr;
// in case a QLayout is created, an additional QWidget parent
// will also be created because that is needed for QtInstanceContainer
QWidget* pLayoutParentWidget = nullptr;
if (sName == u"GtkMessageDialog")
{
pObject = new QMessageBox(pParentWidget);
}
else if (sName == u"GtkBox")
{
// for a QMessageBox, return the existing layout instead of creating a new one
if (QMessageBox* pMessageBox = qobject_cast<QMessageBox*>(pParent))
{
pObject = pMessageBox->layout();
assert(pObject && "QMessageBox has no layout");
}
else
{
QWidget* pBoxParentWidget = pParentWidget;
// Unless this is the direct GtkBox child of a GtkDialog, create a parent widget
// that can be used to create a QtInstanceContainer for this box
if (!qobject_cast<QDialog*>(pParentWidget))
{
pLayoutParentWidget = new QWidget(pParentWidget);
pBoxParentWidget = pLayoutParentWidget;
}
const bool bVertical = hasOrientationVertical(rMap);
if (bVertical)
pObject = new QVBoxLayout(pBoxParentWidget);
else
pObject = new QHBoxLayout(pBoxParentWidget);
}
}
else if (sName == u"GtkButtonBox")
{
QWidget* pTopLevel = windowForObject(pParent);
if (QMessageBox* pMessageBox = qobject_cast<QMessageBox*>(pTopLevel))
{
// for a QMessageBox, return the existing button box instead of creating a new one
QDialogButtonBox* pButtonBox = findButtonBox(pMessageBox);
assert(pButtonBox && "Could not find QMessageBox's button box");
pObject = pButtonBox;
// skip adding to layout below, button box is already contained in dialog
pParentLayout = nullptr;
}
else
{
pObject = new QDialogButtonBox(pParentWidget);
}
}
else if (sName == u"GtkButton")
{
if (QDialogButtonBox* pButtonBox = qobject_cast<QDialogButtonBox*>(pParentWidget))
{
pObject = pButtonBox->addButton("", QDialogButtonBox::NoRole);
// for message boxes, avoid implicit standard buttons in addition to those explicitly added
if (QMessageBox* pMessageBox = qobject_cast<QMessageBox*>(pParentWidget->window()))
pMessageBox->setStandardButtons(QMessageBox::NoButton);
}
else
{
pObject = new QPushButton(pParentWidget);
}
}
else if (sName == u"GtkCheckButton")
{
pObject = new QCheckBox(pParentWidget);
}
else if (sName == u"GtkComboBoxText")
{
QComboBox* pComboBox = new QComboBox(pParentWidget);
pComboBox->setEditable(extractEntry(rMap));
pObject = pComboBox;
}
else if (sName == u"GtkDialog")
{
pObject = new QDialog(pParentWidget);
}
else if (sName == u"GtkDrawingArea")
{
pObject = new QLabel(pParentWidget);
}
else if (sName == u"GtkEntry")
{
QLineEdit* pLineEdit = new QLineEdit(pParentWidget);
auto aIt = rMap.find(u"visibility"_ustr);
if (aIt != rMap.end() && !toBool(aIt->second))
pLineEdit->setEchoMode(QLineEdit::Password);
pObject = pLineEdit;
}
else if (sName == u"GtkExpander")
{
pObject = new QtExpander(pParentWidget);
}
else if (sName == u"GtkFrame")
{
pObject = new QGroupBox(pParentWidget);
}
else if (sName == u"GtkGrid")
{
pLayoutParentWidget = new QWidget(pParentWidget);
pObject = new QGridLayout(pLayoutParentWidget);
}
else if (sName == u"GtkImage")
{
QLabel* pLabel = new QLabel(pParentWidget);
const OUString sIconName = extractIconName(rMap);
if (!sIconName.isEmpty())
{
const Image aImage = loadThemeImage(sIconName);
pLabel->setPixmap(toQPixmap(aImage));
}
pObject = pLabel;
}
else if (sName == u"GtkLabel")
{
QLabel* pLabel = new QLabel(pParentWidget);
setLabelProperties(*pLabel, rMap);
extractMnemonicWidget(sID, rMap);
pObject = pLabel;
}
else if (sName == u"GtkLevelBar" || sName == u"GtkProgressBar")
{
QProgressBar* pProgressBar = new QProgressBar(pParentWidget);
// don't show text (progress in percent) by default
pProgressBar->setTextVisible(false);
pObject = pProgressBar;
}
else if (sName == u"GtkLinkButton")
{
QtHyperlinkLabel* pLabel = new QtHyperlinkLabel(pParentWidget);
if (rMap.contains(u"label"_ustr))
pLabel->setDisplayText(toQString(rMap[u"label"_ustr]));
if (rMap.contains(u"uri"_ustr))
pLabel->setUri(toQString(rMap[u"uri"_ustr]));
pObject = pLabel;
}
else if (sName == u"GtkNotebook")
{
pObject = new QTabWidget(pParentWidget);
}
else if (sName == u"GtkRadioButton")
{
pObject = new QRadioButton(pParentWidget);
}
else if (sName == u"GtkScrolledWindow")
{
pObject = new QScrollArea(pParentWidget);
}
else if (sName == u"GtkSeparator")
{
const bool bVertical = hasOrientationVertical(rMap);
QFrame* pFrame = new QFrame(pParentWidget);
pFrame->setFrameShape(bVertical ? QFrame::VLine : QFrame::HLine);
pObject = pFrame;
}
else if (sName == u"GtkSpinButton")
{
QtDoubleSpinBox* pSpinBox = new QtDoubleSpinBox(pParentWidget);
setSpinButtonProperties(*pSpinBox, rMap);
pObject = pSpinBox;
}
else if (sName == u"GtkTextView")
{
pObject = new QPlainTextEdit(pParentWidget);
}
else if (sName == u"GtkTreeView")
{
QTreeView* pTreeView = new QTreeView(pParentWidget);
pTreeView->setModel(new QStandardItemModel(pTreeView));
pTreeView->setHeaderHidden(!extractHeadersVisible(rMap));
pTreeView->setRootIsDecorated(extractShowExpanders(rMap));
pObject = pTreeView;
}
else if (sName == u"GtkTreeViewColumn")
{
SAL_WARN("vcl.qt", "GtkTreeViewColumn properties not evaluated yet");
}
else
{
SAL_WARN("vcl.qt", "Widget type not supported yet: "
<< OUStringToOString(sName, RTL_TEXTENCODING_UTF8));
assert(false && "Widget type not supported yet");
}
QWidget* pWidget = qobject_cast<QWidget*>(pObject);
if (!pWidget)
pWidget = pLayoutParentWidget;
QTabWidget* pParentTabWidget = qobject_cast<QTabWidget*>(pParentWidget);
if (pParentTabWidget)
{
// remove QTabWidget child widget, set via QTabWidget::addTab instead
assert(pWidget);
pWidget->setParent(nullptr);
// initially, add tab with empty label, QtBuilder::applyTabChildProperties will evaluate actual one
pParentTabWidget->addTab(pWidget, QStringLiteral());
// unset pParentWidget to not create a layout below
pParentWidget = nullptr;
}
else if (QtExpander* pExpander = qobject_cast<QtExpander*>(pParentWidget))
{
// set the content (not the label) child as the expander's widget
if (sType != "label")
{
pExpander->setContentWidget(pWidget);
// erase "visible" property, QtExpander shows/hides the widget as needed
rMap.erase("visible");
}
}
if (pWidget)
{
if (!pParentLayout && pParentWidget)
{
// if the parent is a widget, use the widget's layout, and ensure it has one set
pParentLayout = pParentWidget->layout();
if (!pParentLayout)
pParentLayout = new QVBoxLayout(pParentWidget);
}
// add widget to parent layout
if (pParentLayout)
pParentLayout->addWidget(pWidget);
QtInstanceWidget::setHelpId(*pWidget, getHelpRoot() + sID);
pWidget->setToolTip(toQString(extractTooltipText(rMap)));
pWidget->setVisible(extractVisible(rMap));
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
// Set GtkBuilder ID as accessible ID
pWidget->setAccessibleIdentifier(toQString(sID));
#endif
}
else if (QLayout* pLayout = qobject_cast<QLayout*>(pObject))
{
// add layout to parent layout
if (QBoxLayout* pParentBoxLayout = qobject_cast<QBoxLayout*>(pParentLayout))
pParentBoxLayout->addLayout(pLayout);
else if (QGridLayout* pParentGridLayout = qobject_cast<QGridLayout*>(pParentLayout))
pParentGridLayout->addLayout(pLayout, pParentGridLayout->rowCount(), 0);
}
m_aChildren.emplace_back(sID, pObject);
return pObject;
}
void QtBuilder::tweakInsertedChild(QObject* pParent, QObject* pCurrentChild, std::string_view sType,
std::string_view sInternalChild)
{
if (sInternalChild == "entry" && qobject_cast<QComboBox*>(pParent))
{
// an editable GtkComboBox has an internal GtkEntry child,
// but QComboBox doesn't need a separate widget for it, so
// delete it
deleteObject(pCurrentChild);
}
if (sType == "label")
{
if (QLabel* pLabel = qobject_cast<QLabel*>(pCurrentChild))
{
if (QGroupBox* pGroupBox = qobject_cast<QGroupBox*>(pParent))
{
// GtkFrame has a `child-type="label"` child for the GtkFrame label
// in the GtkBuilder .ui file, s. https://docs.gtk.org/gtk3/class.Frame.html
// For QGroupBox, the title can be set directly. Therefore, take over the
// title from the label and delete the separate label widget again
pGroupBox->setTitle(pLabel->text());
deleteObject(pLabel);
}
else if (QtExpander* pExpander = qobject_cast<QtExpander*>(pParent))
{
// GtkExpander has a `child-type="label"` child for the expander label
// in the GtkBuilder .ui file, s. https://docs.gtk.org/gtk3/class.Expander.html
// For QtExpander, the (button) text can be set directly. Therefore, take over
// text from the label and delete the separate label widget again
pExpander->setText(pLabel->text());
deleteObject(pLabel);
}
}
}
if (QDialog* pDialog = qobject_cast<QDialog*>(pCurrentChild))
{
// no action needed for QMessageBox, where the default button box is used
// and button click is handled in QtInstanceMessageDialog
if (!qobject_cast<QMessageBox*>(pDialog))
{
if (QDialogButtonBox* pButtonBox = findButtonBox(pDialog))
{
// ensure that button box is the last item in QDialog's layout
// (that seems to be implicitly the case for GtkDialog in GTK)
QLayout* pLayout = pDialog->layout();
assert(pLayout && "dialog has no layout");
pLayout->removeWidget(pButtonBox);
pLayout->addWidget(pButtonBox);
// connect button click handler
const QList<QAbstractButton*> aButtons = pButtonBox->buttons();
for (QAbstractButton* pButton : aButtons)
{
assert(pButton);
QObject::connect(pButton, &QAbstractButton::clicked, pDialog,
[pDialog, pButton] {
QtInstanceDialog::handleButtonClick(*pDialog, *pButton);
});
}
}
}
}
}
void QtBuilder::setMnemonicWidget(const OUString& rLabelId, const OUString& rMnemonicWidgetId)
{
QLabel* pLabel = get<QLabel>(rLabelId);
QObject* pBuddy = get_by_name(rMnemonicWidgetId);
if (!pLabel || !pBuddy || !pBuddy->isWidgetType())
return;
pLabel->setBuddy(static_cast<QWidget*>(pBuddy));
}
void QtBuilder::setPriority(QObject*, int) { SAL_WARN("vcl.qt", "Ignoring priority"); }
void QtBuilder::setContext(QObject*, std::vector<vcl::EnumContext::Context>&&)
{
SAL_WARN("vcl.qt", "Ignoring context");
}
bool QtBuilder::isHorizontalTabControl(QObject* pObject)
{
QTabWidget* pTabWidget = qobject_cast<QTabWidget*>(pObject);
if (!pTabWidget)
return false;
const QTabWidget::TabPosition ePosition = pTabWidget->tabPosition();
return ePosition == QTabWidget::TabPosition::North
|| ePosition == QTabWidget::TabPosition::South;
}
QMenu* QtBuilder::createMenu(const OUString&)
{
assert(false && "Not implemented yet");
return nullptr;
}
void QtBuilder::insertMenuObject(QMenu*, QMenu*, const OUString&, const OUString&, stringmap&,
stringmap&, accelmap&)
{
assert(false && "Not implemented yet");
}
void QtBuilder::applyAtkProperties(QObject* pObject, const stringmap& rProperties, bool)
{
if (!pObject || !pObject->isWidgetType())
return;
QWidget* pWidget = static_cast<QWidget*>(pObject);
for (auto const & [ rKey, rValue ] : rProperties)
{
if (rKey == "AtkObject::accessible-description")
pWidget->setAccessibleDescription(toQString(rValue));
else if (rKey == "AtkObject::accessible-name")
pWidget->setAccessibleName(toQString(rValue));
}
}
void QtBuilder::applyGridPackingProperties(QWidget* pCurrentChild, QGridLayout& rGrid,
const stringmap& rPackingProperties)
{
assert(pCurrentChild);
// properties not set when there's no explicit GtkGrid in the .ui file,
// like for the QGridLayout that's the (implicit) layout of a QMessageBox
if (!rPackingProperties.contains(u"left-attach"_ustr)
|| !rPackingProperties.contains(u"top-attach"_ustr))
return;
const sal_Int32 nColumn = rPackingProperties.at(u"left-attach"_ustr).toInt32();
const sal_Int32 nRow = rPackingProperties.at(u"top-attach"_ustr).toInt32();
auto aWidthIt = rPackingProperties.find(u"width"_ustr);
sal_Int32 nColumnSpan = (aWidthIt == rPackingProperties.end()) ? 1 : aWidthIt->second.toInt32();
auto aHeightIt = rPackingProperties.find(u"height"_ustr);
sal_Int32 nRowSpan = (aHeightIt == rPackingProperties.end()) ? 1 : aHeightIt->second.toInt32();
rGrid.removeWidget(pCurrentChild);
rGrid.addWidget(pCurrentChild, nRow, nColumn, nRowSpan, nColumnSpan);
}
void QtBuilder::applyPackingProperties(QObject* pCurrentChild, QObject* pParent,
const stringmap& rPackingProperties)
{
if (!pCurrentChild)
return;
QWidget* pWidget = nullptr;
if (pCurrentChild->isWidgetType())
pWidget = static_cast<QWidget*>(pCurrentChild);
else
{
QObject* pParentObject = pCurrentChild->parent();
assert(pParent && "Non-widget (i.e. layout) has no parent");
if (pParentObject->isWidgetType())
pWidget = static_cast<QWidget*>(pParentObject);
}
if (!pWidget)
return;
// check parent's parent, due to extra QWidget parents for layouts
if (QGridLayout* pGrid = qobject_cast<QGridLayout*>(pParent))
applyGridPackingProperties(pWidget, *pGrid, rPackingProperties);
else
SAL_WARN("vcl.qt", "QtBuilder::applyPackingProperties not yet implemented for this case");
}
void QtBuilder::applyTabChildProperties(QObject* pParent, const std::vector<OUString>& rIDs,
std::vector<vcl::EnumContext::Context>&,
stringmap& rProperties, stringmap&)
{
QTabWidget* pTabWidget = qobject_cast<QTabWidget*>(pParent);
assert(pTabWidget && "parent must be a QTabWidget");
// set ID and label for the last inserted tab
assert(rProperties.contains(u"label"_ustr) && "Tab has no label");
QtInstanceNotebook::setTabIdAndLabel(*pTabWidget, pTabWidget->count() - 1, rIDs.front(),
rProperties.at(u"label"_ustr));
}
void QtBuilder::set_response(std::u16string_view sID, short nResponse)
{
QPushButton* pPushButton = get<QPushButton>(sID);
assert(pPushButton);
pPushButton->setProperty(QtInstanceMessageDialog::PROPERTY_VCL_RESPONSE_CODE, int(nResponse));
}
void QtBuilder::deleteObject(QObject* pObject)
{
if (pObject->isWidgetType())
static_cast<QWidget*>(pObject)->hide();
pObject->deleteLater();
}
void QtBuilder::setProperties(QObject* pObject, stringmap& rProps)
{
if (QMessageBox* pMessageBox = qobject_cast<QMessageBox*>(pObject))
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"text")
{
pMessageBox->setText(toQString(rValue));
}
else if (rKey == u"title")
{
pMessageBox->setWindowTitle(toQString(rValue));
}
else if (rKey == u"secondary-text")
{
pMessageBox->setInformativeText(toQString(rValue));
}
else if (rKey == u"message-type")
{
if (rValue == u"error")
pMessageBox->setIcon(QMessageBox::Critical);
else if (rValue == u"info")
pMessageBox->setIcon(QMessageBox::Information);
else if (rValue == u"question")
pMessageBox->setIcon(QMessageBox::Question);
else if (rValue == u"warning")
pMessageBox->setIcon(QMessageBox::Warning);
else
assert(false && "Unhandled message-type");
}
}
}
else if (qobject_cast<QCheckBox*>(pObject) || qobject_cast<QRadioButton*>(pObject))
{
QAbstractButton* pButton = static_cast<QAbstractButton*>(pObject);
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"active")
pButton->setChecked(toBool(rValue));
else if (rKey == u"label")
pButton->setText(convertAccelerator(rValue));
}
}
else if (QDialog* pDialog = qobject_cast<QDialog*>(pObject))
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"modal")
pDialog->setModal(toBool(rValue));
else if (rKey == u"title")
pDialog->setWindowTitle(toQString(rValue));
}
}
else if (QPlainTextEdit* pTextEdit = qobject_cast<QPlainTextEdit*>(pObject))
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"accepts-tab")
pTextEdit->setTabChangesFocus(!toBool(rValue));
}
}
else if (QPushButton* pButton = qobject_cast<QPushButton*>(pObject))
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"image")
{
QLabel* pImageLabel = get<QLabel>(rValue);
assert(pImageLabel && "Button has non-existent image set");
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
pButton->setIcon(QIcon(pImageLabel->pixmap()));
#else
pButton->setIcon(QIcon(pImageLabel->pixmap(Qt::ReturnByValue)));
#endif
// parentless GtkImage in .ui file is only used for setting button
// image, so the object is no longer needed after doing so
if (!pImageLabel->parent())
deleteObject(pImageLabel);
}
else if (rKey == u"label")
{
pButton->setText(convertAccelerator(rValue));
}
}
}
}
void QtBuilder::setLabelProperties(QLabel& rLabel, stringmap& rProps)
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"label")
rLabel.setText(convertAccelerator(rValue));
else if (rKey == u"wrap")
rLabel.setWordWrap(toBool(rValue));
}
}
void QtBuilder::setSpinButtonProperties(QDoubleSpinBox& rSpinBox, stringmap& rProps)
{
auto aDigitsIt = rProps.find(u"digits"_ustr);
sal_Int32 nDigits = (aDigitsIt != rProps.end()) ? aDigitsIt->second.toInt32() : 0;
rSpinBox.setDecimals(nDigits);
auto aAdjustmentIt = rProps.find("adjustment");
if (aAdjustmentIt != rProps.end())
{
const Adjustment* pAdjustment = get_adjustment_by_name(aAdjustmentIt->second);
assert(pAdjustment && "referenced adjustment doesn't exist");
for (auto const & [ rKey, rValue ] : *pAdjustment)
{
if (rKey == u"upper")
rSpinBox.setMaximum(rValue.toDouble());
else if (rKey == u"lower")
rSpinBox.setMinimum(rValue.toDouble());
else if (rKey == "value")
rSpinBox.setValue(rValue.toDouble());
else if (rKey == "step-increment")
rSpinBox.setSingleStep(rValue.toDouble());
}
}
}
QWidget* QtBuilder::windowForObject(QObject* pObject)
{
if (QWidget* pWidget = qobject_cast<QWidget*>(pObject))
return pWidget->window();
if (QLayout* pLayout = qobject_cast<QLayout*>(pObject))
{
if (QWidget* pParentWidget = pLayout->parentWidget())
return pParentWidget->window();
}
return nullptr;
}
QDialogButtonBox* QtBuilder::findButtonBox(QDialog* pDialog)
{
assert(pDialog);
QLayout* pLayout = pDialog->layout();
if (!pLayout)
return nullptr;
for (int i = 0; i < pLayout->count(); i++)
{
QLayoutItem* pItem = pLayout->itemAt(i);
if (QWidget* pItemWidget = pItem->widget())
{
if (QDialogButtonBox* pButtonBox = qobject_cast<QDialogButtonBox*>(pItemWidget))
return pButtonBox;
}
}
return nullptr;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */