update dev300-m58
[ooovba.git] / applied_patches / 0179-calc-find-replace-skip-filtered.diff
blob5bde7bc576290c2a352717b1c517d968eaea78fa
1 diff --git sc/inc/table.hxx sc/inc/table.hxx
2 index 62207fb..192ca18 100644
3 --- sc/inc/table.hxx
4 +++ sc/inc/table.hxx
5 @@ -826,6 +826,8 @@ private:
6 // also invalidates script type, broadcasts for "calc as shown"
7 void InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
8 BOOL bNumFormatChanged, BOOL bBroadcast );
10 + void SkipFilteredRows(SCROW& rRow, SCROW& rLastNonFilteredRow, bool bForward);
14 diff --git sc/source/core/data/table6.cxx sc/source/core/data/table6.cxx
15 index 272e049..be44ff1 100644
16 --- sc/source/core/data/table6.cxx
17 +++ sc/source/core/data/table6.cxx
18 @@ -251,6 +251,42 @@ BOOL ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, SCROW nRo
19 return bFound;
22 +void ScTable::SkipFilteredRows(SCROW& rRow, SCROW& rLastNonFilteredRow, bool bForward)
24 + if (bForward)
25 + {
26 + // forward search
28 + if (rRow <= rLastNonFilteredRow)
29 + return;
31 + SCROW nLastRow = rRow;
32 + if (RowFiltered(rRow, NULL, &nLastRow))
33 + // move to the first non-filtered row.
34 + rRow = nLastRow + 1;
35 + else
36 + // record the last non-filtered row to avoid checking
37 + // the filtered state for each and every row.
38 + rLastNonFilteredRow = nLastRow;
39 + }
40 + else
41 + {
42 + // backward search
44 + if (rRow >= rLastNonFilteredRow)
45 + return;
47 + SCROW nFirstRow = rRow;
48 + if (RowFiltered(rRow, &nFirstRow, NULL))
49 + // move to the first non-filtered row.
50 + rRow = nFirstRow - 1;
51 + else
52 + // record the last non-filtered row to avoid checking
53 + // the filtered state for each and every row.
54 + rLastNonFilteredRow = nFirstRow;
55 + }
58 BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
59 const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
61 @@ -264,6 +300,7 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
62 GetLastDataPos(nLastCol, nLastRow);
63 if (!bAll && rSearchItem.GetBackward())
65 + SCROW nLastNonFilteredRow = MAXROW + 1;
66 nCol = Min(nCol, (SCCOL)(nLastCol + 1));
67 nRow = Min(nRow, (SCROW)(nLastRow + 1));
68 if (rSearchItem.GetRowDirection())
69 @@ -271,6 +308,8 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
70 nCol--;
71 while (!bFound && ((SCsROW)nRow >= 0))
73 + SkipFilteredRows(nRow, nLastNonFilteredRow, false);
75 while (!bFound && ((SCsCOL)nCol >= 0))
77 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
78 @@ -302,6 +341,8 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
80 while (!bFound && ((SCsROW)nRow >= 0))
82 + SkipFilteredRows(nRow, nLastNonFilteredRow, false);
84 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
85 if (!bFound)
87 @@ -311,8 +352,10 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
89 if (!bFound)
91 + // Not found in this column. Move to the next column.
92 BOOL bIsEmpty;
93 nRow = nLastRow;
94 + nLastNonFilteredRow = MAXROW + 1;
97 nCol--;
98 @@ -328,11 +371,14 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
100 else
102 + SCROW nLastNonFilteredRow = -1;
103 if (!bAll && rSearchItem.GetRowDirection())
105 nCol++;
106 while (!bFound && (nRow <= nLastRow))
108 + SkipFilteredRows(nRow, nLastNonFilteredRow, true);
110 while (!bFound && (nCol <= nLastCol))
112 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
113 @@ -356,6 +402,8 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
115 while (!bFound && (nRow <= nLastRow))
117 + SkipFilteredRows(nRow, nLastNonFilteredRow, true);
119 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
120 if (!bFound)
122 @@ -365,7 +413,9 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
124 if (!bFound)
126 + // Not found in this column. Move to the next column.
127 nRow = 0;
128 + nLastNonFilteredRow = -1;
129 nCol++;
130 while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
132 @@ -770,6 +820,30 @@ bool ScTable::SearchAndReplaceEmptyCells(
133 return false;
136 +namespace {
138 +bool lcl_maybeReplaceCellString(
139 + ScColumn& rColObj, SCCOL& rCol, SCROW& rRow, String& rUndoStr, SCCOL nCol, SCROW nRow, const SvxSearchItem& rSearchItem)
141 + ScBaseCell* pCell = rColObj.GetCell(nRow);
142 + if (!pCell || pCell->GetCellType() == CELLTYPE_NOTE)
144 + // empty cell found.
145 + rCol = nCol;
146 + rRow = nRow;
147 + if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
148 + rSearchItem.GetReplaceString().Len())
150 + rColObj.Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
151 + rUndoStr = String();
153 + return true;
155 + return false;
160 bool ScTable::SearchRangeForEmptyCell(
161 const ScRange& rRange, const SvxSearchItem& rSearchItem,
162 SCCOL& rCol, SCROW& rRow, String& rUndoStr, ScDocument* /*pUndoDoc*/)
163 @@ -781,9 +855,14 @@ bool ScTable::SearchRangeForEmptyCell(
164 if (rSearchItem.GetRowDirection())
166 // row direction.
167 + SCROW nLastNonFilteredRow = MAXROW + 1;
168 SCROW nBeginRow = rRange.aEnd.Row() > rRow ? rRow : rRange.aEnd.Row();
169 for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
171 + SkipFilteredRows(nRow, nLastNonFilteredRow, false);
172 + if (nRow < rRange.aStart.Row())
173 + break;
175 SCCOL nBeginCol = rRange.aEnd.Col();
176 if (nRow == rRow && nBeginCol >= rCol)
177 // always start from one cell before the cursor.
178 @@ -791,20 +870,8 @@ bool ScTable::SearchRangeForEmptyCell(
180 for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
182 - ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
183 - if (!pCell)
185 - // empty cell found.
186 - rCol = nCol;
187 - rRow = nRow;
188 - if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
189 - rSearchItem.GetReplaceString().Len())
191 - aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
192 - rUndoStr = String();
194 + if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
195 return true;
200 @@ -814,26 +881,19 @@ bool ScTable::SearchRangeForEmptyCell(
201 SCCOL nBeginCol = rRange.aEnd.Col() > rCol ? rCol : rRange.aEnd.Col();
202 for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
204 + SCROW nLastNonFilteredRow = MAXROW + 1;
205 SCROW nBeginRow = rRange.aEnd.Row();
206 if (nCol == rCol && nBeginRow >= rRow)
207 // always start from one cell before the cursor.
208 nBeginRow = rRow - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
209 for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
211 - ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
212 - if (!pCell)
214 - // empty cell found.
215 - rCol = nCol;
216 - rRow = nRow;
217 - if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
218 - rSearchItem.GetReplaceString().Len())
220 - aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
221 - rUndoStr = String();
223 + SkipFilteredRows(nRow, nLastNonFilteredRow, false);
224 + if (nRow < rRange.aStart.Row())
225 + break;
227 + if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
228 return true;
233 @@ -844,29 +904,22 @@ bool ScTable::SearchRangeForEmptyCell(
234 if (rSearchItem.GetRowDirection())
236 // row direction.
237 + SCROW nLastNonFilteredRow = -1;
238 SCROW nBeginRow = rRange.aStart.Row() < rRow ? rRow : rRange.aStart.Row();
239 for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
241 + SkipFilteredRows(nRow, nLastNonFilteredRow, true);
242 + if (nRow > rRange.aEnd.Row())
243 + break;
245 SCCOL nBeginCol = rRange.aStart.Col();
246 if (nRow == rRow && nBeginCol <= rCol)
247 // always start from one cell past the cursor.
248 nBeginCol = rCol + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
249 for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
251 - ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
252 - if (!pCell)
254 - // empty cell found.
255 - rCol = nCol;
256 - rRow = nRow;
257 - if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
258 - rSearchItem.GetReplaceString().Len())
260 - aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
261 - rUndoStr = String();
263 + if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
264 return true;
269 @@ -876,26 +929,19 @@ bool ScTable::SearchRangeForEmptyCell(
270 SCCOL nBeginCol = rRange.aStart.Col() < rCol ? rCol : rRange.aStart.Col();
271 for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
273 + SCROW nLastNonFilteredRow = -1;
274 SCROW nBeginRow = rRange.aStart.Row();
275 if (nCol == rCol && nBeginRow <= rRow)
276 // always start from one cell past the cursor.
277 nBeginRow = rRow + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
278 for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
280 - ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
281 - if (!pCell)
283 - // empty cell found.
284 - rCol = nCol;
285 - rRow = nRow;
286 - if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
287 - rSearchItem.GetReplaceString().Len())
289 - aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
290 - rUndoStr = String();
292 + SkipFilteredRows(nRow, nLastNonFilteredRow, true);
293 + if (nRow > rRange.aEnd.Row())
294 + break;
296 + if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
297 return true;
302 @@ -913,32 +959,44 @@ bool ScTable::SearchRangeForAllEmptyCells(
304 for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
306 + SCROW nLastNonFilteredRow = -1;
307 if (aCol[nCol].IsEmptyData())
309 - // The entire column is empty. Add the whole column and move on.
310 - rMark.SetMultiMarkArea(
311 - ScRange(nCol, rRange.aStart.Row(), nTab, nCol, rRange.aEnd.Row(), nTab));
312 - bFound = true;
314 - if (bReplace)
315 + // The entire column is empty.
316 + for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
318 - const String& rNewStr = rSearchItem.GetReplaceString();
319 - for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
320 + SCROW nLastRow;
321 + if (!RowFiltered(nRow, NULL, &nLastRow))
323 - aCol[nCol].Insert(nRow, new ScStringCell(rNewStr));
324 - if (pUndoDoc)
325 - // TODO: I'm using a string cell with empty content to
326 - // trigger deletion of cell instance on undo. Maybe I
327 - // should create a new cell type for this?
328 - pUndoDoc->PutCell(nCol, nRow, nTab, new ScStringCell(String()));
329 + rMark.SetMultiMarkArea(ScRange(nCol, nRow, nTab, nCol, nLastRow, nTab));
330 + if (bReplace)
332 + const String& rNewStr = rSearchItem.GetReplaceString();
333 + for (SCROW i = nRow; i <= nLastRow; ++i)
334 + {
335 + aCol[nCol].Insert(i, new ScStringCell(rNewStr));
336 + if (pUndoDoc)
337 + // TODO: I'm using a string cell with empty content to
338 + // trigger deletion of cell instance on undo. Maybe I
339 + // should create a new cell type for this?
340 + pUndoDoc->PutCell(nCol, i, nTab, new ScStringCell(String()));
342 + rUndoStr = String();
345 - rUndoStr = String();
347 + nRow = nLastRow; // move to the last filtered row.
349 + bFound = true;
350 continue;
353 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
355 + SkipFilteredRows(nRow, nLastNonFilteredRow, true);
356 + if (nRow > rRange.aEnd.Row())
357 + break;
359 ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
360 if (!pCell)
362 @@ -956,6 +1014,21 @@ bool ScTable::SearchRangeForAllEmptyCells(
363 pUndoDoc->PutCell(nCol, nRow, nTab, new ScStringCell(String()));
366 + else if (pCell->GetCellType() == CELLTYPE_NOTE)
368 + rMark.SetMultiMarkArea(ScRange(nCol, nRow, nTab));
369 + bFound = true;
371 + if (bReplace)
372 + {
373 + if (pUndoDoc)
375 + ScAddress aCellPos(nCol, nRow, nTab);
376 + pUndoDoc->PutCell(nCol, nRow, nTab, pCell->CloneWithNote(aCellPos, *pUndoDoc, aCellPos));
378 + aCol[nCol].SetString(nRow, nTab, rSearchItem.GetReplaceString());
383 return bFound;