Update ooo320-m1
[ooovba.git] / applied_patches / 0156-calc-find-replace-empty-cells-sc.diff
blobf78ad8b0b35e27d464bc42290091dbd5f12f80ed
1 diff --git sc/inc/table.hxx sc/inc/table.hxx
2 index 3c62a56..0c45c64 100644
3 --- sc/inc/table.hxx
4 +++ sc/inc/table.hxx
5 @@ -702,6 +702,16 @@ private:
6 BOOL SearchAllStyle(const SvxSearchItem& rSearchItem, ScMarkData& rMark);
7 BOOL ReplaceAllStyle(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
8 ScDocument* pUndoDoc);
9 + bool SearchAndReplaceEmptyCells(
10 + const SvxSearchItem& rSearchItem,
11 + SCCOL& rCol, SCROW& rRow, ScMarkData& rMark,
12 + String& rUndoStr, ScDocument* pUndoDoc);
13 + bool SearchRangeForEmptyCell(const ScRange& rRange,
14 + const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
15 + String& rUndoStr, ScDocument* pUndoDoc);
16 + bool SearchRangeForAllEmptyCells(const ScRange& rRange,
17 + const SvxSearchItem& rSearchItem, ScMarkData& rMark,
18 + String& rUndoStr, ScDocument* pUndoDoc);
20 // benutzen globalen SortParam:
21 BOOL IsSorted(SCCOLROW nStart, SCCOLROW nEnd);
22 diff --git sc/source/core/data/column.cxx sc/source/core/data/column.cxx
23 index cb9dd4a..5b94923 100644
24 --- sc/source/core/data/column.cxx
25 +++ sc/source/core/data/column.cxx
26 @@ -1373,7 +1373,24 @@ void ScColumn::CopyToColumn(SCROW nRow1, SCROW nRow2, USHORT nFlags, BOOL bMarke
27 CloneCell( i, nFlags, *rColumn.pDocument, aDestPos );
29 if (pNew)
30 - rColumn.Insert(pItems[i].nRow, pNew);
31 + {
32 + // Special case to allow removing of cell instances. A
33 + // string cell with empty content is used to indicate an
34 + // empty cell.
35 + if (pNew->GetCellType() == CELLTYPE_STRING)
36 + {
37 + String aStr;
38 + static_cast<ScStringCell*>(pNew)->GetString(aStr);
39 + if (aStr.Len() == 0)
40 + // A string cell with empty string. Delete the cell itself.
41 + rColumn.Delete(pItems[i].nRow);
42 + else
43 + // non-empty string cell
44 + rColumn.Insert(pItems[i].nRow, pNew);
45 + }
46 + else
47 + rColumn.Insert(pItems[i].nRow, pNew);
48 + }
52 diff --git sc/source/core/data/table6.cxx sc/source/core/data/table6.cxx
53 index 994596d..8d5ec0f 100644
54 --- sc/source/core/data/table6.cxx
55 +++ sc/source/core/data/table6.cxx
56 @@ -52,6 +52,8 @@
57 //--------------------------------------------------------------------------
60 +using ::com::sun::star::util::SearchOptions;
62 BOOL lcl_GetTextWithBreaks( const ScEditCell& rCell, ScDocument* pDoc, String& rVal )
64 // TRUE = more than 1 paragraph
65 @@ -660,6 +662,12 @@ BOOL ScTable::SearchAndReplace(const SvxSearchItem& rSearchItem,
66 com::sun::star::util::SearchOptions aSearchOptions = rSearchItem.GetSearchOptions();
67 aSearchOptions.Locale = *ScGlobal::pLocale;
69 + if (!aSearchOptions.searchString.getLength())
70 + {
71 + // Search for empty cells.
72 + return SearchAndReplaceEmptyCells(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
73 + }
75 // #107259# reflect UseAsianOptions flag in SearchOptions
76 // (use only ignore case and width if asian options are disabled).
77 // This is also done in SvxSearchDialog CommandHdl, but not in API object.
78 @@ -686,6 +694,274 @@ BOOL ScTable::SearchAndReplace(const SvxSearchItem& rSearchItem,
79 return bFound;
82 +bool ScTable::SearchAndReplaceEmptyCells(
83 + const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, ScMarkData& rMark,
84 + String& rUndoStr, ScDocument* pUndoDoc)
86 + SCCOL nColStart, nColEnd;
87 + SCROW nRowStart, nRowEnd;
88 + GetFirstDataPos(nColStart, nRowStart);
89 + GetLastDataPos(nColEnd, nRowEnd);
91 + ScRangeList aRanges;
92 + aRanges.Append(ScRange(nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab));
94 + if (rSearchItem.GetSelection())
95 + {
96 + // current selection only.
97 + if (!rMark.IsMarked() && !rMark.IsMultiMarked())
98 + // There is no selection. Bail out.
99 + return false;
101 + ScRangeList aMarkedRanges, aNewRanges;
102 + rMark.FillRangeListWithMarks(&aMarkedRanges, true);
103 + for (ScRangePtr p = aMarkedRanges.First(); p; p = aMarkedRanges.Next())
105 + if (p->aStart.Col() > nColEnd || p->aStart.Row() > nRowEnd)
106 + // This range is outside the data area. Skip it.
107 + continue;
109 + // Shrink the range into data area only.
110 + if (p->aStart.Col() < nColStart)
111 + p->aStart.SetCol(rCol);
112 + if (p->aStart.Row() < nRowStart)
113 + p->aStart.SetRow(rRow);
115 + if (p->aEnd.Col() > nColEnd)
116 + p->aEnd.SetCol(nColEnd);
117 + if (p->aEnd.Row() > nRowEnd)
118 + p->aEnd.SetRow(nRowEnd);
120 + aNewRanges.Append(*p);
122 + aRanges = aNewRanges;
125 + sal_uInt16 nCommand = rSearchItem.GetCommand();
126 + if (nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE)
128 + if (rSearchItem.GetBackward())
130 + for (ScRangePtr p = aRanges.Last(); p; p = aRanges.Prev())
132 + if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr, pUndoDoc))
133 + return true;
136 + else
138 + for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next())
140 + if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr, pUndoDoc))
141 + return true;
145 + else if (nCommand == SVX_SEARCHCMD_FIND_ALL || nCommand == SVX_SEARCHCMD_REPLACE_ALL)
147 + bool bFound = false;
148 + ScMarkData aNewMark(rMark);
149 + aNewMark.ResetMark();
150 + for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next())
151 + bFound |= SearchRangeForAllEmptyCells(*p, rSearchItem, aNewMark, rUndoStr, pUndoDoc);
152 + rMark = aNewMark;
153 + return bFound;
155 + return false;
158 +bool ScTable::SearchRangeForEmptyCell(
159 + const ScRange& rRange, const SvxSearchItem& rSearchItem,
160 + SCCOL& rCol, SCROW& rRow, String& rUndoStr, ScDocument* /*pUndoDoc*/)
162 + sal_uInt16 nCmd = rSearchItem.GetCommand();
163 + if (rSearchItem.GetBackward())
165 + // backward search
166 + if (rSearchItem.GetRowDirection())
168 + // row direction.
169 + SCROW nBeginRow = rRange.aEnd.Row() > rRow ? rRow : rRange.aEnd.Row();
170 + for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
172 + SCCOL nBeginCol = rRange.aEnd.Col();
173 + if (nRow == rRow && nBeginCol >= rCol)
174 + // always start from one cell before the cursor.
175 + nBeginCol = rCol - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
177 + for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
179 + ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
180 + if (!pCell)
182 + // empty cell found.
183 + rCol = nCol;
184 + rRow = nRow;
185 + if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
186 + rSearchItem.GetReplaceString().Len())
188 + aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
189 + rUndoStr = String();
191 + return true;
196 + else
198 + // column direction.
199 + SCCOL nBeginCol = rRange.aEnd.Col() > rCol ? rCol : rRange.aEnd.Col();
200 + for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
202 + SCROW nBeginRow = rRange.aEnd.Row();
203 + if (nCol == rCol && nBeginRow >= rRow)
204 + // always start from one cell before the cursor.
205 + nBeginRow = rRow - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
206 + for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
207 + {
208 + ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
209 + if (!pCell)
211 + // empty cell found.
212 + rCol = nCol;
213 + rRow = nRow;
214 + if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
215 + rSearchItem.GetReplaceString().Len())
217 + aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
218 + rUndoStr = String();
220 + return true;
226 + else
228 + // forward search
229 + if (rSearchItem.GetRowDirection())
231 + // row direction.
232 + SCROW nBeginRow = rRange.aStart.Row() < rRow ? rRow : rRange.aStart.Row();
233 + for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
235 + SCCOL nBeginCol = rRange.aStart.Col();
236 + if (nRow == rRow && nBeginCol <= rCol)
237 + // always start from one cell past the cursor.
238 + nBeginCol = rCol + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
239 + for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
241 + ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
242 + if (!pCell)
244 + // empty cell found.
245 + rCol = nCol;
246 + rRow = nRow;
247 + if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
248 + rSearchItem.GetReplaceString().Len())
250 + aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
251 + rUndoStr = String();
253 + return true;
258 + else
260 + // column direction.
261 + SCCOL nBeginCol = rRange.aStart.Col() < rCol ? rCol : rRange.aStart.Col();
262 + for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
264 + SCROW nBeginRow = rRange.aStart.Row();
265 + if (nCol == rCol && nBeginRow <= rRow)
266 + // always start from one cell past the cursor.
267 + nBeginRow = rRow + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
268 + for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
269 + {
270 + ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
271 + if (!pCell)
273 + // empty cell found.
274 + rCol = nCol;
275 + rRow = nRow;
276 + if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
277 + rSearchItem.GetReplaceString().Len())
279 + aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
280 + rUndoStr = String();
282 + return true;
288 + return false;
291 +bool ScTable::SearchRangeForAllEmptyCells(
292 + const ScRange& rRange, const SvxSearchItem& rSearchItem, ScMarkData& rMark,
293 + String& rUndoStr, ScDocument* pUndoDoc)
295 + bool bFound = false;
296 + bool bReplace = (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) &&
297 + (rSearchItem.GetReplaceString().Len() > 0);
299 + for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
301 + if (aCol[nCol].IsEmptyData())
303 + // The entire column is empty. Add the whole column and move on.
304 + rMark.SetMultiMarkArea(
305 + ScRange(nCol, rRange.aStart.Row(), nTab, nCol, rRange.aEnd.Row(), nTab));
306 + bFound = true;
308 + if (bReplace)
310 + const String& rNewStr = rSearchItem.GetReplaceString();
311 + for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
312 + {
313 + aCol[nCol].Insert(nRow, new ScStringCell(rNewStr));
314 + if (pUndoDoc)
315 + // TODO: I'm using a string cell with empty content to
316 + // trigger deletion of cell instance on undo. Maybe I
317 + // should create a new cell type for this?
318 + pUndoDoc->PutCell(nCol, nRow, nTab, new ScStringCell(String()));
320 + rUndoStr = String();
322 + continue;
325 + for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
327 + ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
328 + if (!pCell)
329 + {
330 + // empty cell found
331 + rMark.SetMultiMarkArea(ScRange(nCol, nRow, nTab));
332 + bFound = true;
334 + if (bReplace)
335 + {
336 + aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
337 + if (pUndoDoc)
338 + // TODO: I'm using a string cell with empty content to
339 + // trigger deletion of cell instance on undo. Maybe I
340 + // should create a new cell type for this?
341 + pUndoDoc->PutCell(nCol, nRow, nTab, new ScStringCell(String()));
346 + return bFound;
353 diff --git sc/source/ui/view/tabvwsha.cxx sc/source/ui/view/tabvwsha.cxx
354 index c64698b..a7fd06d 100644
355 --- sc/source/ui/view/tabvwsha.cxx
356 +++ sc/source/ui/view/tabvwsha.cxx
357 @@ -224,8 +224,13 @@ void __EXPORT ScTabViewShell::GetState( SfxItemSet& rSet )
358 break;
360 case SID_SEARCH_ITEM:
361 - rSet.Put( ScGlobal::GetSearchItem() );
363 + SvxSearchItem aItem(ScGlobal::GetSearchItem()); // make a copy.
364 + // Search on current selection if a range is marked.
365 + aItem.SetSelection(rMark.IsMarked());
366 + rSet.Put(aItem);
367 break;
370 case SID_SEARCH_OPTIONS: