dbaccess/source/ui/dlg/sqlmessage.cxx | 19 +++++++++------ vcl/inc/qt5/QtBuilder.hxx | 3 ++ vcl/inc/qt5/QtInstanceTreeView.hxx | 9 +++++++ vcl/qt5/QtBuilder.cxx | 43 ++++++++++++++++++++++++++++++---- vcl/qt5/QtInstanceBuilder.cxx | 1 vcl/qt5/QtInstanceTreeView.cxx | 32 +++++++++++++++++++++---- 6 files changed, 91 insertions(+), 16 deletions(-)
New commits: commit 8e33908b538c7700be6f766c472f069d7f4dd15b Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Sun Aug 3 22:17:34 2025 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Mon Aug 4 09:01:19 2025 +0200 tdf#130857 qt weld: Evaluate GtkCellRenderers to know supported types So far, The GtkCellRenderer objects in .ui files were ignored by QtBuilder. However, for the automatic detection of what is the first column of a specific type (e.g. the first text column), that information is relevant, and e.g. the GTK implementation in GtkInstanceTreeView sets `GtkInstanceTreeView::m_nTextCol` based on that, then uses it when inserting text via the weld::TreeView::insert method. Extend the logic in QtBuilder and QtInstanceTreeView to also evaluate the cell renderers set in the .ui file and store the item data roles supported for each column based on those renderers. The Qt data model allows setting any of the roles exactly once for each item, so there is generally no need to explicitly enable something. But in order to adhere to the weld::TreeView logic/API, that kind of information is relevant. Let QtBuilder store a list of supported roles for each column (i.e. use a list of lists for all columns) in a property set for the QTreeView, and then use that property in the QtInstanceTreeView ctor to set the newly introduced QtInstanceTreeView::m_pColumnRoles member. Adjust QtInstanceTreeView::firstTextColumnModelIndex to make use of those stored roles, to reliably detect what is the first text column according to the GTK/weld::TreeView model, without requiring any entries to have been inserted previously. This is one step towards addressing the issue mentioned in previous commit Change-Id: Id94e22e879f712bd967431ec0f9dc34e4480e3dd Author: Michael Weghorn <m.wegh...@posteo.de> Date: Sun Aug 3 22:15:20 2025 +0200 tdf#130857 qt weld: Support Java "Class Path" dialog > Currently, both the icon and the path are displayed > in the first column of the tree view and the second > column remains empty. This will be addressed in > upcoming commits. Change-Id: Ic8a59b254f3bac14c3b812f00d0cbfa3740432f2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188891 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/vcl/inc/qt5/QtBuilder.hxx b/vcl/inc/qt5/QtBuilder.hxx index fbd6ec17a9c4..c2e06d87669b 100644 --- a/vcl/inc/qt5/QtBuilder.hxx +++ b/vcl/inc/qt5/QtBuilder.hxx @@ -22,6 +22,7 @@ #include <QtWidgets/QPushButton> #include <QtWidgets/QSlider> #include <QtWidgets/QToolButton> +#include <QtWidgets/QTreeView> #include <rtl/ustring.hxx> #include <unotools/resmgr.hxx> @@ -84,6 +85,8 @@ public: private: static void deleteObject(QObject* pObject); + static QTreeView* enableTreeViewColumnDataRole(QWidget* pParentWidget, + Qt::ItemDataRole eDataRole); // remove pOldWidget from the widget hierarchy and set (child widget) pNewWidget in its place static void replaceWidget(QWidget* pOldWidget, QWidget* pNewWidget); void setButtonProperties(QAbstractButton& rButton, stringmap& rProps, QWidget* pParentWidget); diff --git a/vcl/inc/qt5/QtInstanceTreeView.hxx b/vcl/inc/qt5/QtInstanceTreeView.hxx index cab92ffb69f2..aa78075d38aa 100644 --- a/vcl/inc/qt5/QtInstanceTreeView.hxx +++ b/vcl/inc/qt5/QtInstanceTreeView.hxx @@ -31,6 +31,9 @@ class QtInstanceTreeView : public QtInstanceWidget, public virtual weld::TreeVie QItemSelectionModel* m_pSelectionModel; + /** List containing a list of item data roles supported by each column. */ + QList<QList<Qt::ItemDataRole>> m_pColumnRoles; + bool m_bExtraToggleButtonsEnabled = false; public: @@ -200,6 +203,12 @@ public: using QtInstanceWidget::set_sensitive; using QtInstanceWidget::get_sensitive; + // methods to get/set which roles are supported by the individual columns + // based on the underlying GtkTreeViewColumns and their GtkCellRenderers + static QList<QList<Qt::ItemDataRole>> columnRoles(QTreeView& rTreeView); + static void setColumnRoles(QTreeView& rTreeView, + const QList<QList<Qt::ItemDataRole>>& rDataRoles); + private: QModelIndex modelIndex(int nRow, int nCol = 0, const QModelIndex& rParentIndex = QModelIndex()) const; diff --git a/vcl/qt5/QtBuilder.cxx b/vcl/qt5/QtBuilder.cxx index cda06da766a1..17050ddf48a3 100644 --- a/vcl/qt5/QtBuilder.cxx +++ b/vcl/qt5/QtBuilder.cxx @@ -14,6 +14,7 @@ #include <QtInstanceMenu.hxx> #include <QtInstanceMessageDialog.hxx> #include <QtInstanceNotebook.hxx> +#include <QtInstanceTreeView.hxx> #include <QtHyperlinkLabel.hxx> #include <vcl/qt/QtUtils.hxx> @@ -47,7 +48,6 @@ #include <QtWidgets/QTabWidget> #include <QtWidgets/QToolBar> #include <QtWidgets/QToolButton> -#include <QtWidgets/QTreeView> #include <QtWidgets/QWizard> namespace @@ -123,9 +123,8 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std: if (sName.empty()) return nullptr; - // nothing to do for these - if (sName == u"GtkCellRendererPixbuf" || sName == u"GtkCellRendererText" - || sName == u"GtkCellRendererToggle" || sName == u"GtkTreeSelection") + // nothing to do for this one + if (sName == u"GtkTreeSelection") return nullptr; QWidget* pParentWidget = qobject_cast<QWidget*>(pParent); @@ -203,6 +202,18 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std: { pObject = new QCalendarWidget(pParentWidget); } + else if (sName == u"GtkCellRendererPixbuf") + { + enableTreeViewColumnDataRole(pParentWidget, Qt::DecorationRole); + } + else if (sName == u"GtkCellRendererText") + { + enableTreeViewColumnDataRole(pParentWidget, Qt::DisplayRole); + } + else if (sName == u"GtkCellRendererToggle") + { + enableTreeViewColumnDataRole(pParentWidget, Qt::CheckStateRole); + } else if (sName == u"GtkCheckButton") { QCheckBox* pCheckBox = new QCheckBox(pParentWidget); @@ -416,6 +427,12 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std: pModel->insertColumn(nCol); pModel->setHeaderData(nCol, Qt::Horizontal, toQString(extractTitle(rMap))); + // add initially empty list of supported roles for the new column that will + // be extended based on the GtkCellRenderer children of the column + QList<QList<Qt::ItemDataRole>> aColumnRoles = QtInstanceTreeView::columnRoles(*pTreeView); + aColumnRoles.push_back({}); + QtInstanceTreeView::setColumnRoles(*pTreeView, aColumnRoles); + // nothing else to do, return tree view parent for the widget return pTreeView; } @@ -826,6 +843,24 @@ void QtBuilder::deleteObject(QObject* pObject) pObject->deleteLater(); } +QTreeView* QtBuilder::enableTreeViewColumnDataRole(QWidget* pParentWidget, + Qt::ItemDataRole eDataRole) +{ + QTreeView* pTreeView = qobject_cast<QTreeView*>(pParentWidget); + assert(pTreeView && "No tree view for cell renderer"); + + // Mark support for the new role for the tree view's last inserted column + // (the GtkCellRenderer is a child object of the GtkTreeViewColumn) + QList<QList<Qt::ItemDataRole>> aColumnRoles = QtInstanceTreeView::columnRoles(*pTreeView); + assert(!aColumnRoles.empty() && "Missing list of column data roles"); + assert(!aColumnRoles.back().contains(eDataRole) + && "Using the same role multiple times in one column is not supported"); + aColumnRoles.back().push_back(eDataRole); + QtInstanceTreeView::setColumnRoles(*pTreeView, aColumnRoles); + + return pTreeView; +} + void QtBuilder::replaceWidget(QWidget* pOldWidget, QWidget* pNewWidget) { QWidget* pParent = pOldWidget->parentWidget(); diff --git a/vcl/qt5/QtInstanceTreeView.cxx b/vcl/qt5/QtInstanceTreeView.cxx index 413eb30f8614..41b94fe9eea7 100644 --- a/vcl/qt5/QtInstanceTreeView.cxx +++ b/vcl/qt5/QtInstanceTreeView.cxx @@ -17,6 +17,9 @@ // role used for the ID in the QStandardItem constexpr int ROLE_ID = Qt::UserRole + 1000; +// Property used to store the supported roles for each of the columns +const char* const PROPERTY_COLUMN_ROLES = "column-roles"; + QtInstanceTreeView::QtInstanceTreeView(QTreeView* pTreeView) : QtInstanceWidget(pTreeView) , m_pTreeView(pTreeView) @@ -32,6 +35,9 @@ QtInstanceTreeView::QtInstanceTreeView(QTreeView* pTreeView) m_pSelectionModel = m_pTreeView->selectionModel(); assert(m_pSelectionModel); + m_pColumnRoles = columnRoles(*pTreeView); + assert(m_pColumnRoles.size() == m_pModel->columnCount() && "column count doesn't match"); + connect(m_pTreeView, &QTreeView::activated, this, &QtInstanceTreeView::handleActivated); connect(m_pSelectionModel, &QItemSelectionModel::selectionChanged, this, &QtInstanceTreeView::handleSelectionChanged); @@ -1008,6 +1014,24 @@ QAbstractItemView::SelectionMode QtInstanceTreeView::mapSelectionMode(SelectionM } } +QList<QList<Qt::ItemDataRole>> QtInstanceTreeView::columnRoles(QTreeView& rTreeView) +{ + QVariant aVariant = rTreeView.property(PROPERTY_COLUMN_ROLES); + if (aVariant.isValid()) + { + assert(aVariant.canConvert<QList<QList<Qt::ItemDataRole>>>()); + return aVariant.value<QList<QList<Qt::ItemDataRole>>>(); + } + + return {}; +} + +void QtInstanceTreeView::setColumnRoles(QTreeView& rTreeView, + const QList<QList<Qt::ItemDataRole>>& rDataRoles) +{ + rTreeView.setProperty(PROPERTY_COLUMN_ROLES, QVariant::fromValue(rDataRoles)); +} + QModelIndex QtInstanceTreeView::modelIndex(int nRow, int nCol, const QModelIndex& rParentIndex) const { @@ -1042,12 +1066,10 @@ QModelIndex QtInstanceTreeView::toggleButtonModelIndex(const weld::TreeIter& rIt QModelIndex QtInstanceTreeView::firstTextColumnModelIndex(const weld::TreeIter& rIter) const { - for (int i = 0; i < m_pModel->columnCount(); i++) + for (qsizetype i = 0; i < m_pColumnRoles.size(); i++) { - const QModelIndex aIndex = modelIndex(rIter, i); - QVariant data = m_pModel->data(aIndex, Qt::DisplayRole); - if (data.canConvert<QString>()) - return aIndex; + if (m_pColumnRoles.at(i).contains(Qt::DisplayRole)) + return modelIndex(rIter, i); } assert(false && "No text column found"); commit ea3259d1c109c87135f54ef065fa1beb30cadb28 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Sun Aug 3 22:15:20 2025 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Mon Aug 4 09:01:13 2025 +0200 tdf#130857 qt weld: Support Java "Class Path" dialog This means that native Qt widgets are used for that dialog now when using the qt5 or qt6 VCL plugin and starting LO with environment variable SAL_VCL_QT_USE_WELDED_WIDGETS=1 set. The dialog can be triggered as follows: * "Tools" -> "Options" * "LibreOfficDev" -> "Advanced" * select a JVM in the treeview * click the "Class Path" button Currently, both the icon and the path are displayed in the first column of the tree view and the second column remains empty. This will be addressed in upcoming commits. Change-Id: Id94e22e879f712bd967431ec0f9dc34e4480e3dd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188890 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/vcl/qt5/QtInstanceBuilder.cxx b/vcl/qt5/QtInstanceBuilder.cxx index 718a53ece436..4eb3ceea0e14 100644 --- a/vcl/qt5/QtInstanceBuilder.cxx +++ b/vcl/qt5/QtInstanceBuilder.cxx @@ -75,6 +75,7 @@ bool QtInstanceBuilder::IsUIFileSupported(const OUString& rUIFile, const weld::W u"cui/ui/graphictestdlg.ui"_ustr, u"cui/ui/imageviewer.ui"_ustr, u"cui/ui/insertrowcolumn.ui"_ustr, + u"cui/ui/javaclasspathdialog.ui"_ustr, u"cui/ui/javastartparametersdialog.ui"_ustr, u"cui/ui/linedialog.ui"_ustr, u"cui/ui/namedialog.ui"_ustr, commit 54160ef0a5e6faa052f04a8d3ca3744943f6a8ef Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Sat Aug 2 23:49:53 2025 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Mon Aug 4 09:01:07 2025 +0200 dbaccess: Switch static helper to OExceptionChainDialog method This allows to use the m_xExceptionList member directly instead of passing it as a param. Change-Id: I74881c1ab5577a5b9dea424c887977f492b377ed Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188881 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/dbaccess/source/ui/dlg/sqlmessage.cxx b/dbaccess/source/ui/dlg/sqlmessage.cxx index 3d15c662ea17..9fe71ae4b44f 100644 --- a/dbaccess/source/ui/dlg/sqlmessage.cxx +++ b/dbaccess/source/ui/dlg/sqlmessage.cxx @@ -247,11 +247,6 @@ namespace } } } - - void lcl_insertExceptionEntry(weld::TreeView& rList, size_t nElementPos, const ExceptionDisplayInfo& rEntry) - { - rList.append(OUString::number(nElementPos), rEntry.pLabelProvider->getLabel(), rEntry.pImageProvider->getImage()); - } } namespace { @@ -271,6 +266,9 @@ public: protected: DECL_LINK(OnExceptionSelected, weld::TreeView&, void); + +private: + void insertExceptionEntry(size_t nElementPos, const ExceptionDisplayInfo& rEntry); }; } @@ -298,7 +296,7 @@ OExceptionChainDialog::OExceptionChainDialog(weld::Window* pParent, ExceptionDis for (auto const& elem : m_aExceptions) { - lcl_insertExceptionEntry(*m_xExceptionList, elementPos, elem); + insertExceptionEntry(elementPos, elem); bHave22018 = elem.sSQLState == "22018"; ++elementPos; } @@ -315,7 +313,7 @@ OExceptionChainDialog::OExceptionChainDialog(weld::Window* pParent, ExceptionDis aInfo22018.pImageProvider = aProviderFactory.getImageProvider( SQLExceptionInfo::TYPE::SQLContext ); m_aExceptions.push_back( aInfo22018 ); - lcl_insertExceptionEntry(*m_xExceptionList, m_aExceptions.size() - 1, aInfo22018); + insertExceptionEntry(m_aExceptions.size() - 1, aInfo22018); } if (m_xExceptionList->n_children()) @@ -325,6 +323,13 @@ OExceptionChainDialog::OExceptionChainDialog(weld::Window* pParent, ExceptionDis } } +void OExceptionChainDialog::insertExceptionEntry(size_t nElementPos, + const ExceptionDisplayInfo& rEntry) +{ + m_xExceptionList->append(OUString::number(nElementPos), rEntry.pLabelProvider->getLabel(), + rEntry.pImageProvider->getImage()); +} + IMPL_LINK_NOARG(OExceptionChainDialog, OnExceptionSelected, weld::TreeView&, void) { OUString sText;