diff --git a/svx/Module_svx.mk b/svx/Module_svx.mk index 089e9a919d57..e6528fa00add 100644 --- a/svx/Module_svx.mk +++ b/svx/Module_svx.mk @@ -70,6 +70,7 @@ $(eval $(call gb_Module_add_subsequentcheck_targets,svx,\ )) $(eval $(call gb_Module_add_uicheck_targets,svx,\ + UITest_svx_form \ UITest_svx_table \ )) diff --git a/svx/UITest_svx_form.mk b/svx/UITest_svx_form.mk new file mode 100644 index 000000000000..18e473824e36 --- /dev/null +++ b/svx/UITest_svx_form.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_UITest_UITest,svx_form)) + +$(eval $(call gb_UITest_add_modules,svx_form,$(SRCDIR)/svx/qa/uitest,\ + form/ \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/svx/qa/uitest/form/tdf170190.py b/svx/qa/uitest/form/tdf170190.py new file mode 100644 index 000000000000..a307ab336db1 --- /dev/null +++ b/svx/qa/uitest/form/tdf170190.py @@ -0,0 +1,53 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-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/. +# +from uitest.framework import UITestCase +from com.sun.star.awt import Size + +# Bug 170190 - Form based filter reads wrong filter string +class tdf170190(UITestCase): + def test_tdf170190(self): + with self.ui_test.create_doc_in_start_center("writer") as document: + # a form on the Bibliography table, filtered by two conditions on the same column + xForm = document.createInstance("com.sun.star.form.component.DataForm") + xForm.DataSourceName = "Bibliography" + xForm.Command = "biblio" + xForm.CommandType = 0 # TABLE + xForm.Filter = "\"Title\" LIKE 'A%' AND \"Title\" LIKE '%e'" + xForm.ApplyFilter = True + document.DrawPage.Forms.insertByName("Form", xForm) + + xTextField = document.createInstance("com.sun.star.form.component.TextField") + xTextField.DataField = "Title" + xForm.insertByName("Title", xTextField) + xShape = document.createInstance("com.sun.star.drawing.ControlShape") + xShape.Size = Size(5000, 1000) + xShape.Control = xTextField + document.DrawPage.add(xShape) + + xController = document.CurrentController + xController.setFormDesignMode(False) + xToolkit = self.xContext.ServiceManager.createInstance('com.sun.star.awt.Toolkit') + xToolkit.waitUntilAllIdlesDispatched() + self.assertTrue(xForm.isLoaded()) + + # start the form based filter, which shows the current filter in the controls + xController.getControl(xTextField).setFocus() + xToolkit.waitUntilAllIdlesDispatched() + self.xUITest.executeCommand(".uno:FormFilter") + xToolkit.waitUntilAllIdlesDispatched() + + aPredicates = xController.getFormController(xForm).getPredicateExpressions() + self.xUITest.executeCommand(".uno:FormFilterExit") + + # Before the fix: AssertionError: "LIKE 'A%' AND LIKE '%e'" != "LIKE 'A%' AND '%e'" + self.assertEqual(1, len(aPredicates)) + self.assertEqual(1, len(aPredicates[0])) + self.assertEqual("LIKE 'A%' AND LIKE '%e'", " ".join(aPredicates[0][0].split())) + +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/svx/source/form/formcontroller.cxx b/svx/source/form/formcontroller.cxx index eb6bada9ea15..88a43f43fb97 100644 --- a/svx/source/form/formcontroller.cxx +++ b/svx/source/form/formcontroller.cxx @@ -3020,6 +3020,60 @@ void FormController::setFilter(::std::vector& rFieldInfos) const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetUILocaleDataWrapper() ); OUString strDecimalSeparator = rLocaleWrapper.getNumDecimalSep(); + // convert one structured condition into its UI text, e.g. "LIKE A*" + auto getCriteriaText = [&](const PropertyValue& rRefValue, const Reference< XPropertySet >& xField) -> OUString + { + OUString sPredicate,sErrorMsg; + rRefValue.Value >>= sPredicate; + std::unique_ptr< OSQLParseNode > pParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField, xConnection); + if ( pParseNode == nullptr ) + return OUString(); + + OUString sCriteria; + switch (rRefValue.Handle) + { + case css::sdb::SQLFilterOperator::EQUAL: + sCriteria += "="; + break; + case css::sdb::SQLFilterOperator::NOT_EQUAL: + sCriteria += "!="; + break; + case css::sdb::SQLFilterOperator::LESS: + sCriteria += "<"; + break; + case css::sdb::SQLFilterOperator::GREATER: + sCriteria += ">"; + break; + case css::sdb::SQLFilterOperator::LESS_EQUAL: + sCriteria += "<="; + break; + case css::sdb::SQLFilterOperator::GREATER_EQUAL: + sCriteria += ">="; + break; + case css::sdb::SQLFilterOperator::LIKE: + sCriteria += "LIKE "; + break; + case css::sdb::SQLFilterOperator::NOT_LIKE: + sCriteria += "NOT LIKE "; + break; + case css::sdb::SQLFilterOperator::SQLNULL: + sCriteria += "IS NULL"; + break; + case css::sdb::SQLFilterOperator::NOT_SQLNULL: + sCriteria += "IS NOT NULL"; + break; + } + pParseNode->parseNodeToPredicateStr( sCriteria + ,xConnection + ,xFormatter + ,xField + ,OUString() + ,aAppLocale + ,strDecimalSeparator + ,getParseContext()); + return sCriteria; + }; + // retrieving the filter for (const Sequence < PropertyValue >& rRow : aFilterRows) { @@ -3080,62 +3134,20 @@ void FormController::setFilter(::std::vector& rFieldInfos) // do we already have the control ? if (aRow.find(rFieldInfo.xText) != aRow.end()) { + // further conditions on the same field need their operator too + OUString sCriteria = getCriteriaText(rRefValue, xField); + if (sCriteria.isEmpty()) + sCriteria = ::comphelper::getString(rRefValue.Value); OString aVal = m_pParser->getContext().getIntlKeywordAscii(IParseContext::InternationalKeyCode::And); aRow[rFieldInfo.xText] = aRow[rFieldInfo.xText] + " " + OStringToOUString(aVal, RTL_TEXTENCODING_ASCII_US) + " " + - ::comphelper::getString(rRefValue.Value); + sCriteria; } else { - OUString sPredicate,sErrorMsg; - rRefValue.Value >>= sPredicate; - std::unique_ptr< OSQLParseNode > pParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField, xConnection); - if ( pParseNode != nullptr ) - { - OUString sCriteria; - switch (rRefValue.Handle) - { - case css::sdb::SQLFilterOperator::EQUAL: - sCriteria += "="; - break; - case css::sdb::SQLFilterOperator::NOT_EQUAL: - sCriteria += "!="; - break; - case css::sdb::SQLFilterOperator::LESS: - sCriteria += "<"; - break; - case css::sdb::SQLFilterOperator::GREATER: - sCriteria += ">"; - break; - case css::sdb::SQLFilterOperator::LESS_EQUAL: - sCriteria += "<="; - break; - case css::sdb::SQLFilterOperator::GREATER_EQUAL: - sCriteria += ">="; - break; - case css::sdb::SQLFilterOperator::LIKE: - sCriteria += "LIKE "; - break; - case css::sdb::SQLFilterOperator::NOT_LIKE: - sCriteria += "NOT LIKE "; - break; - case css::sdb::SQLFilterOperator::SQLNULL: - sCriteria += "IS NULL"; - break; - case css::sdb::SQLFilterOperator::NOT_SQLNULL: - sCriteria += "IS NOT NULL"; - break; - } - pParseNode->parseNodeToPredicateStr( sCriteria - ,xConnection - ,xFormatter - ,xField - ,OUString() - ,aAppLocale - ,strDecimalSeparator - ,getParseContext()); + OUString sCriteria = getCriteriaText(rRefValue, xField); + if (!sCriteria.isEmpty()) aRow[rFieldInfo.xText] = sCriteria; - } } } }