dbaccess/source/ui/dlg/sqlmessage.cxx | 276 ++++++++++++++++------------------ include/vcl/qt/QtUtils.hxx | 13 + vcl/qt5/QtBuilder.cxx | 20 -- vcl/qt5/QtInstanceBuilder.cxx | 1 4 files changed, 151 insertions(+), 159 deletions(-)
New commits: commit 687007afca9a8ad261f1990de38736cec35868d0 Author: Michael Weghorn <[email protected]> AuthorDate: Fri Feb 20 14:18:02 2026 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Sat Feb 21 02:32:53 2026 +0100 dbaccess: Drop extra indentation level in sqlmessage.cxx Drop the extra indentation for the code in the first anonymous namespace at the top of the source file, to be consistent with the rest. clang-format the newly (un)indented code. Change-Id: I35b165698fce3151b4ec8f16cfab3c96b08ca9c4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199859 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/dbaccess/source/ui/dlg/sqlmessage.cxx b/dbaccess/source/ui/dlg/sqlmessage.cxx index e49633b6a204..29bb20cd75bb 100644 --- a/dbaccess/source/ui/dlg/sqlmessage.cxx +++ b/dbaccess/source/ui/dlg/sqlmessage.cxx @@ -51,61 +51,54 @@ namespace dbaui namespace { - class ImageProvider +class ImageProvider +{ +private: + OUString m_defaultImageID; + +public: + explicit ImageProvider(OUString defaultImageID) + : m_defaultImageID(std::move(defaultImageID)) { - private: - OUString m_defaultImageID; + } - public: - explicit ImageProvider(OUString defaultImageID) - : m_defaultImageID(std::move(defaultImageID)) - { - } + const OUString& getImage() const { return m_defaultImageID; } +}; - const OUString& getImage() const - { - return m_defaultImageID; - } - }; +class LabelProvider +{ +private: + OUString m_label; - class LabelProvider +public: + explicit LabelProvider(TranslateId labelResourceID) + : m_label(DBA_RES(labelResourceID)) { - private: - OUString m_label; - public: - explicit LabelProvider(TranslateId labelResourceID) - : m_label(DBA_RES(labelResourceID)) - { - } + } - const OUString& getLabel() const - { - return m_label; - } - }; + const OUString& getLabel() const { return m_label; } +}; + +class ProviderFactory +{ +private: + mutable std::shared_ptr<ImageProvider> m_pErrorImage; + mutable std::shared_ptr<ImageProvider> m_pWarningsImage; + mutable std::shared_ptr<ImageProvider> m_pInfoImage; + mutable std::shared_ptr<LabelProvider> m_pErrorLabel; + mutable std::shared_ptr<LabelProvider> m_pWarningsLabel; + mutable std::shared_ptr<LabelProvider> m_pInfoLabel; - class ProviderFactory +public: + ProviderFactory() {} + + std::shared_ptr<ImageProvider> const& getImageProvider(SQLExceptionInfo::TYPE _eType) const { - private: - mutable std::shared_ptr< ImageProvider > m_pErrorImage; - mutable std::shared_ptr< ImageProvider > m_pWarningsImage; - mutable std::shared_ptr< ImageProvider > m_pInfoImage; - mutable std::shared_ptr< LabelProvider > m_pErrorLabel; - mutable std::shared_ptr< LabelProvider > m_pWarningsLabel; - mutable std::shared_ptr< LabelProvider > m_pInfoLabel; - - public: - ProviderFactory() - { - } + std::shared_ptr<ImageProvider>* ppProvider(&m_pErrorImage); + OUString sNormalImageID(u"dialog-error"_ustr); - std::shared_ptr< ImageProvider > const & getImageProvider( SQLExceptionInfo::TYPE _eType ) const + switch (_eType) { - std::shared_ptr< ImageProvider >* ppProvider( &m_pErrorImage ); - OUString sNormalImageID(u"dialog-error"_ustr); - - switch ( _eType ) - { case SQLExceptionInfo::TYPE::SQLWarning: ppProvider = &m_pWarningsImage; sNormalImageID = "dialog-warning"; @@ -118,20 +111,21 @@ namespace default: break; - } - - if ( !ppProvider->get() ) - (*ppProvider) = std::make_shared<ImageProvider>(sNormalImageID); - return *ppProvider; } - std::shared_ptr< LabelProvider > const & getLabelProvider( SQLExceptionInfo::TYPE _eType, bool _bSubLabel ) const - { - std::shared_ptr< LabelProvider >* ppProvider( &m_pErrorLabel ); - TranslateId pLabelID( STR_EXCEPTION_ERROR ); + if (!ppProvider->get()) + (*ppProvider) = std::make_shared<ImageProvider>(sNormalImageID); + return *ppProvider; + } - switch ( _eType ) - { + std::shared_ptr<LabelProvider> const& getLabelProvider(SQLExceptionInfo::TYPE _eType, + bool _bSubLabel) const + { + std::shared_ptr<LabelProvider>* ppProvider(&m_pErrorLabel); + TranslateId pLabelID(STR_EXCEPTION_ERROR); + + switch (_eType) + { case SQLExceptionInfo::TYPE::SQLWarning: ppProvider = &m_pWarningsLabel; pLabelID = STR_EXCEPTION_WARNING; @@ -143,117 +137,121 @@ namespace break; default: break; - } - - if ( !ppProvider->get() ) - (*ppProvider) = std::make_shared<LabelProvider>( pLabelID ); - return *ppProvider; } - }; - - /// a stripped version of the SQLException, packed for displaying - struct ExceptionDisplayInfo - { - SQLExceptionInfo::TYPE eType; + if (!ppProvider->get()) + (*ppProvider) = std::make_shared<LabelProvider>(pLabelID); + return *ppProvider; + } +}; - std::shared_ptr< ImageProvider > pImageProvider; - std::shared_ptr< LabelProvider > pLabelProvider; +/// a stripped version of the SQLException, packed for displaying +struct ExceptionDisplayInfo +{ + SQLExceptionInfo::TYPE eType; - bool bSubEntry; + std::shared_ptr<ImageProvider> pImageProvider; + std::shared_ptr<LabelProvider> pLabelProvider; - OUString sMessage; - OUString sSQLState; - OUString sErrorCode; + bool bSubEntry; - ExceptionDisplayInfo() : eType( SQLExceptionInfo::TYPE::Undefined ), bSubEntry( false ) { } - explicit ExceptionDisplayInfo( SQLExceptionInfo::TYPE _eType ) : eType( _eType ), bSubEntry( false ) { } - }; + OUString sMessage; + OUString sSQLState; + OUString sErrorCode; - bool lcl_hasDetails( const ExceptionDisplayInfo& _displayInfo ) + ExceptionDisplayInfo() + : eType(SQLExceptionInfo::TYPE::Undefined) + , bSubEntry(false) { - return ( !_displayInfo.sErrorCode.isEmpty() ) - || ( !_displayInfo.sSQLState.isEmpty() - && _displayInfo.sSQLState != "S1000" - ); } + explicit ExceptionDisplayInfo(SQLExceptionInfo::TYPE _eType) + : eType(_eType) + , bSubEntry(false) + { + } +}; - typedef std::vector< ExceptionDisplayInfo > ExceptionDisplayChain; +bool lcl_hasDetails(const ExceptionDisplayInfo& _displayInfo) +{ + return (!_displayInfo.sErrorCode.isEmpty()) + || (!_displayInfo.sSQLState.isEmpty() && _displayInfo.sSQLState != "S1000"); +} - /// strips the [OOoBase] vendor identifier from the given error message, if applicable - OUString lcl_stripOOoBaseVendor( const OUString& _rErrorMessage ) - { - OUString sErrorMessage( _rErrorMessage ); +typedef std::vector<ExceptionDisplayInfo> ExceptionDisplayChain; - const OUString sVendorIdentifier( ::connectivity::SQLError::getMessagePrefix() ); - if ( sErrorMessage.startsWith( sVendorIdentifier ) ) - { - // characters to strip - sal_Int32 nStripLen( sVendorIdentifier.getLength() ); - // usually, there should be a whitespace between the vendor and the real message - while ( ( sErrorMessage.getLength() > nStripLen ) - && ( sErrorMessage[nStripLen] == ' ' ) - ) - ++nStripLen; - sErrorMessage = sErrorMessage.copy( nStripLen ); - } +/// strips the [OOoBase] vendor identifier from the given error message, if applicable +OUString lcl_stripOOoBaseVendor(const OUString& _rErrorMessage) +{ + OUString sErrorMessage(_rErrorMessage); - return sErrorMessage; + const OUString sVendorIdentifier(::connectivity::SQLError::getMessagePrefix()); + if (sErrorMessage.startsWith(sVendorIdentifier)) + { + // characters to strip + sal_Int32 nStripLen(sVendorIdentifier.getLength()); + // usually, there should be a whitespace between the vendor and the real message + while ((sErrorMessage.getLength() > nStripLen) && (sErrorMessage[nStripLen] == ' ')) + ++nStripLen; + sErrorMessage = sErrorMessage.copy(nStripLen); } - void lcl_buildExceptionChain( const SQLExceptionInfo& _rErrorInfo, const ProviderFactory& _rFactory, ExceptionDisplayChain& _out_rChain ) - { - ExceptionDisplayChain().swap(_out_rChain); + return sErrorMessage; +} - SQLExceptionIteratorHelper iter( _rErrorInfo ); - while ( iter.hasMoreElements() ) - { - // current chain element - SQLExceptionInfo aCurrentElement; - iter.next( aCurrentElement ); +void lcl_buildExceptionChain(const SQLExceptionInfo& _rErrorInfo, const ProviderFactory& _rFactory, + ExceptionDisplayChain& _out_rChain) +{ + ExceptionDisplayChain().swap(_out_rChain); - const SQLException* pCurrentError = aCurrentElement; - assert(pCurrentError && "lcl_buildExceptionChain: iterator failure!"); - // hasMoreElements should not have returned <TRUE/> in this case + SQLExceptionIteratorHelper iter(_rErrorInfo); + while (iter.hasMoreElements()) + { + // current chain element + SQLExceptionInfo aCurrentElement; + iter.next(aCurrentElement); - ExceptionDisplayInfo aDisplayInfo( aCurrentElement.getType() ); + const SQLException* pCurrentError = aCurrentElement; + assert(pCurrentError && "lcl_buildExceptionChain: iterator failure!"); + // hasMoreElements should not have returned <TRUE/> in this case - aDisplayInfo.sMessage = pCurrentError->Message.trim(); - aDisplayInfo.sSQLState = pCurrentError->SQLState; - if ( pCurrentError->ErrorCode ) - aDisplayInfo.sErrorCode = OUString::number( pCurrentError->ErrorCode ); + ExceptionDisplayInfo aDisplayInfo(aCurrentElement.getType()); - if ( aDisplayInfo.sMessage.isEmpty() - && !lcl_hasDetails( aDisplayInfo ) - ) - { - OSL_FAIL( "lcl_buildExceptionChain: useless exception: no state, no error code, no message!" ); - continue; - } + aDisplayInfo.sMessage = pCurrentError->Message.trim(); + aDisplayInfo.sSQLState = pCurrentError->SQLState; + if (pCurrentError->ErrorCode) + aDisplayInfo.sErrorCode = OUString::number(pCurrentError->ErrorCode); + + if (aDisplayInfo.sMessage.isEmpty() && !lcl_hasDetails(aDisplayInfo)) + { + OSL_FAIL( + "lcl_buildExceptionChain: useless exception: no state, no error code, no message!"); + continue; + } - aDisplayInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() ); - aDisplayInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), false ); + aDisplayInfo.pImageProvider = _rFactory.getImageProvider(aCurrentElement.getType()); + aDisplayInfo.pLabelProvider = _rFactory.getLabelProvider(aCurrentElement.getType(), false); - _out_rChain.push_back(std::move(aDisplayInfo)); + _out_rChain.push_back(std::move(aDisplayInfo)); - if ( aCurrentElement.getType() == SQLExceptionInfo::TYPE::SQLContext ) + if (aCurrentElement.getType() == SQLExceptionInfo::TYPE::SQLContext) + { + const SQLContext* pContext = aCurrentElement; + if (!pContext->Details.isEmpty()) { - const SQLContext* pContext = aCurrentElement; - if ( !pContext->Details.isEmpty() ) - { - ExceptionDisplayInfo aSubInfo( aCurrentElement.getType() ); - - aSubInfo.sMessage = pContext->Details; - aSubInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() ); - aSubInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), true ); - aSubInfo.bSubEntry = true; - - _out_rChain.push_back(std::move(aSubInfo)); - } + ExceptionDisplayInfo aSubInfo(aCurrentElement.getType()); + + aSubInfo.sMessage = pContext->Details; + aSubInfo.pImageProvider = _rFactory.getImageProvider(aCurrentElement.getType()); + aSubInfo.pLabelProvider + = _rFactory.getLabelProvider(aCurrentElement.getType(), true); + aSubInfo.bSubEntry = true; + + _out_rChain.push_back(std::move(aSubInfo)); } } } } +} namespace { commit 5f83cc9a31a0fe2c972f89d6708012126214f590 Author: Michael Weghorn <[email protected]> AuthorDate: Fri Feb 20 13:53:38 2026 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Sat Feb 21 02:32:46 2026 +0100 tdf#130857 qt weld: Support SQL Exception 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 like this: * start Writer * enable "View" -> "Toolbars" -> "Mail Merge" * press the "Address Book Source" toolbar button * press the "Assign" button in the dialog * in the "Address Book Data Source Wizard" dialog that shows up, select "Thunderbird" and press "Next" button * in the dialog showing an error message that shows up, press the "More" button Change-Id: Iee094a83b739abefe4f36c117289fe3c81c77b0f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199858 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/vcl/qt5/QtInstanceBuilder.cxx b/vcl/qt5/QtInstanceBuilder.cxx index aa7932d9a78f..9582a3e23b72 100644 --- a/vcl/qt5/QtInstanceBuilder.cxx +++ b/vcl/qt5/QtInstanceBuilder.cxx @@ -124,6 +124,7 @@ constexpr auto SUPPORTED_UI_FILES = frozen::make_unordered_set<std::u16string_vi u"dbaccess/ui/fielddialog.ui", u"dbaccess/ui/queryfilterdialog.ui", u"dbaccess/ui/savedialog.ui", + u"dbaccess/ui/sqlexception.ui", u"dbaccess/ui/tabledesignsavemodifieddialog.ui", u"desktop/ui/installforalldialog.ui", u"desktop/ui/showlicensedialog.ui", commit 59fee5976e846b2287a5ff0c07bdcd65a9bd2ea8 Author: Michael Weghorn <[email protected]> AuthorDate: Fri Feb 20 13:49:26 2026 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Sat Feb 21 02:32:40 2026 +0100 tdf#130857 qt weld: Move logic to load LO or stock icon to loadQPixmapIcon The "GtkImage" case in QtBuilder::makeObject has logic to either load a LO icon or use a system/stock icon from a Qt icon theme. Don't implement the logic there, but in the loadQPixmapIcon helper instead, and use that one in two more places. This also prepares for an upcoming commit to support the SQL error dialog where "dialog-error" etc. are used for icon names (see dbaccess/source/ui/dlg/sqlmessage.cxx) and it's expected that stock icons are used for those. (For the vcl/SalInstance* case, those are handled specially in createImage in vcl/source/app/salvtables.cxx .) Without this commit, upcoming Change-Id: Iee094a83b739abefe4f36c117289fe3c81c77b0f Author: Michael Weghorn <[email protected]> Date: Fri Feb 20 13:53:38 2026 +0100 tdf#130857 qt weld: Support SQL Exception dialog would trigger this assert: soffice.bin: .../include/vcl/qt/QtUtils.hxx:50: QPixmap toQPixmap(const Bitmap &): Assertion `!aPixmap.isNull() && "Failed to create icon pixmap"' failed. Change-Id: I086b368493267455187e0c3cff3c79520f5a7b50 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199857 Reviewed-by: Michael Weghorn <[email protected]> Tested-by: Jenkins diff --git a/include/vcl/qt/QtUtils.hxx b/include/vcl/qt/QtUtils.hxx index 1a48601cab3d..feee3b3d747f 100644 --- a/include/vcl/qt/QtUtils.hxx +++ b/include/vcl/qt/QtUtils.hxx @@ -26,7 +26,10 @@ #include <vcl/outdev.hxx> #include <QtCore/QString> +#include <QtGui/QIcon> #include <QtGui/QPixmap> +#include <QtWidgets/QApplication> +#include <QtWidgets/QStyle> inline QString toQString(const OUString& rStr) { @@ -69,8 +72,14 @@ inline QPixmap toQPixmap(const OutputDevice& rDevice) inline QPixmap loadQPixmapIcon(const OUString& rIconName) { - Bitmap aIcon(rIconName); - return toQPixmap(aIcon); + const Bitmap aBitmap(rIconName); + if (!aBitmap.IsEmpty()) + return toQPixmap(aBitmap); + + const QIcon aIcon = QIcon::fromTheme(toQString(rIconName)); + assert(!aIcon.isNull() && "No icon found for that icon name"); + const int nIconSize = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize); + return aIcon.pixmap(nIconSize); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtBuilder.cxx b/vcl/qt5/QtBuilder.cxx index c038a986bdbd..064d86bfb41c 100644 --- a/vcl/qt5/QtBuilder.cxx +++ b/vcl/qt5/QtBuilder.cxx @@ -279,20 +279,7 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std: QLabel* pLabel = new QLabel(pParentWidget); const OUString sIconName = extractIconName(rMap); if (!sIconName.isEmpty()) - { - const Image aImage = loadThemeImage(sIconName); - if (!aImage.GetBitmap().IsEmpty()) - { - pLabel->setPixmap(toQPixmap(aImage)); - } - else - { - const QIcon aIcon = QIcon::fromTheme(toQString(sIconName)); - assert(!aIcon.isNull() && "No icon found for that icon name"); - const int nIconSize = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize); - pLabel->setPixmap(aIcon.pixmap(nIconSize)); - } - } + pLabel->setPixmap(loadQPixmapIcon(sIconName)); pObject = pLabel; } else if (sName == u"GtkLabel") @@ -412,10 +399,7 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std: QToolButton* pToolButton = new QToolButton(pParentWidget); const OUString sIconName = extractIconName(rMap); if (!sIconName.isEmpty()) - { - const Image aImage = loadThemeImage(sIconName); - pToolButton->setIcon(toQPixmap(aImage)); - } + pToolButton->setIcon(loadQPixmapIcon(sIconName)); pToolButton->setText(toQString(extractLabel(rMap))); pToolButton->setCheckable(sName == u"GtkRadioToolButton" || sName == u"GtkToggleToolButton");
