1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
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>
21 #include <scresid.hxx>
25 SearchResultsDlg::SearchResultsDlg(SfxBindings
* _pBindings
, weld::Window
* pParent
)
26 : SfxDialogController(pParent
, u
"modules/scalc/ui/searchresults.ui"_ustr
, u
"SearchResultsDialog"_ustr
)
27 , aSkipped(ScResId(SCSTR_SKIPPED
))
28 , mpBindings(_pBindings
)
31 , mxList(m_xBuilder
->weld_tree_view(u
"results"_ustr
))
32 , mxSearchResults(m_xBuilder
->weld_label(u
"lbSearchResults"_ustr
))
33 , mxShowDialog(m_xBuilder
->weld_check_button(u
"cbShow"_ustr
))
35 mxList
->set_size_request(mxList
->get_approximate_digit_width() * 50, mxList
->get_height_rows(15));
36 mxShowDialog
->connect_toggled(LINK(this, SearchResultsDlg
, OnShowToggled
));
37 std::vector
<int> aWidths
39 o3tl::narrowing
<int>(mxList
->get_approximate_digit_width() * 10),
40 o3tl::narrowing
<int>(mxList
->get_approximate_digit_width() * 10)
42 mxList
->set_column_fixed_widths(aWidths
);
43 mxList
->connect_selection_changed(LINK(this, SearchResultsDlg
, ListSelectHdl
));
44 mxList
->connect_column_clicked(LINK(this, SearchResultsDlg
, HeaderBarClick
));
47 SearchResultsDlg::~SearchResultsDlg()
49 // tdf#133807 if the search dialog is shown then re-present that dialog
50 // when this results dialog is dismissed
51 SfxViewFrame
* pViewFrame
= mpBindings
->GetDispatcher()->GetFrame();
54 SfxChildWindow
* pChildWindow
= pViewFrame
->GetChildWindow(
55 SvxSearchDialogWrapper::GetChildWindowId());
58 SvxSearchDialog
* pSearchDlg
= static_cast<SvxSearchDialog
*>(pChildWindow
->GetController().get());
61 pSearchDlg
->Present();
67 weld::TreeView
& mrList
;
70 static const size_t mnMaximum
= 1000;
71 ListWrapper(weld::TreeView
& rList
)
81 void Insert(const OUString
&rTabName
,
82 const ScAddress
&rPos
,
83 formula::FormulaGrammar::AddressConvention eConvention
,
84 const OUString
&rText
)
86 if (mnCount
++ < mnMaximum
)
88 mrList
.append_text(rTabName
);
89 int nPos
= mrList
.n_children() - 1;
90 mrList
.set_text(nPos
, rPos
.Format(ScRefFlags::ADDR_ABS
,
91 nullptr, eConvention
), 1);
92 mrList
.set_text(nPos
, rText
, 2);
98 void SearchResultsDlg::FillResults( ScDocument
& rDoc
, const ScRangeList
&rMatchedRanges
, bool bCellNotes
,
99 bool bEmptyCells
, bool bMatchedRangesWereClamped
)
101 ListWrapper
aList(*mxList
);
102 std::vector
<OUString
> aTabNames
= rDoc
.GetAllTableNames();
103 SCTAB nTabCount
= aTabNames
.size();
105 // tdf#92160 - too many results blow the widget's mind
106 size_t nMatchMax
= rMatchedRanges
.size();
107 if (nMatchMax
> ListWrapper::mnMaximum
)
108 nMatchMax
= ListWrapper::mnMaximum
;
110 if (bCellNotes
|| bEmptyCells
)
112 for (size_t i
= 0, n
= nMatchMax
; i
< n
; ++i
)
114 ScRange
const & rRange( rMatchedRanges
[i
] );
115 // Bear in mind that mostly the range is one address position
116 // or a column or a row joined.
117 ScAddress
aPos( rRange
.aStart
);
118 for ( ; aPos
.Tab() <= rRange
.aEnd
.Tab(); aPos
.IncTab())
120 if (aPos
.Tab() >= nTabCount
)
121 break; // can this even happen? we just searched on existing sheets ...
122 for (aPos
.SetCol( rRange
.aStart
.Col()); aPos
.Col() <= rRange
.aEnd
.Col(); aPos
.IncCol())
124 for (aPos
.SetRow( rRange
.aStart
.Row()); aPos
.Row() <= rRange
.aEnd
.Row(); aPos
.IncRow())
128 const ScPostIt
* pNote
= rDoc
.GetNote( aPos
);
130 aList
.Insert(aTabNames
[aPos
.Tab()], aPos
,
131 rDoc
.GetAddressConvention(),
136 aList
.Insert(aTabNames
[aPos
.Tab()], aPos
,
137 rDoc
.GetAddressConvention(),
138 rDoc
.GetString(aPos
));
147 for (size_t i
= 0, n
= nMatchMax
; i
< n
; ++i
)
149 ScCellIterator
aIter(rDoc
, rMatchedRanges
[i
]);
150 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
152 const ScAddress
& aPos
= aIter
.GetPos();
153 if (aPos
.Tab() >= nTabCount
)
154 // Out-of-bound sheet index.
157 aList
.Insert(aTabNames
[aPos
.Tab()], aPos
,
158 rDoc
.GetAddressConvention(),
159 rDoc
.GetString(aPos
));
164 OUString aSearchResultsMsg
;
165 if (bMatchedRangesWereClamped
)
167 aSearchResultsMsg
= ScResId(SCSTR_RESULTS_CLAMPED
);
168 aSearchResultsMsg
= aSearchResultsMsg
.replaceFirst("%1", OUString::number(1000));
172 OUString
aTotal(ScResId(SCSTR_TOTAL
, aList
.mnCount
));
173 aSearchResultsMsg
= aTotal
.replaceFirst("%1", OUString::number(aList
.mnCount
));
174 if (aList
.mnCount
> ListWrapper::mnMaximum
)
175 aSearchResultsMsg
+= " " + ScGlobal::ReplaceOrAppend( aSkipped
, u
"%1", OUString::number( ListWrapper::mnMaximum
) );
177 mxSearchResults
->set_label(aSearchResultsMsg
);
182 void SearchResultsDlg::Close()
186 // Remove this dialog from the view frame after the dialog gets
187 // dismissed, else it would keep popping up endlessly!
188 SfxDispatcher
* pDispacher
= mpBindings
->GetDispatcher();
189 SfxBoolItem
aItem(SID_SEARCH_RESULTS_DIALOG
, false);
192 pDispacher
->ExecuteList(SID_SEARCH_RESULTS_DIALOG
,
193 SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
, { &aItem
});
197 SfxDialogController::Close();
200 IMPL_LINK(SearchResultsDlg
, HeaderBarClick
, int, nColumn
, void)
204 mxList
->make_sorted();
208 bool bSortAtoZ
= mxList
->get_sort_order();
210 //set new arrow positions in headerbar
211 if (nColumn
== mxList
->get_sort_column())
213 bSortAtoZ
= !bSortAtoZ
;
214 mxList
->set_sort_order(bSortAtoZ
);
218 int nOldSortColumn
= mxList
->get_sort_column();
219 if (nOldSortColumn
!= -1)
220 mxList
->set_sort_indicator(TRISTATE_INDET
, nOldSortColumn
);
221 mxList
->set_sort_column(nColumn
);
227 mxList
->set_sort_indicator(bSortAtoZ
? TRISTATE_TRUE
: TRISTATE_FALSE
, nColumn
);
231 IMPL_LINK_NOARG( SearchResultsDlg
, ListSelectHdl
, weld::TreeView
&, void )
236 int nEntry
= mxList
->get_selected_index();
237 OUString aTabStr
= mxList
->get_text(nEntry
, 0);
238 OUString aPosStr
= mxList
->get_text(nEntry
, 1);
241 if (!mpDoc
->GetTable(aTabStr
, nTab
))
242 // No sheet with specified name.
246 ScRefFlags nRes
= aPos
.Parse(aPosStr
, *mpDoc
, mpDoc
->GetAddressConvention());
247 if (!(nRes
& ScRefFlags::VALID
))
248 // Invalid address string.
252 if (ScTabViewShell
* pScViewShell
= ScTabViewShell::GetActiveViewShell())
254 pScViewShell
->SetTabNo(nTab
);
255 pScViewShell
->SetCursor(aPos
.Col(), aPos
.Row());
256 pScViewShell
->AlignToCursor(aPos
.Col(), aPos
.Row(), SC_FOLLOW_JUMP
);
260 IMPL_STATIC_LINK( SearchResultsDlg
, OnShowToggled
, weld::Toggleable
&, rButton
, void )
262 if (ScTabViewShell
* pScViewShell
= ScTabViewShell::GetActiveViewShell())
264 ScViewOptions
aViewOpt( pScViewShell
->GetViewData().GetOptions() );
265 aViewOpt
.SetOption( VOPT_SUMMARY
, rButton
.get_active() );
266 pScViewShell
->GetViewData().SetOptions( aViewOpt
);
270 SearchResultsDlgWrapper::SearchResultsDlgWrapper(
271 vcl::Window
* _pParent
, sal_uInt16 nId
, SfxBindings
* pBindings
, SfxChildWinInfo
* /*pInfo*/)
272 : SfxChildWindow(_pParent
, nId
)
273 , m_xDialog(std::make_shared
<SearchResultsDlg
>(pBindings
, _pParent
->GetFrameWeld()))
275 SetController(m_xDialog
);
278 SearchResultsDlgWrapper::~SearchResultsDlgWrapper() {}
280 SfxChildWinInfo
SearchResultsDlgWrapper::GetInfo() const
282 SfxChildWinInfo aInfo
= SfxChildWindow::GetInfo();
283 aInfo
.bVisible
= false;
287 SFX_IMPL_CHILDWINDOW_WITHID(SearchResultsDlgWrapper
, SID_SEARCH_RESULTS_DIALOG
);
291 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */