/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: */ |