Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/dialogs/searchresults.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include <o3tl/safeint.hxx>
11
#include <searchresults.hxx>
12
#include <sfx2/bindings.hxx>
13
#include <sfx2/dispatch.hxx>
14
#include <sfx2/viewfrm.hxx>
15
#include <svx/srchdlg.hxx>
16
#include <dociter.hxx>
17
#include <document.hxx>
18
#include <tabvwsh.hxx>
19
#include <strings.hrc>
20
#include <sc.hrc>
21
#include <scresid.hxx>
22
23
namespace sc {
24
25
SearchResultsDlg::SearchResultsDlg(SfxBindings* _pBindings, weld::Window* pParent)
26
0
    : SfxDialogController(pParent, u"modules/scalc/ui/searchresults.ui"_ustr, u"SearchResultsDialog"_ustr)
27
0
    , aSkipped(ScResId(SCSTR_SKIPPED))
28
0
    , mpBindings(_pBindings)
29
0
    , mpDoc(nullptr)
30
0
    , mbSorted(false)
31
0
    , mxList(m_xBuilder->weld_tree_view(u"results"_ustr))
32
0
    , mxSearchResults(m_xBuilder->weld_label(u"lbSearchResults"_ustr))
33
0
    , mxShowDialog(m_xBuilder->weld_check_button(u"cbShow"_ustr))
34
0
{
35
0
    mxList->set_size_request(mxList->get_approximate_digit_width() * 50, mxList->get_height_rows(15));
36
0
    mxShowDialog->connect_toggled(LINK(this, SearchResultsDlg, OnShowToggled));
37
0
    std::vector<int> aWidths
38
0
    {
39
0
        o3tl::narrowing<int>(mxList->get_approximate_digit_width() * 10),
40
0
        o3tl::narrowing<int>(mxList->get_approximate_digit_width() * 10)
41
0
    };
42
0
    mxList->set_column_fixed_widths(aWidths);
43
0
    mxList->connect_selection_changed(LINK(this, SearchResultsDlg, ListSelectHdl));
44
0
    mxList->connect_column_clicked(LINK(this, SearchResultsDlg, HeaderBarClick));
45
0
}
46
47
SearchResultsDlg::~SearchResultsDlg()
48
0
{
49
    // tdf#133807 if the search dialog is shown then re-present that dialog
50
    // when this results dialog is dismissed
51
0
    SfxViewFrame* pViewFrame = mpBindings->GetDispatcher()->GetFrame();
52
0
    if (!pViewFrame)
53
0
        return;
54
0
    SfxChildWindow* pChildWindow = pViewFrame->GetChildWindow(
55
0
            SvxSearchDialogWrapper::GetChildWindowId());
56
0
    if (!pChildWindow)
57
0
        return;
58
0
    SvxSearchDialog* pSearchDlg = static_cast<SvxSearchDialog*>(pChildWindow->GetController().get());
59
0
    if (!pSearchDlg)
60
0
        return;
61
0
    pSearchDlg->Present();
62
0
}
63
64
namespace
65
{
66
    class ListWrapper {
67
        weld::TreeView& mrList;
68
        const ScDocument& mrDoc;
69
    public:
70
        size_t mnCount = 0;
71
        static const size_t mnMaximum = 1000;
72
        ListWrapper(weld::TreeView& rList, const ScDocument& rDoc)
73
0
            : mrList(rList)
74
0
            , mrDoc(rDoc)
75
0
        {
76
0
            mrList.clear();
77
0
            mrList.freeze();
78
0
        }
79
        ~ListWrapper()
80
0
        {
81
0
            mrList.thaw();
82
0
        }
83
        void Insert(const ScAddress &rPos, const OUString &rText)
84
0
        {
85
0
            if (mnCount++ < mnMaximum)
86
0
            {
87
0
                OUString aTabName;
88
0
                mrDoc.GetName(rPos.Tab(), aTabName);
89
0
                mrList.append_text(aTabName);
90
0
                int nPos = mrList.n_children() - 1;
91
0
                mrList.set_text(nPos, rPos.Format(ScRefFlags::ADDR_ABS,
92
0
                                      nullptr, mrDoc.GetAddressConvention()), 1);
93
0
                mrList.set_text(nPos, rText, 2);
94
0
            }
95
0
        }
96
    };
97
}
98
99
void SearchResultsDlg::FillResults( ScDocument& rDoc, const ScRangeList &rMatchedRanges, bool bCellNotes,
100
        bool bEmptyCells, bool bMatchedRangesWereClamped )
101
0
{
102
0
    ListWrapper aList(*mxList, rDoc);
103
104
0
    for (const auto& rRange : rMatchedRanges)
105
0
    {
106
0
        if (bCellNotes || bEmptyCells)
107
0
        {
108
            // Bear in mind that mostly the range is one address position
109
            // or a column or a row joined.
110
0
            ScAddress aPos( rRange.aStart );
111
0
            for ( ; aPos.Tab() <= rRange.aEnd.Tab(); aPos.IncTab())
112
0
            {
113
0
                for (aPos.SetCol( rRange.aStart.Col()); aPos.Col() <= rRange.aEnd.Col(); aPos.IncCol())
114
0
                {
115
0
                    for (aPos.SetRow( rRange.aStart.Row()); aPos.Row() <= rRange.aEnd.Row(); aPos.IncRow())
116
0
                    {
117
0
                        if (bCellNotes)
118
0
                        {
119
0
                            const ScPostIt* pNote = rDoc.GetNote( aPos);
120
0
                            if (pNote)
121
0
                                aList.Insert(aPos, pNote->GetText());
122
0
                        }
123
0
                        else  // bEmptyCells
124
0
                        {
125
0
                            aList.Insert(aPos, rDoc.GetString(aPos));
126
0
                        }
127
0
                    }
128
0
                }
129
0
            }
130
0
        }
131
0
        else
132
0
        {
133
0
            ScCellIterator aIter(rDoc, rRange);
134
0
            for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
135
0
            {
136
0
                const ScAddress& aPos = aIter.GetPos();
137
0
                aList.Insert(aPos, rDoc.GetString(aPos));
138
0
            }
139
0
        }
140
0
    }
141
142
0
    OUString aSearchResultsMsg;
143
0
    if (bMatchedRangesWereClamped)
144
0
    {
145
0
        aSearchResultsMsg = ScResId(SCSTR_RESULTS_CLAMPED);
146
0
        aSearchResultsMsg = aSearchResultsMsg.replaceFirst("%1", OUString::number(1000));
147
0
    }
148
0
    else
149
0
    {
150
0
        OUString aTotal(ScResId(SCSTR_TOTAL, aList.mnCount));
151
0
        aSearchResultsMsg = aTotal.replaceFirst("%1", OUString::number(aList.mnCount));
152
0
        if (aList.mnCount > ListWrapper::mnMaximum)
153
0
            aSearchResultsMsg += " " + ScGlobal::ReplaceOrAppend( aSkipped, u"%1", OUString::number( ListWrapper::mnMaximum ) );
154
0
    }
155
0
    mxSearchResults->set_label(aSearchResultsMsg);
156
157
0
    mpDoc = &rDoc;
158
0
}
159
160
void SearchResultsDlg::Close()
161
0
{
162
0
    if (mpBindings)
163
0
    {
164
        // Remove this dialog from the view frame after the dialog gets
165
        // dismissed, else it would keep popping up endlessly!
166
0
        SfxDispatcher* pDispacher = mpBindings ->GetDispatcher();
167
0
        SfxBoolItem aItem(SID_SEARCH_RESULTS_DIALOG, false);
168
0
        if (pDispacher)
169
0
        {
170
0
            pDispacher->ExecuteList(SID_SEARCH_RESULTS_DIALOG,
171
0
                SfxCallMode::SYNCHRON | SfxCallMode::RECORD, { &aItem });
172
0
        }
173
0
    }
174
175
0
    SfxDialogController::Close();
176
0
}
177
178
IMPL_LINK(SearchResultsDlg, HeaderBarClick, int, nColumn, void)
179
0
{
180
0
    if (!mbSorted)
181
0
    {
182
0
        mxList->make_sorted();
183
0
        mbSorted = true;
184
0
    }
185
186
0
    bool bSortAtoZ = mxList->get_sort_order();
187
188
    //set new arrow positions in headerbar
189
0
    if (nColumn == mxList->get_sort_column())
190
0
    {
191
0
        bSortAtoZ = !bSortAtoZ;
192
0
        mxList->set_sort_order(bSortAtoZ);
193
0
    }
194
0
    else
195
0
    {
196
0
        int nOldSortColumn = mxList->get_sort_column();
197
0
        if (nOldSortColumn != -1)
198
0
            mxList->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
199
0
        mxList->set_sort_column(nColumn);
200
0
    }
201
202
0
    if (nColumn != -1)
203
0
    {
204
        //sort lists
205
0
        mxList->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
206
0
    }
207
0
}
208
209
IMPL_LINK_NOARG( SearchResultsDlg, ListSelectHdl, weld::TreeView&, void )
210
0
{
211
0
    if (!mpDoc)
212
0
        return;
213
214
0
    int nEntry = mxList->get_selected_index();
215
0
    OUString aTabStr = mxList->get_text(nEntry, 0);
216
0
    OUString aPosStr = mxList->get_text(nEntry, 1);
217
218
0
    SCTAB nTab = -1;
219
0
    if (!mpDoc->GetTable(aTabStr, nTab))
220
        // No sheet with specified name.
221
0
        return;
222
223
0
    ScAddress aPos;
224
0
    ScRefFlags nRes = aPos.Parse(aPosStr, *mpDoc, mpDoc->GetAddressConvention());
225
0
    if (!(nRes & ScRefFlags::VALID))
226
        // Invalid address string.
227
0
        return;
228
229
    // Jump to the cell.
230
0
    if (ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell())
231
0
    {
232
0
        pScViewShell->SetTabNo(nTab);
233
0
        pScViewShell->SetCursor(aPos.Col(), aPos.Row());
234
0
        pScViewShell->AlignToCursor(aPos.Col(), aPos.Row(), SC_FOLLOW_JUMP);
235
0
    }
236
0
}
237
238
IMPL_STATIC_LINK( SearchResultsDlg, OnShowToggled, weld::Toggleable&, rButton, void )
239
0
{
240
0
    if (ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell())
241
0
    {
242
0
        ScViewOptions aViewOpt( pScViewShell->GetViewData().GetOptions() );
243
0
        aViewOpt.SetOption(sc::ViewOption::SUMMARY, rButton.get_active());
244
0
        pScViewShell->GetViewData().SetOptions( aViewOpt );
245
0
    }
246
0
}
247
248
SearchResultsDlgWrapper::SearchResultsDlgWrapper(
249
    vcl::Window* _pParent, sal_uInt16 nId, SfxBindings* pBindings, SfxChildWinInfo* /*pInfo*/)
250
0
    : SfxChildWindow(_pParent, nId)
251
0
    , m_xDialog(std::make_shared<SearchResultsDlg>(pBindings, _pParent->GetFrameWeld()))
252
0
{
253
0
    SetController(m_xDialog);
254
0
}
255
256
0
SearchResultsDlgWrapper::~SearchResultsDlgWrapper() {}
257
258
SfxChildWinInfo SearchResultsDlgWrapper::GetInfo() const
259
0
{
260
0
    SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
261
0
    aInfo.bVisible = false;
262
0
    return aInfo;
263
0
}
264
265
SFX_IMPL_CHILDWINDOW_WITHID(SearchResultsDlgWrapper, SID_SEARCH_RESULTS_DIALOG);
266
267
}
268
269
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */