Set orientation to vertical if that's specified in the .ui file instead of using the default of horizontal. This is used by the button box on the right hand side of the "Tools" -> "XML Filter Settings" dialog. Change-Id: I64460037649dcd24897c7a5d7148430836702edc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178064 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
743 lines
26 KiB
C++
743 lines
26 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
|
|
{
|
|
QDialogButtonBox* pButtonBox = new QDialogButtonBox(pParentWidget);
|
|
if (hasOrientationVertical(rMap))
|
|
pButtonBox->setOrientation(Qt::Vertical);
|
|
pObject = pButtonBox;
|
|
}
|
|
}
|
|
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")
|
|
{
|
|
QTreeView* pTreeView = qobject_cast<QTreeView*>(pParentWidget);
|
|
assert(pTreeView && "Tree view column doesn't have a tree view parent");
|
|
QStandardItemModel* pModel = qobject_cast<QStandardItemModel*>(pTreeView->model());
|
|
assert(pModel && "Tree view doesn't have QStandardItemModel set");
|
|
const int nCol = pModel->columnCount();
|
|
pModel->insertColumn(nCol);
|
|
pModel->setHeaderData(nCol, Qt::Horizontal, toQString(extractTitle(rMap)));
|
|
|
|
// nothing else to do, return tree view parent for the widget
|
|
return pTreeView;
|
|
}
|
|
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: */
|