LibreOffice Module sc (master)  1
searchresults.cxx
Go to the documentation of this file.
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 
26  : SfxDialogController(pParent, "modules/scalc/ui/searchresults.ui", "SearchResultsDialog")
27  , aSkipped(ScResId(SCSTR_SKIPPED))
28  , mpBindings(_pBindings)
29  , mpDoc(nullptr)
30  , mbSorted(false)
31  , mxList(m_xBuilder->weld_tree_view("results"))
32  , mxSearchResults(m_xBuilder->weld_label("lbSearchResults"))
33  , mxShowDialog(m_xBuilder->weld_check_button("cbShow"))
34 {
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
38  {
39  o3tl::narrowing<int>(mxList->get_approximate_digit_width() * 10),
40  o3tl::narrowing<int>(mxList->get_approximate_digit_width() * 10)
41  };
42  mxList->set_column_fixed_widths(aWidths);
43  mxList->connect_changed(LINK(this, SearchResultsDlg, ListSelectHdl));
44  mxList->connect_column_clicked(LINK(this, SearchResultsDlg, HeaderBarClick));
45 }
46 
48 {
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();
52  if (!pViewFrame)
53  return;
54  SfxChildWindow* pChildWindow = pViewFrame->GetChildWindow(
55  SvxSearchDialogWrapper::GetChildWindowId());
56  if (!pChildWindow)
57  return;
58  SvxSearchDialog* pSearchDlg = static_cast<SvxSearchDialog*>(pChildWindow->GetController().get());
59  if (!pSearchDlg)
60  return;
61  pSearchDlg->Present();
62 }
63 
64 namespace
65 {
66  class ListWrapper {
67  weld::TreeView& mrList;
68  public:
69  size_t mnCount = 0;
70  static const size_t mnMaximum = 1000;
71  ListWrapper(weld::TreeView& rList)
72  : mrList(rList)
73  {
74  mrList.clear();
75  mrList.freeze();
76  }
77  ~ListWrapper()
78  {
79  mrList.thaw();
80  }
81  void Insert(const OUString &rTabName,
82  const ScAddress &rPos,
84  const OUString &rText)
85  {
86  if (mnCount++ < mnMaximum)
87  {
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);
93  }
94  }
95  };
96 }
97 
98 void SearchResultsDlg::FillResults( ScDocument& rDoc, const ScRangeList &rMatchedRanges, bool bCellNotes,
99  bool bEmptyCells )
100 {
101  ListWrapper aList(*mxList);
102  std::vector<OUString> aTabNames = rDoc.GetAllTableNames();
103  SCTAB nTabCount = aTabNames.size();
104 
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;
109 
110  if (bCellNotes || bEmptyCells)
111  {
112  for (size_t i = 0, n = nMatchMax; i < n; ++i)
113  {
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())
119  {
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())
123  {
124  for (aPos.SetRow( rRange.aStart.Row()); aPos.Row() <= rRange.aEnd.Row(); aPos.IncRow())
125  {
126  if (bCellNotes)
127  {
128  const ScPostIt* pNote = rDoc.GetNote( aPos);
129  if (pNote)
130  aList.Insert(aTabNames[aPos.Tab()], aPos,
131  rDoc.GetAddressConvention(),
132  pNote->GetText());
133  }
134  else // bEmptyCells
135  {
136  aList.Insert(aTabNames[aPos.Tab()], aPos,
137  rDoc.GetAddressConvention(),
138  rDoc.GetString(aPos));
139  }
140  }
141  }
142  }
143  }
144  }
145  else
146  {
147  for (size_t i = 0, n = nMatchMax; i < n; ++i)
148  {
149  ScCellIterator aIter(rDoc, rMatchedRanges[i]);
150  for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
151  {
152  const ScAddress& aPos = aIter.GetPos();
153  if (aPos.Tab() >= nTabCount)
154  // Out-of-bound sheet index.
155  continue;
156 
157  aList.Insert(aTabNames[aPos.Tab()], aPos,
158  rDoc.GetAddressConvention(),
159  rDoc.GetString(aPos));
160  }
161  }
162  }
163 
164  OUString aTotal(ScResId(SCSTR_TOTAL, aList.mnCount));
165  OUString aSearchResults = aTotal.replaceFirst("%1", OUString::number(aList.mnCount));
166  if (aList.mnCount > ListWrapper::mnMaximum)
167  aSearchResults += " " + ScGlobal::ReplaceOrAppend( aSkipped, u"%1", OUString::number( ListWrapper::mnMaximum ) );
168  mxSearchResults->set_label(aSearchResults);
169 
170  mpDoc = &rDoc;
171 }
172 
174 {
175  if (mpBindings)
176  {
177  // Remove this dialog from the view frame after the dialog gets
178  // dismissed, else it would keep popping up endlessly!
179  SfxDispatcher* pDispacher = mpBindings ->GetDispatcher();
180  SfxBoolItem aItem(SID_SEARCH_RESULTS_DIALOG, false);
181  if (pDispacher)
182  {
183  pDispacher->ExecuteList(SID_SEARCH_RESULTS_DIALOG,
184  SfxCallMode::SYNCHRON | SfxCallMode::RECORD, { &aItem });
185  }
186  }
187 
189 }
190 
191 IMPL_LINK(SearchResultsDlg, HeaderBarClick, int, nColumn, void)
192 {
193  if (!mbSorted)
194  {
195  mxList->make_sorted();
196  mbSorted = true;
197  }
198 
199  bool bSortAtoZ = mxList->get_sort_order();
200 
201  //set new arrow positions in headerbar
202  if (nColumn == mxList->get_sort_column())
203  {
204  bSortAtoZ = !bSortAtoZ;
205  mxList->set_sort_order(bSortAtoZ);
206  }
207  else
208  {
209  int nOldSortColumn = mxList->get_sort_column();
210  if (nOldSortColumn != -1)
211  mxList->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
212  mxList->set_sort_column(nColumn);
213  }
214 
215  if (nColumn != -1)
216  {
217  //sort lists
218  mxList->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
219  }
220 }
221 
223 {
224  if (!mpDoc)
225  return;
226 
227  int nEntry = mxList->get_selected_index();
228  OUString aTabStr = mxList->get_text(nEntry, 0);
229  OUString aPosStr = mxList->get_text(nEntry, 1);
230 
231  SCTAB nTab = -1;
232  if (!mpDoc->GetTable(aTabStr, nTab))
233  // No sheet with specified name.
234  return;
235 
236  ScAddress aPos;
237  ScRefFlags nRes = aPos.Parse(aPosStr, *mpDoc, mpDoc->GetAddressConvention());
238  if (!(nRes & ScRefFlags::VALID))
239  // Invalid address string.
240  return;
241 
242  // Jump to the cell.
244  pScViewShell->SetTabNo(nTab);
245  pScViewShell->SetCursor(aPos.Col(), aPos.Row());
246  pScViewShell->AlignToCursor(aPos.Col(), aPos.Row(), SC_FOLLOW_JUMP);
247 }
248 
249 IMPL_STATIC_LINK( SearchResultsDlg, OnShowToggled, weld::Toggleable&, rButton, void )
250 {
252  ScViewOptions aViewOpt( pScViewShell->GetViewData().GetOptions() );
253  aViewOpt.SetOption( VOPT_SUMMARY, rButton.get_active() );
254  pScViewShell->GetViewData().SetOptions( aViewOpt );
255 }
256 
258  vcl::Window* _pParent, sal_uInt16 nId, SfxBindings* pBindings, SfxChildWinInfo* /*pInfo*/)
259  : SfxChildWindow(_pParent, nId)
260  , m_xDialog(std::make_shared<SearchResultsDlg>(pBindings, _pParent->GetFrameWeld()))
261 {
263 }
264 
266 
268 {
270  aInfo.bVisible = false;
271  return aInfo;
272 }
273 
274 SFX_IMPL_CHILDWINDOW_WITHID(SearchResultsDlgWrapper, SID_SEARCH_RESULTS_DIALOG);
275 
276 }
277 
278 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void set_text(int row, const OUString &rText, int col=-1)=0
std::shared_ptr< SfxDialogController > & GetController()
void SetOption(ScViewOption eOpt, bool bNew)
Definition: viewopti.hxx:87
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2074
const SfxPoolItem * ExecuteList(sal_uInt16 nSlot, SfxCallMode nCall, std::initializer_list< SfxPoolItem const * > args, std::initializer_list< SfxPoolItem const * > internalargs=std::initializer_list< SfxPoolItem const * >())
static SC_DLLPUBLIC OUString ReplaceOrAppend(const OUString &rString, std::u16string_view rPlaceholder, const OUString &rReplacement)
Replaces the first occurrence of rPlaceholder in rString with rReplacement, or if rPlaceholder is not...
Definition: global.cxx:1107
void FillResults(ScDocument &rDoc, const ScRangeList &rMatchedRanges, bool bCellNotes, bool bEmptyCells)
std::unique_ptr< weld::Label > mxSearchResults
ScAddress aStart
Definition: address.hxx:497
SfxChildWindow * GetChildWindow(sal_uInt16)
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
void IncTab(SCTAB nDelta=1)
Definition: address.hxx:320
SCROW Row() const
Definition: address.hxx:274
virtual void Close()
SC_DLLPUBLIC std::vector< OUString > GetAllTableNames() const
Definition: document.cxx:288
sal_Int64 n
virtual ~SearchResultsDlgWrapper() override
virtual void clear()=0
ScAddress aEnd
Definition: address.hxx:498
std::shared_ptr< T > make_shared(Args &&...args)
SC_DLLPUBLIC void SetCursor(SCCOL nPosX, SCROW nPosY, bool bNew=false)
Definition: tabview3.cxx:363
TRISTATE_TRUE
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:494
virtual void thaw()=0
SC_DLLPUBLIC ScPostIt * GetNote(const ScAddress &rPos)
Definition: document.cxx:6716
void append_text(const OUString &rStr)
IMPL_LINK(SearchResultsDlg, HeaderBarClick, int, nColumn, void)
Additional class containing cell annotation data.
Definition: postit.hxx:160
virtual int n_children() const =0
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3536
void SetOptions(const ScViewOptions &rOpt)
Definition: viewdata.cxx:3984
SC_DLLPUBLIC bool GetTable(const OUString &rName, SCTAB &rTab) const
Definition: document.cxx:262
Walk through all cells in an area.
Definition: dociter.hxx:207
SCTAB Tab() const
Definition: address.hxx:283
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void SetCol(SCCOL nColP)
Definition: address.hxx:291
TRISTATE_INDET
ScViewData & GetViewData()
Definition: tabview.hxx:333
std::unique_ptr< weld::TreeView > mxList
int i
void IncCol(SCCOL nDelta=1)
Definition: address.hxx:316
std::unique_ptr< weld::CheckButton > mxShowDialog
virtual void freeze()=0
CAUTION! The following defines must be in the same namespace as the respective type.
TRISTATE_FALSE
SC_DLLPUBLIC void SetTabNo(SCTAB nTab, bool bNew=false, bool bExtendSelection=false, bool bSameTabButMoved=false)
Definition: tabview3.cxx:1800
size_t size() const
Definition: rangelst.hxx:89
void IncRow(SCROW nDelta=1)
Definition: address.hxx:312
float u
OUString GetText() const
Returns the caption text of this note.
Definition: postit.cxx:916
SFX_IMPL_CHILDWINDOW_WITHID(SearchResultsDlgWrapper, SID_SEARCH_RESULTS_DIALOG)
SfxBindings * mpBindings
IMPL_LINK_NOARG(SharedStringPoolPurge, timerHandler, Timer *, void)
std::size_t mnCount
SCCOL Col() const
Definition: address.hxx:279
const ScAddress & GetPos() const
Definition: dociter.hxx:233
static ScTabViewShell * GetActiveViewShell()
Definition: tabvwsh4.cxx:1075
SfxViewFrame * GetFrame() const
void SetController(std::shared_ptr< SfxDialogController > controller)
Reference< XExecutableDialog > m_xDialog
const ScViewOptions & GetOptions() const
Definition: viewdata.hxx:554
std::shared_ptr< SearchResultsDlg > m_xDialog
void AlignToCursor(SCCOL nCurX, SCROW nCurY, ScFollowMode eMode, const ScSplitPos *pWhich=nullptr)
Definition: tabview3.cxx:920
virtual void Close() override
SfxDispatcher * GetDispatcher() const
SearchResultsDlg(SfxBindings *_pBindings, weld::Window *pParent)
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument &, const Details &rDetails=detailsOOOa1, ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, sal_Int32 *pSheetEndPos=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1537
ScRefFlags
Definition: address.hxx:157
virtual ~SearchResultsDlg() override
IMPL_STATIC_LINK(SearchResultsDlg, OnShowToggled, weld::Toggleable &, rButton, void)
virtual void Insert(SotClipboardFormatId nFormat, const OUString &rFormatName) override
weld::Window * GetFrameWeld(const SfxFrame *pFrame)
virtual SfxChildWinInfo GetInfo() const
sal_uInt16 nPos
sal_Int16 SCTAB
Definition: types.hxx:22
bool m_bDetectedRangeSegmentation false
SearchResultsDlgWrapper(vcl::Window *_pParent, sal_uInt16 nId, SfxBindings *pBindings, SfxChildWinInfo *pInfo)