774786a019
Move VclBuilder::handleMenuObject to the WidgetBuilder template
base class, and add a new purely virtual WidgetBuilder::insertMenuObject
that the existing VclBuilder equivalent now overrides.
This moves the remaining XML parsing logic from VclBuilder
to one of the base classes (WidgetBuilder, BuilderBase),
following the approach outlined in
commit f61ecf2563
Author: OmkarAcharekar <omkaracharekar12@gmail.com>
Date: Fri Sep 20 13:33:01 2024 +0200
tdf#130857 refactor VclBuilder: Extract template base class
Update the source code comments accordingly.
For QtBuilder, initially add a dummy implementation
that simply triggers an assert, but can be adjusted
in the future to create native Qt menus.
Change-Id: I3147cac28c7273cd4c4ea7344a083cd66af8337f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176362
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
686 lines
23 KiB
C++
686 lines
23 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* 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 <QtInstanceLinkButton.hxx>
|
|
#include <QtInstanceMessageDialog.hxx>
|
|
#include <QtInstanceNotebook.hxx>
|
|
#include <QtTools.hxx>
|
|
|
|
#include <rtl/ustrbuf.hxx>
|
|
#include <vcl/qt/QtUtils.hxx>
|
|
|
|
#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, const OUString& rID,
|
|
stringmap& rProps, stringmap&, stringmap&)
|
|
{
|
|
QObject* pCurrentChild = nullptr;
|
|
|
|
pCurrentChild = makeObject(pParent, rClass, rID, rProps);
|
|
|
|
setProperties(pCurrentChild, rProps);
|
|
|
|
rProps.clear();
|
|
|
|
return pCurrentChild;
|
|
}
|
|
|
|
QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, const OUString& sID,
|
|
stringmap& rMap)
|
|
{
|
|
// ignore placeholders
|
|
if (sName.empty())
|
|
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"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")
|
|
{
|
|
QDoubleSpinBox* pSpinBox = new QDoubleSpinBox(pParentWidget);
|
|
setSpinButtonProperties(*pSpinBox, rMap);
|
|
pObject = pSpinBox;
|
|
}
|
|
else if (sName == u"GtkTextView")
|
|
{
|
|
pObject = new QPlainTextEdit(pParentWidget);
|
|
}
|
|
else if (sName == u"GtkTreeView")
|
|
{
|
|
pObject = new QTreeView(pParentWidget);
|
|
}
|
|
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 not create a layout below
|
|
pParentWidget = nullptr;
|
|
}
|
|
|
|
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
|
|
pCurrentChild->deleteLater();
|
|
}
|
|
|
|
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());
|
|
pLabel->setParent(nullptr);
|
|
pLabel->deleteLater();
|
|
}
|
|
}
|
|
}
|
|
|
|
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::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())
|
|
pImageLabel->deleteLater();
|
|
}
|
|
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: */
|