1 diff --git sc/inc/table.hxx sc/inc/table.hxx
2 index 62207fb..192ca18 100644
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
22 +void ScTable::SkipFilteredRows(SCROW& rRow, SCROW& rLastNonFilteredRow, bool bForward)
28 + if (rRow <= rLastNonFilteredRow)
31 + SCROW nLastRow = rRow;
32 + if (RowFiltered(rRow, NULL, &nLastRow))
33 + // move to the first non-filtered row.
34 + rRow = nLastRow + 1;
36 + // record the last non-filtered row to avoid checking
37 + // the filtered state for each and every row.
38 + rLastNonFilteredRow = nLastRow;
44 + if (rRow >= rLastNonFilteredRow)
47 + SCROW nFirstRow = rRow;
48 + if (RowFiltered(rRow, &nFirstRow, NULL))
49 + // move to the first non-filtered row.
50 + rRow = nFirstRow - 1;
52 + // record the last non-filtered row to avoid checking
53 + // the filtered state for each and every row.
54 + rLastNonFilteredRow = nFirstRow;
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,
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);
87 @@ -311,8 +352,10 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
91 + // Not found in this column. Move to the next column.
94 + nLastNonFilteredRow = MAXROW + 1;
98 @@ -328,11 +371,14 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
102 + SCROW nLastNonFilteredRow = -1;
103 if (!bAll && rSearchItem.GetRowDirection())
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);
122 @@ -365,7 +413,9 @@ BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
126 + // Not found in this column. Move to the next column.
128 + nLastNonFilteredRow = -1;
130 while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
132 @@ -770,6 +820,30 @@ bool ScTable::SearchAndReplaceEmptyCells(
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.
147 + if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
148 + rSearchItem.GetReplaceString().Len())
150 + rColObj.Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
151 + rUndoStr = String();
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())
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())
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);
185 - // empty cell found.
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))
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);
214 - // empty cell found.
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())
227 + if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
233 @@ -844,29 +904,22 @@ bool ScTable::SearchRangeForEmptyCell(
234 if (rSearchItem.GetRowDirection())
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())
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);
254 - // empty cell found.
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))
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);
283 - // empty cell found.
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())
296 + if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
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));
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)
321 + if (!RowFiltered(nRow, NULL, &nLastRow))
323 - aCol[nCol].Insert(nRow, new ScStringCell(rNewStr));
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));
332 + const String& rNewStr = rSearchItem.GetReplaceString();
333 + for (SCROW i = nRow; i <= nLastRow; ++i)
335 + aCol[nCol].Insert(i, new ScStringCell(rNewStr));
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.
353 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
355 + SkipFilteredRows(nRow, nLastNonFilteredRow, true);
356 + if (nRow > rRange.aEnd.Row())
359 ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
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));
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());