Line data Source code
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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <com/sun/star/i18n/TransliterationModules.hpp>
21 :
22 : #include <unotools/textsearch.hxx>
23 : #include <svl/srchitem.hxx>
24 : #include <editeng/editobj.hxx>
25 :
26 : #include "table.hxx"
27 : #include "formulacell.hxx"
28 : #include "document.hxx"
29 : #include "stlpool.hxx"
30 : #include "markdata.hxx"
31 : #include "editutil.hxx"
32 : #include "detfunc.hxx"
33 : #include "postit.hxx"
34 : #include "stringutil.hxx"
35 :
36 : //--------------------------------------------------------------------------
37 :
38 :
39 : using ::com::sun::star::util::SearchOptions;
40 :
41 : namespace {
42 :
43 4 : bool lcl_GetTextWithBreaks( const EditTextObject& rData, ScDocument* pDoc, OUString& rVal )
44 : {
45 : // true = more than 1 paragraph
46 :
47 4 : EditEngine& rEngine = pDoc->GetEditEngine();
48 4 : rEngine.SetText(rData);
49 4 : rVal = rEngine.GetText( LINEEND_LF );
50 4 : return ( rEngine.GetParagraphCount() > 1 );
51 : }
52 :
53 : }
54 :
55 4594 : bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, SCROW nRow,
56 : const ScMarkData& rMark, OUString& rUndoStr, ScDocument* pUndoDoc)
57 : {
58 4594 : bool bFound = false;
59 4594 : bool bDoSearch = true;
60 4594 : bool bDoBack = rSearchItem.GetBackward();
61 :
62 4594 : OUString aString;
63 9188 : ScRefCellValue aCell;
64 4594 : if (rSearchItem.GetSelection())
65 4477 : bDoSearch = rMark.IsCellMarked(nCol, nRow);
66 :
67 4594 : if (!bDoSearch)
68 3512 : return false;
69 :
70 1082 : aCell = aCol[nCol].GetCellValue(nRow);
71 1082 : if (aCell.isEmpty())
72 63 : return false;
73 :
74 1019 : bool bMultiLine = false;
75 1019 : CellType eCellType = aCell.meType;
76 1019 : switch (rSearchItem.GetCellType())
77 : {
78 : case SVX_SEARCHIN_FORMULA:
79 : {
80 1019 : if ( eCellType == CELLTYPE_FORMULA )
81 18 : aCell.mpFormula->GetFormula(aString, pDocument->GetGrammar());
82 1001 : else if ( eCellType == CELLTYPE_EDIT )
83 4 : bMultiLine = lcl_GetTextWithBreaks(*aCell.mpEditText, pDocument, aString);
84 : else
85 : {
86 997 : aCol[nCol].GetInputString( nRow, aString );
87 : }
88 : }
89 1019 : break;
90 : case SVX_SEARCHIN_VALUE:
91 0 : if ( eCellType == CELLTYPE_EDIT )
92 0 : bMultiLine = lcl_GetTextWithBreaks(*aCell.mpEditText, pDocument, aString);
93 : else
94 : {
95 0 : aCol[nCol].GetInputString( nRow, aString );
96 : }
97 0 : break;
98 : case SVX_SEARCHIN_NOTE:
99 0 : break; // don't search this case here
100 : default:
101 0 : break;
102 : }
103 1019 : sal_Int32 nStart = 0;
104 1019 : sal_Int32 nEnd = aString.getLength();
105 1019 : ::com::sun::star::util::SearchResult aSearchResult;
106 1019 : if (pSearchText)
107 : {
108 1019 : if ( bDoBack )
109 : {
110 0 : sal_Int32 nTemp=nStart; nStart=nEnd; nEnd=nTemp;
111 0 : bFound = pSearchText->SearchBackward(aString, &nStart, &nEnd, &aSearchResult);
112 : // change results to definition before 614:
113 0 : --nEnd;
114 : }
115 : else
116 : {
117 1019 : bFound = pSearchText->SearchForward(aString, &nStart, &nEnd, &aSearchResult);
118 : // change results to definition before 614:
119 1019 : --nEnd;
120 : }
121 :
122 1019 : if (bFound && rSearchItem.GetWordOnly())
123 106 : bFound = (nStart == 0 && nEnd == aString.getLength() - 1);
124 : }
125 : else
126 : {
127 : OSL_FAIL("pSearchText == NULL");
128 0 : return bFound;
129 : }
130 :
131 1019 : sal_uInt8 cMatrixFlag = MM_NONE;
132 1599 : if ( bFound &&
133 580 : ( (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE)
134 580 : ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) ) &&
135 : // Matrix nicht zerreissen, nur Matrixformel ersetzen
136 3 : !( (eCellType == CELLTYPE_FORMULA &&
137 3 : ((cMatrixFlag = aCell.mpFormula->GetMatrixFlag()) == MM_REFERENCE))
138 : // kein UndoDoc => Matrix nicht wiederherstellbar => nicht ersetzen
139 1589 : || (cMatrixFlag != MM_NONE && !pUndoDoc) ) &&
140 285 : IsBlockEditable(nCol, nRow, nCol, nRow)
141 : )
142 : {
143 285 : if ( cMatrixFlag == MM_NONE && rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE )
144 0 : rUndoStr = aString;
145 285 : else if (pUndoDoc)
146 : {
147 285 : ScAddress aAdr( nCol, nRow, nTab );
148 285 : aCell.commit(*pUndoDoc, aAdr);
149 : }
150 285 : bool bRepeat = !rSearchItem.GetWordOnly();
151 285 : do
152 : {
153 : // wenn der gefundene Text leer ist, nicht weitersuchen,
154 : // sonst wuerde man nie mehr aufhoeren (#35410#)
155 285 : if ( nEnd < nStart )
156 0 : bRepeat = false;
157 :
158 285 : OUString sReplStr = rSearchItem.GetReplaceString();
159 285 : if (rSearchItem.GetRegExp())
160 : {
161 269 : pSearchText->ReplaceBackReferences( sReplStr, aString, aSearchResult );
162 269 : OUStringBuffer aStrBuffer(aString);
163 269 : aStrBuffer.remove(nStart, nEnd-nStart+1);
164 269 : aStrBuffer.insert(nStart, sReplStr);
165 269 : aString = aStrBuffer.makeStringAndClear();
166 : }
167 : else
168 : {
169 16 : OUStringBuffer aStrBuffer(aString);
170 16 : aStrBuffer.remove(nStart, nEnd-nStart+1);
171 16 : aStrBuffer.insert(nStart, rSearchItem.GetReplaceString());
172 16 : aString = aStrBuffer.makeStringAndClear();
173 : }
174 :
175 : // Indizes anpassen
176 285 : if (bDoBack)
177 : {
178 0 : nEnd = nStart;
179 0 : nStart = 0;
180 : }
181 : else
182 : {
183 285 : nStart = nStart + sReplStr.getLength();
184 285 : nEnd = aString.getLength();
185 : }
186 :
187 : // weitersuchen ?
188 285 : if (bRepeat)
189 : {
190 285 : if ( rSearchItem.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL || nStart >= nEnd )
191 281 : bRepeat = false;
192 4 : else if (bDoBack)
193 : {
194 0 : sal_Int32 nTemp=nStart; nStart=nEnd; nEnd=nTemp;
195 0 : bRepeat = pSearchText->SearchBackward(aString, &nStart, &nEnd, &aSearchResult);
196 : // change results to definition before 614:
197 0 : --nEnd;
198 : }
199 : else
200 : {
201 4 : bRepeat = pSearchText->SearchForward(aString, &nStart, &nEnd, &aSearchResult);
202 : // change results to definition before 614:
203 4 : --nEnd;
204 : }
205 285 : }
206 : }
207 : while (bRepeat);
208 :
209 285 : if ( cMatrixFlag != MM_NONE )
210 : { // Matrix nicht zerreissen
211 0 : if ( aString.getLength() > 2 )
212 : { // {} raus, erst hier damit auch "{=" durch "{=..." ersetzt werden kann
213 0 : if ( aString[ aString.getLength()-1 ] == '}' )
214 0 : aString = aString.copy( 0, aString.getLength()-1 );
215 0 : if ( aString[0] == '{' )
216 0 : aString = aString.copy( 1 );
217 : }
218 0 : ScAddress aAdr( nCol, nRow, nTab );
219 : ScFormulaCell* pFCell = new ScFormulaCell( pDocument, aAdr,
220 0 : aString, pDocument->GetGrammar(), cMatrixFlag );
221 : SCCOL nMatCols;
222 : SCROW nMatRows;
223 0 : aCell.mpFormula->GetMatColsRows(nMatCols, nMatRows);
224 0 : pFCell->SetMatColsRows( nMatCols, nMatRows );
225 0 : aCol[nCol].SetFormulaCell(nRow, pFCell);
226 : }
227 285 : else if ( bMultiLine && aString.indexOf('\n') != -1 )
228 : {
229 0 : ScFieldEditEngine& rEngine = pDocument->GetEditEngine();
230 0 : rEngine.SetText(aString);
231 0 : SetEditText(nCol, nRow, rEngine.CreateTextObject());
232 : }
233 : else
234 285 : aCol[nCol].SetString(nRow, nTab, aString, pDocument->GetAddressConvention());
235 : // pCell is invalid now (deleted)
236 : }
237 5613 : return bFound;
238 : }
239 :
240 4594 : void ScTable::SkipFilteredRows(SCROW& rRow, SCROW& rLastNonFilteredRow, bool bForward)
241 : {
242 4594 : if (bForward)
243 : {
244 : // forward search
245 :
246 4594 : if (rRow <= rLastNonFilteredRow)
247 3436 : return;
248 :
249 1158 : SCROW nLastRow = rRow;
250 1158 : if (RowFiltered(rRow, NULL, &nLastRow))
251 : // move to the first non-filtered row.
252 0 : rRow = nLastRow + 1;
253 : else
254 : // record the last non-filtered row to avoid checking
255 : // the filtered state for each and every row.
256 1158 : rLastNonFilteredRow = nLastRow;
257 : }
258 : else
259 : {
260 : // backward search
261 :
262 0 : if (rRow >= rLastNonFilteredRow)
263 0 : return;
264 :
265 0 : SCROW nFirstRow = rRow;
266 0 : if (RowFiltered(rRow, &nFirstRow, NULL))
267 : // move to the first non-filtered row.
268 0 : rRow = nFirstRow - 1;
269 : else
270 : // record the last non-filtered row to avoid checking
271 : // the filtered state for each and every row.
272 0 : rLastNonFilteredRow = nFirstRow;
273 : }
274 : }
275 :
276 637 : bool ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
277 : const ScMarkData& rMark, OUString& rUndoStr, ScDocument* pUndoDoc)
278 : {
279 637 : bool bFound = false;
280 637 : bool bAll = (rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL)
281 637 : ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL);
282 637 : SCCOL nCol = rCol;
283 637 : SCROW nRow = rRow;
284 : SCCOL nLastCol;
285 : SCROW nLastRow;
286 637 : GetLastDataPos(nLastCol, nLastRow);
287 637 : bool bSkipFiltered = !rSearchItem.IsSearchFiltered();
288 637 : if (!bAll && rSearchItem.GetBackward())
289 : {
290 0 : SCROW nLastNonFilteredRow = MAXROW + 1;
291 0 : nCol = std::min(nCol, (SCCOL)(nLastCol + 1));
292 0 : nRow = std::min(nRow, (SCROW)(nLastRow + 1));
293 0 : if (rSearchItem.GetRowDirection())
294 : {
295 0 : nCol--;
296 0 : while (!bFound && ((SCsROW)nRow >= 0))
297 : {
298 0 : if (bSkipFiltered)
299 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, false);
300 :
301 0 : while (!bFound && ((SCsCOL)nCol >= 0))
302 : {
303 0 : bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
304 0 : if (!bFound)
305 : {
306 : bool bIsEmpty;
307 0 : do
308 : {
309 0 : nCol--;
310 0 : if ((SCsCOL)nCol >= 0)
311 0 : bIsEmpty = aCol[nCol].IsEmptyData();
312 : else
313 0 : bIsEmpty = true;
314 : }
315 0 : while (((SCsCOL)nCol >= 0) && bIsEmpty);
316 : }
317 : }
318 0 : if (!bFound)
319 : {
320 0 : nCol = nLastCol;
321 0 : nRow--;
322 : }
323 : }
324 : }
325 : else
326 : {
327 0 : nRow--;
328 0 : while (!bFound && ((SCsCOL)nCol >= 0))
329 : {
330 0 : while (!bFound && ((SCsROW)nRow >= 0))
331 : {
332 0 : if (bSkipFiltered)
333 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, false);
334 :
335 0 : bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
336 0 : if (!bFound)
337 : {
338 0 : if (!aCol[nCol].GetPrevDataPos(nRow))
339 0 : nRow = -1;
340 : }
341 : }
342 0 : if (!bFound)
343 : {
344 : // Not found in this column. Move to the next column.
345 : bool bIsEmpty;
346 0 : nRow = nLastRow;
347 0 : nLastNonFilteredRow = MAXROW + 1;
348 0 : do
349 : {
350 0 : nCol--;
351 0 : if ((SCsCOL)nCol >= 0)
352 0 : bIsEmpty = aCol[nCol].IsEmptyData();
353 : else
354 0 : bIsEmpty = true;
355 : }
356 0 : while (((SCsCOL)nCol >= 0) && bIsEmpty);
357 : }
358 : }
359 : }
360 : }
361 : else
362 : {
363 637 : SCROW nLastNonFilteredRow = -1;
364 637 : if (!bAll && rSearchItem.GetRowDirection())
365 : {
366 0 : nCol++;
367 0 : while (!bFound && (nRow <= nLastRow))
368 : {
369 0 : if (bSkipFiltered)
370 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
371 :
372 0 : while (!bFound && (nCol <= nLastCol))
373 : {
374 0 : bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
375 0 : if (!bFound)
376 : {
377 0 : nCol++;
378 0 : while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
379 : }
380 : }
381 0 : if (!bFound)
382 : {
383 0 : nCol = 0;
384 0 : nRow++;
385 : }
386 : }
387 : }
388 : else
389 : {
390 637 : nRow++;
391 2441 : while (!bFound && (nCol <= nLastCol))
392 : {
393 6928 : while (!bFound && (nRow <= nLastRow))
394 : {
395 4594 : if (bSkipFiltered)
396 4594 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
397 :
398 4594 : bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
399 4594 : if (!bFound)
400 : {
401 4014 : if (!aCol[nCol].GetNextDataPos(nRow))
402 578 : nRow = MAXROW + 1;
403 : }
404 : }
405 1167 : if (!bFound)
406 : {
407 : // Not found in this column. Move to the next column.
408 587 : nRow = 0;
409 587 : nLastNonFilteredRow = -1;
410 587 : nCol++;
411 587 : while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
412 : }
413 : }
414 : }
415 : }
416 637 : if (bFound)
417 : {
418 580 : rCol = nCol;
419 580 : rRow = nRow;
420 : }
421 637 : return bFound;
422 : }
423 :
424 23 : bool ScTable::SearchAll(const SvxSearchItem& rSearchItem, const ScMarkData& rMark,
425 : ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
426 : {
427 23 : bool bFound = true;
428 23 : SCCOL nCol = 0;
429 23 : SCROW nRow = -1;
430 23 : bool bEverFound = false;
431 :
432 303 : do
433 : {
434 303 : bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
435 303 : if (bFound)
436 : {
437 280 : bEverFound = true;
438 280 : rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
439 : }
440 : }
441 : while (bFound);
442 :
443 23 : return bEverFound;
444 : }
445 :
446 0 : void ScTable::UpdateSearchItemAddressForReplace( const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow )
447 : {
448 0 : if (rSearchItem.GetBackward())
449 : {
450 0 : if (rSearchItem.GetRowDirection())
451 0 : rCol += 1;
452 : else
453 0 : rRow += 1;
454 : }
455 : else
456 : {
457 0 : if (rSearchItem.GetRowDirection())
458 0 : rCol -= 1;
459 : else
460 0 : rRow -= 1;
461 : }
462 0 : }
463 :
464 0 : bool ScTable::Replace(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
465 : const ScMarkData& rMark, OUString& rUndoStr, ScDocument* pUndoDoc)
466 : {
467 0 : bool bFound = false;
468 0 : SCCOL nCol = rCol;
469 0 : SCROW nRow = rRow;
470 :
471 0 : UpdateSearchItemAddressForReplace( rSearchItem, nCol, nRow );
472 0 : bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
473 0 : if (bFound)
474 : {
475 0 : rCol = nCol;
476 0 : rRow = nRow;
477 : }
478 0 : return bFound;
479 : }
480 :
481 26 : bool ScTable::ReplaceAll(
482 : const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges,
483 : OUString& rUndoStr, ScDocument* pUndoDoc)
484 : {
485 26 : SCCOL nCol = 0;
486 26 : SCROW nRow = -1;
487 :
488 26 : bool bEverFound = false;
489 : while (true)
490 : {
491 311 : bool bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
492 :
493 311 : if (bFound)
494 : {
495 285 : bEverFound = true;
496 285 : rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
497 : }
498 : else
499 26 : break;
500 : }
501 285 : return bEverFound;
502 : }
503 :
504 0 : bool ScTable::SearchStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
505 : const ScMarkData& rMark)
506 : {
507 : const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
508 0 : pDocument->GetStyleSheetPool()->Find(
509 0 : rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
510 :
511 0 : SCsCOL nCol = rCol;
512 0 : SCsROW nRow = rRow;
513 0 : bool bFound = false;
514 :
515 0 : bool bSelect = rSearchItem.GetSelection();
516 0 : bool bRows = rSearchItem.GetRowDirection();
517 0 : bool bBack = rSearchItem.GetBackward();
518 0 : short nAdd = bBack ? -1 : 1;
519 :
520 0 : if (bRows) // zeilenweise
521 : {
522 0 : nRow += nAdd;
523 0 : do
524 : {
525 0 : SCsROW nNextRow = aCol[nCol].SearchStyle( nRow, pSearchStyle, bBack, bSelect, rMark );
526 0 : if (!ValidRow(nNextRow))
527 : {
528 0 : nRow = bBack ? MAXROW : 0;
529 0 : nCol = sal::static_int_cast<SCsCOL>( nCol + nAdd );
530 : }
531 : else
532 : {
533 0 : nRow = nNextRow;
534 0 : bFound = true;
535 : }
536 : }
537 0 : while (!bFound && ValidCol(nCol));
538 : }
539 : else // spaltenweise
540 : {
541 : SCsROW nNextRows[MAXCOLCOUNT];
542 : SCsCOL i;
543 0 : for (i=0; i<=MAXCOL; i++)
544 : {
545 0 : SCsROW nSRow = nRow;
546 0 : if (bBack) { if (i>=nCol) --nSRow; }
547 0 : else { if (i<=nCol) ++nSRow; }
548 0 : nNextRows[i] = aCol[i].SearchStyle( nSRow, pSearchStyle, bBack, bSelect, rMark );
549 : }
550 0 : if (bBack) // rueckwaerts
551 : {
552 0 : nRow = -1;
553 0 : for (i=MAXCOL; i>=0; i--)
554 0 : if (nNextRows[i]>nRow)
555 : {
556 0 : nCol = i;
557 0 : nRow = nNextRows[i];
558 0 : bFound = true;
559 : }
560 : }
561 : else // vorwaerts
562 : {
563 0 : nRow = MAXROW+1;
564 0 : for (i=0; i<=MAXCOL; i++)
565 0 : if (nNextRows[i]<nRow)
566 : {
567 0 : nCol = i;
568 0 : nRow = nNextRows[i];
569 0 : bFound = true;
570 : }
571 : }
572 : }
573 :
574 0 : if (bFound)
575 : {
576 0 : rCol = (SCCOL) nCol;
577 0 : rRow = (SCROW) nRow;
578 : }
579 0 : return bFound;
580 : }
581 :
582 : //! einzelnes Pattern fuer Undo zurueckgeben
583 :
584 0 : bool ScTable::ReplaceStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
585 : const ScMarkData& rMark, bool bIsUndo)
586 : {
587 : bool bRet;
588 0 : if (bIsUndo)
589 0 : bRet = true;
590 : else
591 0 : bRet = SearchStyle(rSearchItem, rCol, rRow, rMark);
592 0 : if (bRet)
593 : {
594 : const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
595 0 : pDocument->GetStyleSheetPool()->Find(
596 0 : rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
597 :
598 0 : if (pReplaceStyle)
599 0 : ApplyStyle( rCol, rRow, *pReplaceStyle );
600 : else
601 : {
602 : OSL_FAIL("pReplaceStyle==0");
603 : }
604 : }
605 :
606 0 : return bRet;
607 : }
608 :
609 0 : bool ScTable::SearchAllStyle(
610 : const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges)
611 : {
612 : const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
613 0 : pDocument->GetStyleSheetPool()->Find(
614 0 : rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
615 0 : bool bSelect = rSearchItem.GetSelection();
616 0 : bool bBack = rSearchItem.GetBackward();
617 0 : bool bEverFound = false;
618 :
619 0 : for (SCCOL i=0; i<=MAXCOL; i++)
620 : {
621 0 : bool bFound = true;
622 0 : SCsROW nRow = 0;
623 : SCsROW nEndRow;
624 0 : while (bFound && nRow <= MAXROW)
625 : {
626 0 : bFound = aCol[i].SearchStyleRange( nRow, nEndRow, pSearchStyle, bBack, bSelect, rMark );
627 0 : if (bFound)
628 : {
629 0 : if (nEndRow<nRow)
630 : {
631 0 : SCsROW nTemp = nRow;
632 0 : nRow = nEndRow;
633 0 : nEndRow = nTemp;
634 : }
635 0 : rMatchedRanges.Join(ScRange(i, nRow, nTab, i, nEndRow, nTab));
636 0 : nRow = nEndRow + 1;
637 0 : bEverFound = true;
638 : }
639 : }
640 : }
641 :
642 0 : return bEverFound;
643 : }
644 :
645 0 : bool ScTable::ReplaceAllStyle(
646 : const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges,
647 : ScDocument* pUndoDoc)
648 : {
649 0 : bool bRet = SearchAllStyle(rSearchItem, rMark, rMatchedRanges);
650 0 : if (bRet)
651 : {
652 : const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
653 0 : pDocument->GetStyleSheetPool()->Find(
654 0 : rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
655 :
656 0 : if (pReplaceStyle)
657 : {
658 0 : if (pUndoDoc)
659 : pDocument->CopyToDocument( 0,0,nTab, MAXCOL,MAXROW,nTab,
660 0 : IDF_ATTRIB, true, pUndoDoc, &rMark );
661 0 : ApplySelectionStyle( *pReplaceStyle, rMark );
662 : }
663 : else
664 : {
665 : OSL_FAIL("pReplaceStyle==0");
666 : }
667 : }
668 :
669 0 : return bRet;
670 : }
671 :
672 72 : bool ScTable::SearchAndReplace(
673 : const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark,
674 : ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
675 : {
676 72 : sal_uInt16 nCommand = rSearchItem.GetCommand();
677 72 : bool bFound = false;
678 144 : if ( ValidColRow(rCol, rRow) ||
679 21 : ((nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE) &&
680 63 : (((rCol == MAXCOLCOUNT || rCol == -1) && ValidRow(rRow)) ||
681 42 : ((rRow == MAXROWCOUNT || rRow == -1) && ValidCol(rCol))
682 : )
683 : )
684 : )
685 : {
686 72 : bool bStyles = rSearchItem.GetPattern();
687 72 : if (bStyles)
688 : {
689 0 : if (nCommand == SVX_SEARCHCMD_FIND)
690 0 : bFound = SearchStyle(rSearchItem, rCol, rRow, rMark);
691 0 : else if (nCommand == SVX_SEARCHCMD_REPLACE)
692 0 : bFound = ReplaceStyle(rSearchItem, rCol, rRow, rMark, false);
693 0 : else if (nCommand == SVX_SEARCHCMD_FIND_ALL)
694 0 : bFound = SearchAllStyle(rSearchItem, rMark, rMatchedRanges);
695 0 : else if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
696 0 : bFound = ReplaceAllStyle(rSearchItem, rMark, rMatchedRanges, pUndoDoc);
697 : }
698 : else
699 : {
700 : // SearchParam no longer needed - SearchOptions contains all settings
701 72 : com::sun::star::util::SearchOptions aSearchOptions = rSearchItem.GetSearchOptions();
702 72 : aSearchOptions.Locale = *ScGlobal::GetLocale();
703 :
704 72 : if (aSearchOptions.searchString.isEmpty())
705 : {
706 : // Search for empty cells.
707 0 : return SearchAndReplaceEmptyCells(rSearchItem, rCol, rRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
708 : }
709 :
710 : // reflect UseAsianOptions flag in SearchOptions
711 : // (use only ignore case and width if asian options are disabled).
712 : // This is also done in SvxSearchDialog CommandHdl, but not in API object.
713 72 : if ( !rSearchItem.IsUseAsianOptions() )
714 : aSearchOptions.transliterateFlags &=
715 : ( com::sun::star::i18n::TransliterationModules_IGNORE_CASE |
716 72 : com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
717 :
718 72 : pSearchText = new utl::TextSearch( aSearchOptions );
719 :
720 72 : if (nCommand == SVX_SEARCHCMD_FIND)
721 23 : bFound = Search(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
722 49 : else if (nCommand == SVX_SEARCHCMD_FIND_ALL)
723 23 : bFound = SearchAll(rSearchItem, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
724 26 : else if (nCommand == SVX_SEARCHCMD_REPLACE)
725 0 : bFound = Replace(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
726 26 : else if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
727 26 : bFound = ReplaceAll(rSearchItem, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
728 :
729 72 : delete pSearchText;
730 72 : pSearchText = NULL;
731 : }
732 : }
733 72 : return bFound;
734 : }
735 :
736 0 : bool ScTable::SearchAndReplaceEmptyCells(
737 : const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark,
738 : ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
739 : {
740 : SCCOL nColStart, nColEnd;
741 : SCROW nRowStart, nRowEnd;
742 0 : GetFirstDataPos(nColStart, nRowStart);
743 0 : GetLastDataPos(nColEnd, nRowEnd);
744 :
745 0 : ScRangeList aRanges;
746 0 : aRanges.Append(ScRange(nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab));
747 :
748 0 : if (rSearchItem.GetSelection())
749 : {
750 : // current selection only.
751 0 : if (!rMark.IsMarked() && !rMark.IsMultiMarked())
752 : // There is no selection. Bail out.
753 0 : return false;
754 :
755 0 : ScRangeList aMarkedRanges, aNewRanges;
756 0 : rMark.FillRangeListWithMarks(&aMarkedRanges, true);
757 0 : for ( size_t i = 0, n = aMarkedRanges.size(); i < n; ++i )
758 : {
759 0 : ScRange* p = aMarkedRanges[ i ];
760 0 : if (p->aStart.Col() > nColEnd || p->aStart.Row() > nRowEnd)
761 : // This range is outside the data area. Skip it.
762 0 : continue;
763 :
764 : // Shrink the range into data area only.
765 0 : if (p->aStart.Col() < nColStart)
766 0 : p->aStart.SetCol(rCol);
767 0 : if (p->aStart.Row() < nRowStart)
768 0 : p->aStart.SetRow(rRow);
769 :
770 0 : if (p->aEnd.Col() > nColEnd)
771 0 : p->aEnd.SetCol(nColEnd);
772 0 : if (p->aEnd.Row() > nRowEnd)
773 0 : p->aEnd.SetRow(nRowEnd);
774 :
775 0 : aNewRanges.Append(*p);
776 : }
777 0 : aRanges = aNewRanges;
778 : }
779 :
780 0 : sal_uInt16 nCommand = rSearchItem.GetCommand();
781 0 : if (nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE)
782 : {
783 0 : if (rSearchItem.GetBackward())
784 : {
785 0 : for ( size_t i = aRanges.size(); i > 0; --i )
786 : {
787 0 : ScRange* p = aRanges[ i - 1 ];
788 0 : if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr))
789 0 : return true;
790 : }
791 : }
792 : else
793 : {
794 0 : for ( size_t i = 0, nListSize = aRanges.size(); i < nListSize; ++i )
795 : {
796 0 : ScRange* p = aRanges[ i ];
797 0 : if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr))
798 0 : return true;
799 : }
800 0 : }
801 : }
802 0 : else if (nCommand == SVX_SEARCHCMD_FIND_ALL || nCommand == SVX_SEARCHCMD_REPLACE_ALL)
803 : {
804 0 : bool bFound = false;
805 0 : for ( size_t i = 0, nListSize = aRanges.size(); i < nListSize; ++i )
806 : {
807 0 : ScRange* p = aRanges[ i ];
808 0 : bFound |= SearchRangeForAllEmptyCells(*p, rSearchItem, rMatchedRanges, rUndoStr, pUndoDoc);
809 : }
810 0 : return bFound;
811 : }
812 0 : return false;
813 : }
814 :
815 : namespace {
816 :
817 0 : bool lcl_maybeReplaceCellString(
818 : ScColumn& rColObj, SCCOL& rCol, SCROW& rRow, OUString& rUndoStr, SCCOL nCol, SCROW nRow, const SvxSearchItem& rSearchItem)
819 : {
820 0 : ScRefCellValue aCell = rColObj.GetCellValue(nRow);
821 0 : if (aCell.isEmpty())
822 : {
823 : // empty cell found.
824 0 : rCol = nCol;
825 0 : rRow = nRow;
826 0 : if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
827 0 : !rSearchItem.GetReplaceString().isEmpty())
828 : {
829 0 : rColObj.SetRawString(nRow, rSearchItem.GetReplaceString());
830 0 : rUndoStr = OUString();
831 : }
832 0 : return true;
833 : }
834 0 : return false;
835 : }
836 :
837 : }
838 :
839 0 : bool ScTable::SearchRangeForEmptyCell(
840 : const ScRange& rRange, const SvxSearchItem& rSearchItem,
841 : SCCOL& rCol, SCROW& rRow, OUString& rUndoStr)
842 : {
843 0 : sal_uInt16 nCmd = rSearchItem.GetCommand();
844 0 : bool bSkipFiltered = rSearchItem.IsSearchFiltered();
845 0 : if (rSearchItem.GetBackward())
846 : {
847 : // backward search
848 0 : if (rSearchItem.GetRowDirection())
849 : {
850 : // row direction.
851 0 : SCROW nLastNonFilteredRow = MAXROW + 1;
852 0 : SCROW nBeginRow = rRange.aEnd.Row() > rRow ? rRow : rRange.aEnd.Row();
853 0 : for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
854 : {
855 0 : if (bSkipFiltered)
856 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, false);
857 0 : if (nRow < rRange.aStart.Row())
858 0 : break;
859 :
860 0 : SCCOL nBeginCol = rRange.aEnd.Col();
861 0 : if (nRow == rRow && nBeginCol >= rCol)
862 : // always start from one cell before the cursor.
863 0 : nBeginCol = rCol - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
864 :
865 0 : for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
866 : {
867 0 : if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
868 0 : return true;
869 : }
870 : }
871 : }
872 : else
873 : {
874 : // column direction.
875 0 : SCCOL nBeginCol = rRange.aEnd.Col() > rCol ? rCol : rRange.aEnd.Col();
876 0 : for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
877 : {
878 0 : SCROW nLastNonFilteredRow = MAXROW + 1;
879 0 : SCROW nBeginRow = rRange.aEnd.Row();
880 0 : if (nCol == rCol && nBeginRow >= rRow)
881 : // always start from one cell before the cursor.
882 0 : nBeginRow = rRow - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
883 0 : for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
884 : {
885 0 : if (bSkipFiltered)
886 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, false);
887 0 : if (nRow < rRange.aStart.Row())
888 0 : break;
889 :
890 0 : if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
891 0 : return true;
892 : }
893 : }
894 : }
895 : }
896 : else
897 : {
898 : // forward search
899 0 : if (rSearchItem.GetRowDirection())
900 : {
901 : // row direction.
902 0 : SCROW nLastNonFilteredRow = -1;
903 0 : SCROW nBeginRow = rRange.aStart.Row() < rRow ? rRow : rRange.aStart.Row();
904 0 : for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
905 : {
906 0 : if (bSkipFiltered)
907 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
908 0 : if (nRow > rRange.aEnd.Row())
909 0 : break;
910 :
911 0 : SCCOL nBeginCol = rRange.aStart.Col();
912 0 : if (nRow == rRow && nBeginCol <= rCol)
913 : // always start from one cell past the cursor.
914 0 : nBeginCol = rCol + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
915 0 : for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
916 : {
917 0 : if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
918 0 : return true;
919 : }
920 : }
921 : }
922 : else
923 : {
924 : // column direction.
925 0 : SCCOL nBeginCol = rRange.aStart.Col() < rCol ? rCol : rRange.aStart.Col();
926 0 : for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
927 : {
928 0 : SCROW nLastNonFilteredRow = -1;
929 0 : SCROW nBeginRow = rRange.aStart.Row();
930 0 : if (nCol == rCol && nBeginRow <= rRow)
931 : // always start from one cell past the cursor.
932 0 : nBeginRow = rRow + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
933 0 : for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
934 : {
935 0 : if (bSkipFiltered)
936 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
937 0 : if (nRow > rRange.aEnd.Row())
938 0 : break;
939 :
940 0 : if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
941 0 : return true;
942 : }
943 : }
944 : }
945 : }
946 0 : return false;
947 : }
948 :
949 0 : bool ScTable::SearchRangeForAllEmptyCells(
950 : const ScRange& rRange, const SvxSearchItem& rSearchItem,
951 : ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
952 : {
953 0 : bool bFound = false;
954 0 : bool bReplace = (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) &&
955 0 : !rSearchItem.GetReplaceString().isEmpty();
956 0 : bool bSkipFiltered = rSearchItem.IsSearchFiltered();
957 :
958 0 : for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
959 : {
960 0 : SCROW nLastNonFilteredRow = -1;
961 0 : if (aCol[nCol].IsEmptyData())
962 : {
963 : // The entire column is empty.
964 0 : for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
965 : {
966 : SCROW nLastRow;
967 0 : if (!RowFiltered(nRow, NULL, &nLastRow))
968 : {
969 0 : rMatchedRanges.Join(ScRange(nCol, nRow, nTab, nCol, nLastRow, nTab));
970 0 : if (bReplace)
971 : {
972 0 : const String& rNewStr = rSearchItem.GetReplaceString();
973 0 : for (SCROW i = nRow; i <= nLastRow; ++i)
974 : {
975 0 : aCol[nCol].SetRawString(i, rNewStr);
976 0 : if (pUndoDoc)
977 : {
978 : // TODO: I'm using a string cell with empty content to
979 : // trigger deletion of cell instance on undo. Maybe I
980 : // should create a new cell type for this?
981 0 : ScSetStringParam aParam;
982 0 : aParam.setTextInput();
983 0 : pUndoDoc->SetString(ScAddress(nCol, i, nTab), EMPTY_OUSTRING);
984 : }
985 : }
986 0 : rUndoStr = String();
987 : }
988 : }
989 :
990 0 : nRow = nLastRow; // move to the last filtered row.
991 : }
992 0 : bFound = true;
993 0 : continue;
994 : }
995 :
996 0 : for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
997 : {
998 0 : if (bSkipFiltered)
999 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
1000 0 : if (nRow > rRange.aEnd.Row())
1001 0 : break;
1002 :
1003 0 : ScRefCellValue aCell = aCol[nCol].GetCellValue(nRow);
1004 0 : if (aCell.isEmpty())
1005 : {
1006 : // empty cell found
1007 0 : rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
1008 0 : bFound = true;
1009 :
1010 0 : if (bReplace)
1011 : {
1012 0 : aCol[nCol].SetRawString(nRow, rSearchItem.GetReplaceString());
1013 0 : if (pUndoDoc)
1014 : {
1015 : // TODO: I'm using a string cell with empty content to
1016 : // trigger deletion of cell instance on undo. Maybe I
1017 : // should create a new cell type for this?
1018 0 : ScSetStringParam aParam;
1019 0 : aParam.setTextInput();
1020 0 : pUndoDoc->SetString(ScAddress(nCol, nRow, nTab), EMPTY_OUSTRING);
1021 : }
1022 : }
1023 : }
1024 0 : }
1025 : }
1026 0 : return bFound;
1027 : }
1028 :
1029 0 : void ScTable::RebuildFormulaGroups()
1030 : {
1031 0 : for (SCCOL i=0; i<=MAXCOL; i++)
1032 0 : aCol[i].RebuildFormulaGroups();
1033 93 : }
1034 :
1035 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|