tdf#170190 svx: keep the operator of every condition in form filter text

When a filter condition on a column has more than one part, e.g.
"LIKE A* AND LIKE *e", only the first part was converted back to UI text
with its operator; the rest were appended as bare values
("LIKE A* AND *e"). Convert all parts the same way and add a UITest.

Change-Id: Id6a2ecd5593003c3a9fcef1955f2c672ec1ed520
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211425
Tested-by: Jenkins
Reviewed-by: Vissarion Fisikopoulos <vfisikop@libreoffice.org>
This commit is contained in:
Vissarion Fisikopoulos
2026-10-05 09:32:43 +02:00
parent 0e9f94c375
commit 34f425f8b8
4 changed files with 131 additions and 49 deletions
+1
View File
@@ -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 \
))
+16
View File
@@ -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:
+53
View File
@@ -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:
+61 -49
View File
@@ -3020,6 +3020,60 @@ void FormController::setFilter(::std::vector<FmFieldInfo>& 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<FmFieldInfo>& 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;
}
}
}
}