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 <searchresults.hxx>
11 #include <sfx2/bindings.hxx>
12 #include <sfx2/dispatch.hxx>
13 #include <dociter.hxx>
14 #include <document.hxx>
15 #include <tabvwsh.hxx>
16 #include <strings.hrc>
17 #include <sc.hrc>
18 #include <scresid.hxx>
19
20 namespace sc {
21
SearchResultsDlg(SfxBindings * _pBindings,weld::Window * pParent)22 SearchResultsDlg::SearchResultsDlg(SfxBindings* _pBindings, weld::Window* pParent)
23 : SfxDialogController(pParent, "modules/scalc/ui/searchresults.ui", "SearchResultsDialog")
24 , aSkipped(ScResId(SCSTR_SKIPPED))
25 , mpBindings(_pBindings)
26 , mpDoc(nullptr)
27 , mbSorted(false)
28 , mxList(m_xBuilder->weld_tree_view("results"))
29 , mxSearchResults(m_xBuilder->weld_label("lbSearchResults"))
30 , mxShowDialog(m_xBuilder->weld_check_button("cbShow"))
31 {
32 mxList->set_size_request(mxList->get_approximate_digit_width() * 50, mxList->get_height_rows(15));
33 mxShowDialog->connect_toggled(LINK(this, SearchResultsDlg, OnShowToggled));
34 std::vector<int> aWidths;
35 aWidths.push_back(mxList->get_approximate_digit_width() * 10);
36 aWidths.push_back(mxList->get_approximate_digit_width() * 10);
37 mxList->set_column_fixed_widths(aWidths);
38 mxList->connect_changed(LINK(this, SearchResultsDlg, ListSelectHdl));
39 mxList->connect_column_clicked(LINK(this, SearchResultsDlg, HeaderBarClick));
40 }
41
~SearchResultsDlg()42 SearchResultsDlg::~SearchResultsDlg()
43 {
44 }
45
46 namespace
47 {
48 class ListWrapper {
49 weld::TreeView& mrList;
50 public:
51 size_t mnCount = 0;
52 static const size_t mnMaximum = 1000;
ListWrapper(weld::TreeView & rList)53 ListWrapper(weld::TreeView& rList)
54 : mrList(rList)
55 {
56 mrList.clear();
57 mrList.freeze();
58 }
~ListWrapper()59 ~ListWrapper()
60 {
61 mrList.thaw();
62 }
Insert(const OUString & rTabName,const ScAddress & rPos,formula::FormulaGrammar::AddressConvention eConvention,const OUString & rText)63 void Insert(const OUString &rTabName,
64 const ScAddress &rPos,
65 formula::FormulaGrammar::AddressConvention eConvention,
66 const OUString &rText)
67 {
68 if (mnCount++ < mnMaximum)
69 {
70 mrList.append_text(rTabName);
71 int nPos = mrList.n_children() - 1;
72 mrList.set_text(nPos, rPos.Format(ScRefFlags::ADDR_ABS,
73 nullptr, eConvention), 1);
74 mrList.set_text(nPos, rText, 2);
75 }
76 }
77 };
78 }
79
FillResults(ScDocument * pDoc,const ScRangeList & rMatchedRanges,bool bCellNotes)80 void SearchResultsDlg::FillResults( ScDocument* pDoc, const ScRangeList &rMatchedRanges, bool bCellNotes )
81 {
82 ListWrapper aList(*mxList);
83 std::vector<OUString> aTabNames = pDoc->GetAllTableNames();
84 SCTAB nTabCount = aTabNames.size();
85
86 // tdf#92160 - too many results blow the widget's mind
87 size_t nMatchMax = rMatchedRanges.size();
88 if (nMatchMax > ListWrapper::mnMaximum)
89 nMatchMax = ListWrapper::mnMaximum;
90
91 if (bCellNotes)
92 {
93 for (size_t i = 0, n = nMatchMax; i < n; ++i)
94 {
95 /* TODO: a CellNotes iterator would come handy and might speed
96 * things up a little, though we only loop through the
97 * search/replace result positions here. */
98 ScRange const & rRange( rMatchedRanges[i] );
99 // Bear in mind that mostly the range is one address position
100 // or a column or a row joined.
101 ScAddress aPos( rRange.aStart );
102 for ( ; aPos.Tab() <= rRange.aEnd.Tab(); aPos.IncTab())
103 {
104 if (aPos.Tab() >= nTabCount)
105 break; // can this even happen? we just searched on existing sheets ...
106 for (aPos.SetCol( rRange.aStart.Col()); aPos.Col() <= rRange.aEnd.Col(); aPos.IncCol())
107 {
108 for (aPos.SetRow( rRange.aStart.Row()); aPos.Row() <= rRange.aEnd.Row(); aPos.IncRow())
109 {
110 const ScPostIt* pNote = pDoc->GetNote( aPos);
111 if (pNote)
112 aList.Insert(aTabNames[aPos.Tab()], aPos,
113 pDoc->GetAddressConvention(),
114 pNote->GetText());
115 }
116 }
117 }
118 }
119 }
120 else
121 {
122 for (size_t i = 0, n = nMatchMax; i < n; ++i)
123 {
124 ScCellIterator aIter(pDoc, rMatchedRanges[i]);
125 for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
126 {
127 const ScAddress& aPos = aIter.GetPos();
128 if (aPos.Tab() >= nTabCount)
129 // Out-of-bound sheet index.
130 continue;
131
132 aList.Insert(aTabNames[aPos.Tab()], aPos,
133 pDoc->GetAddressConvention(),
134 pDoc->GetString(aPos));
135 }
136 }
137 }
138
139 OUString aTotal(ScResId(SCSTR_TOTAL, aList.mnCount));
140 OUString aSearchResults = aTotal.replaceFirst("%1", OUString::number(aList.mnCount));
141 if (aList.mnCount > ListWrapper::mnMaximum)
142 aSearchResults += " " + ScGlobal::ReplaceOrAppend( aSkipped, "%1", OUString::number( ListWrapper::mnMaximum ) );
143 mxSearchResults->set_label(aSearchResults);
144
145 mpDoc = pDoc;
146 }
147
Close()148 void SearchResultsDlg::Close()
149 {
150 if (mpBindings)
151 {
152 // Remove this dialog from the view frame after the dialog gets
153 // dismissed, else it would keep popping up endlessly!
154 SfxDispatcher* pDispacher = mpBindings ->GetDispatcher();
155 SfxBoolItem aItem(SID_SEARCH_RESULTS_DIALOG, false);
156 if (pDispacher)
157 {
158 pDispacher->ExecuteList(SID_SEARCH_RESULTS_DIALOG,
159 SfxCallMode::SYNCHRON | SfxCallMode::RECORD, { &aItem });
160 }
161 }
162
163 SfxDialogController::Close();
164 }
165
IMPL_LINK(SearchResultsDlg,HeaderBarClick,int,nColumn,void)166 IMPL_LINK(SearchResultsDlg, HeaderBarClick, int, nColumn, void)
167 {
168 if (!mbSorted)
169 {
170 mxList->make_sorted();
171 mbSorted = true;
172 }
173
174 bool bSortAtoZ = mxList->get_sort_order();
175
176 //set new arrow positions in headerbar
177 if (nColumn == mxList->get_sort_column())
178 {
179 bSortAtoZ = !bSortAtoZ;
180 mxList->set_sort_order(bSortAtoZ);
181 }
182 else
183 {
184 int nOldSortColumn = mxList->get_sort_column();
185 if (nOldSortColumn != -1)
186 mxList->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
187 mxList->set_sort_column(nColumn);
188 }
189
190 if (nColumn != -1)
191 {
192 //sort lists
193 mxList->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
194 }
195 }
196
IMPL_LINK_NOARG(SearchResultsDlg,ListSelectHdl,weld::TreeView &,void)197 IMPL_LINK_NOARG( SearchResultsDlg, ListSelectHdl, weld::TreeView&, void )
198 {
199 if (!mpDoc)
200 return;
201
202 int nEntry = mxList->get_selected_index();
203 OUString aTabStr = mxList->get_text(nEntry, 0);
204 OUString aPosStr = mxList->get_text(nEntry, 1);
205
206 SCTAB nTab = -1;
207 if (!mpDoc->GetTable(aTabStr, nTab))
208 // No sheet with specified name.
209 return;
210
211 ScAddress aPos;
212 ScRefFlags nRes = aPos.Parse(aPosStr, mpDoc, mpDoc->GetAddressConvention());
213 if (!(nRes & ScRefFlags::VALID))
214 // Invalid address string.
215 return;
216
217 // Jump to the cell.
218 ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();
219 pScViewShell->SetTabNo(nTab);
220 pScViewShell->SetCursor(aPos.Col(), aPos.Row());
221 pScViewShell->AlignToCursor(aPos.Col(), aPos.Row(), SC_FOLLOW_JUMP);
222 }
223
IMPL_STATIC_LINK(SearchResultsDlg,OnShowToggled,weld::ToggleButton &,rButton,void)224 IMPL_STATIC_LINK( SearchResultsDlg, OnShowToggled, weld::ToggleButton&, rButton, void )
225 {
226 ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();
227 ScViewOptions aViewOpt( pScViewShell->GetViewData().GetOptions() );
228 aViewOpt.SetOption( VOPT_SUMMARY, rButton.get_active() );
229 pScViewShell->GetViewData().SetOptions( aViewOpt );
230 }
231
SearchResultsDlgWrapper(vcl::Window * _pParent,sal_uInt16 nId,SfxBindings * pBindings,SfxChildWinInfo *)232 SearchResultsDlgWrapper::SearchResultsDlgWrapper(
233 vcl::Window* _pParent, sal_uInt16 nId, SfxBindings* pBindings, SfxChildWinInfo* /*pInfo*/)
234 : SfxChildWindow(_pParent, nId)
235 , m_xDialog(new SearchResultsDlg(pBindings, _pParent->GetFrameWeld()))
236 {
237 SetController(m_xDialog);
238 }
239
~SearchResultsDlgWrapper()240 SearchResultsDlgWrapper::~SearchResultsDlgWrapper() {}
241
GetInfo() const242 SfxChildWinInfo SearchResultsDlgWrapper::GetInfo() const
243 {
244 SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
245 aInfo.bVisible = false;
246 return aInfo;
247 }
248
249 SFX_IMPL_CHILDWINDOW_WITHID(SearchResultsDlgWrapper, SID_SEARCH_RESULTS_DIALOG);
250
251 }
252
253 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
254