https://bugs.documentfoundation.org/show_bug.cgi?id=174372

            Bug ID: 174372
           Summary: Replace field not initialized when non-empty search
                    string is provided via UNO
           Product: LibreOffice
           Version: 25.8.1.1 release
          Hardware: All
                OS: All
            Status: UNCONFIRMED
          Severity: normal
          Priority: medium
         Component: Writer
          Assignee: [email protected]
          Reporter: [email protected]

Description:
When opening the Find & Replace dialog and initializing it via the UNO
dispatcher with both SearchItem.SearchString and SearchItem.ReplaceString, the
search field is populated correctly, but the replace field remains empty.
The replace field can be populated by passing an empty search string instead.
However, doing so causes the dialog to restore the previous search string from
its history rather than retaining the intended search string.
This makes it impossible to reliably initialize both fields in a single UNO
operation.

Steps to Reproduce:
1. Start LibreOffice Writer.
2. Open a document.
3. Close the Find & Replace dialog, if it is already open.
4. Connect to LibreOffice using the UNO API.
5. Execute the following dispatcher command:

[python]

def prop(name, value):
    p = uno.createUnoStruct(
        "com.sun.star.beans.PropertyValue"
    )
    p.Name = name
    p.Value = value
    return p

dispatcher.executeDispatch(
    frame,
    ".uno:ExecuteSearch",
    "",
    0,
    (
        prop("SearchItem.SearchString", "Teststring"),
        prop("SearchItem.ReplaceString", "ersetzt"),
        prop("SearchItem.Backward", False),
        prop("SearchItem.Command", 0),
    )
)

6. Open the Find & Replace dialog using .uno:SearchDialog.

Actual Results:
• The search field contains "Teststring".
• The replace field is empty.

If the same command is executed with an empty search string:
python
prop("SearchItem.SearchString", ""),
prop("SearchItem.ReplaceString", "ersetzt"),
the replace field is populated with "ersetzt".
However, the search field is then restored from the previous search history,
rather than being initialized with the requested search string.

Expected Results:
Both fields should be initialized independently when their corresponding values
are provided through UNO:
    • SearchItem.SearchString should initialize the search field.
    • SearchItem.ReplaceString should initialize the replace field.
The presence of a non-empty search string should not prevent the replace field
from being initialized.
Existing search and replace history should still be respected when no explicit
value is provided.


Reproducible: Always


User Profile Reset: No

Additional Info:
Additional observations

The behaviour is reproducible even after completely restarting LibreOffice.
The two fields appear to be initialized through different code paths.
In SvxSearchDialog::Init_Impl() in cui/source/dialogs/srchdlg.cxx, the
initialization of the replace field appears to be nested in an else if branch
following the initialization of the search field.
Conceptually, the relevant logic looks like this:
cpp
if (!pSearchItem->GetSearchString().isEmpty() && bSetSearch)
{
    m_xSearchLB->set_entry_text(
        pSearchItem->GetSearchString()
    );
}
else if (!aSearchStrings.empty())
{
    // Restore search history

    OUString aReplaceTxt =
        pSearchItem->GetReplaceString();

    if (!aReplaceStrings.empty())
        aReplaceTxt = aReplaceStrings[0];

    if (bSetReplace && !bAttributes)
        m_xReplaceLB->set_entry_text(aReplaceTxt);
}
As a consequence, providing a non-empty search string prevents the code
responsible for initializing the replace field from being executed.

###

Suggested fix
The initialization of the two fields should be independent rather than mutually
exclusive.
For example, conceptually:
cpp
if (bSetSearch)
{
    if (!pSearchItem->GetSearchString().isEmpty())
    {
        m_xSearchLB->set_entry_text(
            pSearchItem->GetSearchString()
        );
    }
    else if (!aSearchStrings.empty())
    {
        m_xSearchLB->set_entry_text(
            aSearchStrings[0]
        );
    }
}

if (bSetReplace && !bAttributes)
{
    OUString aReplaceTxt =
        pSearchItem->GetReplaceString();

    if (aReplaceTxt.isEmpty() && !aReplaceStrings.empty())
        aReplaceTxt = aReplaceStrings[0];

    m_xReplaceLB->set_entry_text(aReplaceTxt);
}
This is only an illustration of the intended behaviour. The actual
implementation should preserve the existing history and initialization
semantics, including the handling of empty values.
The important point is that initializing the search field must not bypass
initialization of the replace field.
Impact
This behaviour makes it difficult for extensions and macros to reliably prepare
the Find & Replace dialog for user interaction.
A typical use case is an extension that pre-populates both fields and then lets
the user decide whether to perform a single replacement or replace all
occurrences.
Currently, this requires multiple dispatcher calls and manipulating the search
history indirectly, which is fragile and can cause unexpected changes to the
current search state.
The user should be able to initialize both fields in one operation without
triggering an actual replacement.

(well, i'm not a programmer but prompted chatgpt to narrow down this problem as
detailed as possible - hope it is useful information ... it took me several
full working days to figure out why there were issues with the replacement
string - which definitly is ok when this bug will be fixed :-)


Version: 26.8.1.1 (X86_64)
Build ID: 680(Build:1)
CPU threads: 8; OS: Linux 6.12; UI render: default; VCL: kf6 (cairo+xcb)
Locale: de-DE (de_DE.UTF-8); UI: de-DE
Calc: threaded

Operating System: openSUSE Leap 16.0
KDE Plasma Version: 6.4.2
KDE Frameworks Version: 6.16.0
Qt Version: 6.9.1
Kernel Version: 6.12.0-160000.40-default (64-bit)
Graphics Platform: X11

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to