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 : using ::com::sun::star::util::SearchOptions;
37 :
38 : namespace {
39 :
40 0 : bool lcl_GetTextWithBreaks( const EditTextObject& rData, ScDocument* pDoc, OUString& rVal )
41 : {
42 : // true = more than 1 paragraph
43 :
44 0 : EditEngine& rEngine = pDoc->GetEditEngine();
45 0 : rEngine.SetText(rData);
46 0 : rVal = rEngine.GetText( LINEEND_LF );
47 0 : return ( rEngine.GetParagraphCount() > 1 );
48 : }
49 :
50 : }
51 :
52 9188 : bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, SCROW nRow,
53 : const ScMarkData& rMark, OUString& rUndoStr, ScDocument* pUndoDoc)
54 : {
55 9188 : if (!ValidColRow( nCol, nRow))
56 0 : return false;
57 :
58 9188 : bool bFound = false;
59 9188 : bool bDoSearch = true;
60 9188 : bool bDoBack = rSearchItem.GetBackward();
61 :
62 9188 : OUString aString;
63 18376 : ScRefCellValue aCell;
64 9188 : if (rSearchItem.GetSelection())
65 8954 : bDoSearch = rMark.IsCellMarked(nCol, nRow);
66 :
67 9188 : if (!bDoSearch)
68 7024 : return false;
69 :
70 2164 : aCell = aCol[nCol].GetCellValue(nRow);
71 2164 : if (aCell.isEmpty())
72 126 : return false;
73 :
74 2038 : bool bMultiLine = false;
75 2038 : CellType eCellType = aCell.meType;
76 2038 : switch (rSearchItem.GetCellType())
77 : {
78 : case SVX_SEARCHIN_FORMULA:
79 : {
80 2038 : if ( eCellType == CELLTYPE_FORMULA )
81 36 : aCell.mpFormula->GetFormula(aString, pDocument->GetGrammar());
82 2002 : else if ( eCellType == CELLTYPE_EDIT )
83 0 : bMultiLine = lcl_GetTextWithBreaks(*aCell.mpEditText, pDocument, aString);
84 : else
85 : {
86 2002 : aCol[nCol].GetInputString( nRow, aString );
87 : }
88 : }
89 2038 : 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 2038 : sal_Int32 nStart = 0;
104 2038 : sal_Int32 nEnd = aString.getLength();
105 2038 : ::com::sun::star::util::SearchResult aSearchResult;
106 2038 : if (pSearchText)
107 : {
108 2038 : 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 2038 : bFound = pSearchText->SearchForward(aString, &nStart, &nEnd, &aSearchResult);
118 : // change results to definition before 614:
119 2038 : --nEnd;
120 : }
121 :
122 2038 : if (bFound && rSearchItem.GetWordOnly())
123 212 : bFound = (nStart == 0 && nEnd == aString.getLength() - 1);
124 : }
125 : else
126 : {
127 : OSL_FAIL("pSearchText == NULL");
128 0 : return bFound;
129 : }
130 :
131 2038 : sal_uInt8 cMatrixFlag = MM_NONE;
132 3198 : if ( bFound &&
133 1160 : ( (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE)
134 1160 : ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) ) &&
135 : // Matrix nicht zerreissen, nur Matrixformel ersetzen
136 6 : !( (eCellType == CELLTYPE_FORMULA &&
137 6 : ((cMatrixFlag = aCell.mpFormula->GetMatrixFlag()) == MM_REFERENCE))
138 : // kein UndoDoc => Matrix nicht wiederherstellbar => nicht ersetzen
139 3178 : || (cMatrixFlag != MM_NONE && !pUndoDoc) ) &&
140 570 : IsBlockEditable(nCol, nRow, nCol, nRow)
141 : )
142 : {
143 570 : if ( cMatrixFlag == MM_NONE && rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE )
144 0 : rUndoStr = aString;
145 570 : else if (pUndoDoc)
146 : {
147 570 : ScAddress aAdr( nCol, nRow, nTab );
148 570 : aCell.commit(*pUndoDoc, aAdr);
149 : }
150 570 : bool bRepeat = !rSearchItem.GetWordOnly();
151 570 : do
152 : {
153 : // wenn der gefundene Text leer ist, nicht weitersuchen,
154 : // sonst wuerde man nie mehr aufhoeren (#35410#)
155 570 : if ( nEnd < nStart )
156 0 : bRepeat = false;
157 :
158 570 : OUString sReplStr = rSearchItem.GetReplaceString();
159 570 : if (rSearchItem.GetRegExp())
160 : {
161 538 : pSearchText->ReplaceBackReferences( sReplStr, aString, aSearchResult );
162 538 : OUStringBuffer aStrBuffer(aString);
163 538 : aStrBuffer.remove(nStart, nEnd-nStart+1);
164 538 : aStrBuffer.insert(nStart, sReplStr);
165 538 : aString = aStrBuffer.makeStringAndClear();
166 : }
167 : else
168 : {
169 32 : OUStringBuffer aStrBuffer(aString);
170 32 : aStrBuffer.remove(nStart, nEnd-nStart+1);
171 32 : aStrBuffer.insert(nStart, rSearchItem.GetReplaceString());
172 32 : aString = aStrBuffer.makeStringAndClear();
173 : }
174 :
175 : // Indizes anpassen
176 570 : if (bDoBack)
177 : {
178 0 : nEnd = nStart;
179 0 : nStart = 0;
180 : }
181 : else
182 : {
183 570 : nStart = nStart + sReplStr.getLength();
184 570 : nEnd = aString.getLength();
185 : }
186 :
187 : // weitersuchen ?
188 570 : if (bRepeat)
189 : {
190 570 : if ( rSearchItem.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL || nStart >= nEnd )
191 562 : bRepeat = false;
192 8 : 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 8 : bRepeat = pSearchText->SearchForward(aString, &nStart, &nEnd, &aSearchResult);
202 : // change results to definition before 614:
203 8 : --nEnd;
204 : }
205 570 : }
206 : }
207 : while (bRepeat);
208 :
209 570 : 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 570 : 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 570 : aCol[nCol].SetString(nRow, nTab, aString, pDocument->GetAddressConvention());
235 : // pCell is invalid now (deleted)
236 : }
237 11226 : return bFound;
238 : }
239 :
240 9188 : void ScTable::SkipFilteredRows(SCROW& rRow, SCROW& rLastNonFilteredRow, bool bForward)
241 : {
242 9188 : if (bForward)
243 : {
244 : // forward search
245 :
246 9188 : if (rRow <= rLastNonFilteredRow)
247 6872 : return;
248 :
249 2316 : SCROW nLastRow = rRow;
250 2316 : 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 2316 : 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 1274 : bool ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
277 : const ScMarkData& rMark, OUString& rUndoStr, ScDocument* pUndoDoc)
278 : {
279 1274 : bool bFound = false;
280 1274 : bool bAll = (rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL)
281 1274 : ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL);
282 1274 : SCCOL nCol = rCol;
283 1274 : SCROW nRow = rRow;
284 : SCCOL nLastCol;
285 : SCROW nLastRow;
286 1274 : GetLastDataPos(nLastCol, nLastRow);
287 1274 : bool bSkipFiltered = !rSearchItem.IsSearchFiltered();
288 1274 : 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 1274 : SCROW nLastNonFilteredRow = -1;
364 1274 : 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 1274 : nRow++;
391 4882 : while (!bFound && (nCol <= nLastCol))
392 : {
393 13856 : while (!bFound && (nRow <= nLastRow))
394 : {
395 9188 : if (bSkipFiltered)
396 9188 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
397 :
398 9188 : bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
399 9188 : if (!bFound)
400 : {
401 8028 : if (!aCol[nCol].GetNextDataPos(nRow))
402 1156 : nRow = MAXROW + 1;
403 : }
404 : }
405 2334 : if (!bFound)
406 : {
407 : // Not found in this column. Move to the next column.
408 1174 : nRow = 0;
409 1174 : nLastNonFilteredRow = -1;
410 1174 : nCol++;
411 1174 : while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
412 : }
413 : }
414 : }
415 : }
416 1274 : if (bFound)
417 : {
418 1160 : rCol = nCol;
419 1160 : rRow = nRow;
420 : }
421 1274 : return bFound;
422 : }
423 :
424 46 : bool ScTable::SearchAll(const SvxSearchItem& rSearchItem, const ScMarkData& rMark,
425 : ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
426 : {
427 46 : bool bFound = true;
428 46 : SCCOL nCol = 0;
429 46 : SCROW nRow = -1;
430 46 : bool bEverFound = false;
431 :
432 606 : do
433 : {
434 606 : bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
435 606 : if (bFound)
436 : {
437 560 : bEverFound = true;
438 560 : rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
439 : }
440 : }
441 : while (bFound);
442 :
443 46 : 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 : SCCOL nCol = rCol;
468 0 : SCROW nRow = rRow;
469 :
470 0 : UpdateSearchItemAddressForReplace( rSearchItem, nCol, nRow );
471 0 : bool bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
472 0 : if (bFound)
473 : {
474 0 : rCol = nCol;
475 0 : rRow = nRow;
476 : }
477 0 : return bFound;
478 : }
479 :
480 52 : bool ScTable::ReplaceAll(
481 : const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges,
482 : OUString& rUndoStr, ScDocument* pUndoDoc)
483 : {
484 52 : SCCOL nCol = 0;
485 52 : SCROW nRow = -1;
486 :
487 52 : bool bEverFound = false;
488 : while (true)
489 : {
490 622 : bool bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
491 :
492 622 : if (bFound)
493 : {
494 570 : bEverFound = true;
495 570 : rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
496 : }
497 : else
498 52 : break;
499 : }
500 570 : return bEverFound;
501 : }
502 :
503 0 : bool ScTable::SearchStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
504 : const ScMarkData& rMark)
505 : {
506 : const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
507 0 : pDocument->GetStyleSheetPool()->Find(
508 0 : rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
509 :
510 0 : SCsCOL nCol = rCol;
511 0 : SCsROW nRow = rRow;
512 0 : bool bFound = false;
513 :
514 0 : bool bSelect = rSearchItem.GetSelection();
515 0 : bool bRows = rSearchItem.GetRowDirection();
516 0 : bool bBack = rSearchItem.GetBackward();
517 0 : short nAdd = bBack ? -1 : 1;
518 :
519 0 : if (bRows) // zeilenweise
520 : {
521 0 : if (!ValidCol(nCol))
522 : {
523 : SAL_WARN( "sc.core", "SearchStyle: bad column " << nCol);
524 0 : return false;
525 : }
526 0 : nRow += nAdd;
527 0 : do
528 : {
529 0 : SCsROW nNextRow = aCol[nCol].SearchStyle( nRow, pSearchStyle, bBack, bSelect, rMark );
530 0 : if (!ValidRow(nNextRow))
531 : {
532 0 : nRow = bBack ? MAXROW : 0;
533 0 : nCol = sal::static_int_cast<SCsCOL>( nCol + nAdd );
534 : }
535 : else
536 : {
537 0 : nRow = nNextRow;
538 0 : bFound = true;
539 : }
540 : }
541 0 : while (!bFound && ValidCol(nCol));
542 : }
543 : else // spaltenweise
544 : {
545 : SCsROW nNextRows[MAXCOLCOUNT];
546 : SCsCOL i;
547 0 : for (i=0; i<=MAXCOL; i++)
548 : {
549 0 : SCsROW nSRow = nRow;
550 0 : if (bBack) { if (i>=nCol) --nSRow; }
551 0 : else { if (i<=nCol) ++nSRow; }
552 0 : nNextRows[i] = aCol[i].SearchStyle( nSRow, pSearchStyle, bBack, bSelect, rMark );
553 : }
554 0 : if (bBack) // rueckwaerts
555 : {
556 0 : nRow = -1;
557 0 : for (i=MAXCOL; i>=0; i--)
558 0 : if (nNextRows[i]>nRow)
559 : {
560 0 : nCol = i;
561 0 : nRow = nNextRows[i];
562 0 : bFound = true;
563 : }
564 : }
565 : else // vorwaerts
566 : {
567 0 : nRow = MAXROW+1;
568 0 : for (i=0; i<=MAXCOL; i++)
569 0 : if (nNextRows[i]<nRow)
570 : {
571 0 : nCol = i;
572 0 : nRow = nNextRows[i];
573 0 : bFound = true;
574 : }
575 : }
576 : }
577 :
578 0 : if (bFound)
579 : {
580 0 : rCol = (SCCOL) nCol;
581 0 : rRow = (SCROW) nRow;
582 : }
583 0 : return bFound;
584 : }
585 :
586 : //! einzelnes Pattern fuer Undo zurueckgeben
587 :
588 0 : bool ScTable::ReplaceStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
589 : const ScMarkData& rMark, bool bIsUndo)
590 : {
591 : bool bRet;
592 0 : if (bIsUndo)
593 0 : bRet = true;
594 : else
595 0 : bRet = SearchStyle(rSearchItem, rCol, rRow, rMark);
596 0 : if (bRet)
597 : {
598 : const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
599 0 : pDocument->GetStyleSheetPool()->Find(
600 0 : rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
601 :
602 0 : if (pReplaceStyle)
603 0 : ApplyStyle( rCol, rRow, *pReplaceStyle );
604 : else
605 : {
606 : OSL_FAIL("pReplaceStyle==0");
607 : }
608 : }
609 :
610 0 : return bRet;
611 : }
612 :
613 0 : bool ScTable::SearchAllStyle(
614 : const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges)
615 : {
616 : const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
617 0 : pDocument->GetStyleSheetPool()->Find(
618 0 : rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
619 0 : bool bSelect = rSearchItem.GetSelection();
620 0 : bool bBack = rSearchItem.GetBackward();
621 0 : bool bEverFound = false;
622 :
623 0 : for (SCCOL i=0; i<=MAXCOL; i++)
624 : {
625 0 : bool bFound = true;
626 0 : SCsROW nRow = 0;
627 : SCsROW nEndRow;
628 0 : while (bFound && nRow <= MAXROW)
629 : {
630 0 : bFound = aCol[i].SearchStyleRange( nRow, nEndRow, pSearchStyle, bBack, bSelect, rMark );
631 0 : if (bFound)
632 : {
633 0 : if (nEndRow<nRow)
634 : {
635 0 : SCsROW nTemp = nRow;
636 0 : nRow = nEndRow;
637 0 : nEndRow = nTemp;
638 : }
639 0 : rMatchedRanges.Join(ScRange(i, nRow, nTab, i, nEndRow, nTab));
640 0 : nRow = nEndRow + 1;
641 0 : bEverFound = true;
642 : }
643 : }
644 : }
645 :
646 0 : return bEverFound;
647 : }
648 :
649 0 : bool ScTable::ReplaceAllStyle(
650 : const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges,
651 : ScDocument* pUndoDoc)
652 : {
653 0 : bool bRet = SearchAllStyle(rSearchItem, rMark, rMatchedRanges);
654 0 : if (bRet)
655 : {
656 : const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
657 0 : pDocument->GetStyleSheetPool()->Find(
658 0 : rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
659 :
660 0 : if (pReplaceStyle)
661 : {
662 0 : if (pUndoDoc)
663 : pDocument->CopyToDocument( 0,0,nTab, MAXCOL,MAXROW,nTab,
664 0 : IDF_ATTRIB, true, pUndoDoc, &rMark );
665 0 : ApplySelectionStyle( *pReplaceStyle, rMark );
666 : }
667 : else
668 : {
669 : OSL_FAIL("pReplaceStyle==0");
670 : }
671 : }
672 :
673 0 : return bRet;
674 : }
675 :
676 144 : bool ScTable::SearchAndReplace(
677 : const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark,
678 : ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
679 : {
680 144 : sal_uInt16 nCommand = rSearchItem.GetCommand();
681 144 : bool bFound = false;
682 288 : if ( ValidColRow(rCol, rRow) ||
683 42 : ((nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE) &&
684 126 : (((rCol == MAXCOLCOUNT || rCol == -1) && ValidRow(rRow)) ||
685 84 : ((rRow == MAXROWCOUNT || rRow == -1) && ValidCol(rCol))
686 : )
687 : )
688 : )
689 : {
690 144 : bool bStyles = rSearchItem.GetPattern();
691 144 : if (bStyles)
692 : {
693 0 : if (nCommand == SVX_SEARCHCMD_FIND)
694 0 : bFound = SearchStyle(rSearchItem, rCol, rRow, rMark);
695 0 : else if (nCommand == SVX_SEARCHCMD_REPLACE)
696 0 : bFound = ReplaceStyle(rSearchItem, rCol, rRow, rMark, false);
697 0 : else if (nCommand == SVX_SEARCHCMD_FIND_ALL)
698 0 : bFound = SearchAllStyle(rSearchItem, rMark, rMatchedRanges);
699 0 : else if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
700 0 : bFound = ReplaceAllStyle(rSearchItem, rMark, rMatchedRanges, pUndoDoc);
701 : }
702 : else
703 : {
704 : // SearchParam no longer needed - SearchOptions contains all settings
705 144 : com::sun::star::util::SearchOptions aSearchOptions = rSearchItem.GetSearchOptions();
706 144 : aSearchOptions.Locale = *ScGlobal::GetLocale();
707 :
708 144 : if (aSearchOptions.searchString.isEmpty())
709 : {
710 : // Search for empty cells.
711 0 : return SearchAndReplaceEmptyCells(rSearchItem, rCol, rRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
712 : }
713 :
714 : // reflect UseAsianOptions flag in SearchOptions
715 : // (use only ignore case and width if asian options are disabled).
716 : // This is also done in SvxSearchDialog CommandHdl, but not in API object.
717 144 : if ( !rSearchItem.IsUseAsianOptions() )
718 : aSearchOptions.transliterateFlags &=
719 : ( com::sun::star::i18n::TransliterationModules_IGNORE_CASE |
720 144 : com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
721 :
722 144 : pSearchText = new utl::TextSearch( aSearchOptions );
723 :
724 144 : if (nCommand == SVX_SEARCHCMD_FIND)
725 46 : bFound = Search(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
726 98 : else if (nCommand == SVX_SEARCHCMD_FIND_ALL)
727 46 : bFound = SearchAll(rSearchItem, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
728 52 : else if (nCommand == SVX_SEARCHCMD_REPLACE)
729 0 : bFound = Replace(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
730 52 : else if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
731 52 : bFound = ReplaceAll(rSearchItem, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
732 :
733 144 : delete pSearchText;
734 144 : pSearchText = NULL;
735 : }
736 : }
737 144 : return bFound;
738 : }
739 :
740 0 : bool ScTable::SearchAndReplaceEmptyCells(
741 : const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark,
742 : ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
743 : {
744 : SCCOL nColStart, nColEnd;
745 : SCROW nRowStart, nRowEnd;
746 0 : GetFirstDataPos(nColStart, nRowStart);
747 0 : GetLastDataPos(nColEnd, nRowEnd);
748 :
749 0 : ScRangeList aRanges;
750 0 : aRanges.Append(ScRange(nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab));
751 :
752 0 : if (rSearchItem.GetSelection())
753 : {
754 : // current selection only.
755 0 : if (!rMark.IsMarked() && !rMark.IsMultiMarked())
756 : // There is no selection. Bail out.
757 0 : return false;
758 :
759 0 : ScRangeList aMarkedRanges, aNewRanges;
760 0 : rMark.FillRangeListWithMarks(&aMarkedRanges, true);
761 0 : for ( size_t i = 0, n = aMarkedRanges.size(); i < n; ++i )
762 : {
763 0 : ScRange* p = aMarkedRanges[ i ];
764 0 : if (p->aStart.Col() > nColEnd || p->aStart.Row() > nRowEnd)
765 : // This range is outside the data area. Skip it.
766 0 : continue;
767 :
768 : // Shrink the range into data area only.
769 0 : if (p->aStart.Col() < nColStart)
770 0 : p->aStart.SetCol(rCol);
771 0 : if (p->aStart.Row() < nRowStart)
772 0 : p->aStart.SetRow(rRow);
773 :
774 0 : if (p->aEnd.Col() > nColEnd)
775 0 : p->aEnd.SetCol(nColEnd);
776 0 : if (p->aEnd.Row() > nRowEnd)
777 0 : p->aEnd.SetRow(nRowEnd);
778 :
779 0 : aNewRanges.Append(*p);
780 : }
781 0 : aRanges = aNewRanges;
782 : }
783 :
784 0 : sal_uInt16 nCommand = rSearchItem.GetCommand();
785 0 : if (nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE)
786 : {
787 0 : if (rSearchItem.GetBackward())
788 : {
789 0 : for ( size_t i = aRanges.size(); i > 0; --i )
790 : {
791 0 : ScRange* p = aRanges[ i - 1 ];
792 0 : if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr))
793 0 : return true;
794 : }
795 : }
796 : else
797 : {
798 0 : for ( size_t i = 0, nListSize = aRanges.size(); i < nListSize; ++i )
799 : {
800 0 : ScRange* p = aRanges[ i ];
801 0 : if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr))
802 0 : return true;
803 : }
804 0 : }
805 : }
806 0 : else if (nCommand == SVX_SEARCHCMD_FIND_ALL || nCommand == SVX_SEARCHCMD_REPLACE_ALL)
807 : {
808 0 : bool bFound = false;
809 0 : for ( size_t i = 0, nListSize = aRanges.size(); i < nListSize; ++i )
810 : {
811 0 : ScRange* p = aRanges[ i ];
812 0 : bFound |= SearchRangeForAllEmptyCells(*p, rSearchItem, rMatchedRanges, rUndoStr, pUndoDoc);
813 : }
814 0 : return bFound;
815 : }
816 0 : return false;
817 : }
818 :
819 : namespace {
820 :
821 0 : bool lcl_maybeReplaceCellString(
822 : ScColumn& rColObj, SCCOL& rCol, SCROW& rRow, OUString& rUndoStr, SCCOL nCol, SCROW nRow, const SvxSearchItem& rSearchItem)
823 : {
824 0 : ScRefCellValue aCell = rColObj.GetCellValue(nRow);
825 0 : if (aCell.isEmpty())
826 : {
827 : // empty cell found.
828 0 : rCol = nCol;
829 0 : rRow = nRow;
830 0 : if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
831 0 : !rSearchItem.GetReplaceString().isEmpty())
832 : {
833 0 : rColObj.SetRawString(nRow, rSearchItem.GetReplaceString());
834 0 : rUndoStr = OUString();
835 : }
836 0 : return true;
837 : }
838 0 : return false;
839 : }
840 :
841 : }
842 :
843 0 : bool ScTable::SearchRangeForEmptyCell(
844 : const ScRange& rRange, const SvxSearchItem& rSearchItem,
845 : SCCOL& rCol, SCROW& rRow, OUString& rUndoStr)
846 : {
847 0 : sal_uInt16 nCmd = rSearchItem.GetCommand();
848 0 : bool bSkipFiltered = rSearchItem.IsSearchFiltered();
849 0 : if (rSearchItem.GetBackward())
850 : {
851 : // backward search
852 0 : if (rSearchItem.GetRowDirection())
853 : {
854 : // row direction.
855 0 : SCROW nLastNonFilteredRow = MAXROW + 1;
856 0 : SCROW nBeginRow = rRange.aEnd.Row() > rRow ? rRow : rRange.aEnd.Row();
857 0 : for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
858 : {
859 0 : if (bSkipFiltered)
860 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, false);
861 0 : if (nRow < rRange.aStart.Row())
862 0 : break;
863 :
864 0 : SCCOL nBeginCol = rRange.aEnd.Col();
865 0 : if (nRow == rRow && nBeginCol >= rCol)
866 : // always start from one cell before the cursor.
867 0 : nBeginCol = rCol - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
868 :
869 0 : for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
870 : {
871 0 : if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
872 0 : return true;
873 : }
874 : }
875 : }
876 : else
877 : {
878 : // column direction.
879 0 : SCCOL nBeginCol = rRange.aEnd.Col() > rCol ? rCol : rRange.aEnd.Col();
880 0 : for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
881 : {
882 0 : SCROW nLastNonFilteredRow = MAXROW + 1;
883 0 : SCROW nBeginRow = rRange.aEnd.Row();
884 0 : if (nCol == rCol && nBeginRow >= rRow)
885 : // always start from one cell before the cursor.
886 0 : nBeginRow = rRow - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
887 0 : for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
888 : {
889 0 : if (bSkipFiltered)
890 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, false);
891 0 : if (nRow < rRange.aStart.Row())
892 0 : break;
893 :
894 0 : if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
895 0 : return true;
896 : }
897 : }
898 : }
899 : }
900 : else
901 : {
902 : // forward search
903 0 : if (rSearchItem.GetRowDirection())
904 : {
905 : // row direction.
906 0 : SCROW nLastNonFilteredRow = -1;
907 0 : SCROW nBeginRow = rRange.aStart.Row() < rRow ? rRow : rRange.aStart.Row();
908 0 : for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
909 : {
910 0 : if (bSkipFiltered)
911 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
912 0 : if (nRow > rRange.aEnd.Row())
913 0 : break;
914 :
915 0 : SCCOL nBeginCol = rRange.aStart.Col();
916 0 : if (nRow == rRow && nBeginCol <= rCol)
917 : // always start from one cell past the cursor.
918 0 : nBeginCol = rCol + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
919 0 : for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
920 : {
921 0 : if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
922 0 : return true;
923 : }
924 : }
925 : }
926 : else
927 : {
928 : // column direction.
929 0 : SCCOL nBeginCol = rRange.aStart.Col() < rCol ? rCol : rRange.aStart.Col();
930 0 : for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
931 : {
932 0 : SCROW nLastNonFilteredRow = -1;
933 0 : SCROW nBeginRow = rRange.aStart.Row();
934 0 : if (nCol == rCol && nBeginRow <= rRow)
935 : // always start from one cell past the cursor.
936 0 : nBeginRow = rRow + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0);
937 0 : for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
938 : {
939 0 : if (bSkipFiltered)
940 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
941 0 : if (nRow > rRange.aEnd.Row())
942 0 : break;
943 :
944 0 : if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
945 0 : return true;
946 : }
947 : }
948 : }
949 : }
950 0 : return false;
951 : }
952 :
953 0 : bool ScTable::SearchRangeForAllEmptyCells(
954 : const ScRange& rRange, const SvxSearchItem& rSearchItem,
955 : ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
956 : {
957 0 : bool bFound = false;
958 0 : bool bReplace = (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) &&
959 0 : !rSearchItem.GetReplaceString().isEmpty();
960 0 : bool bSkipFiltered = rSearchItem.IsSearchFiltered();
961 :
962 0 : for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
963 : {
964 0 : SCROW nLastNonFilteredRow = -1;
965 0 : if (aCol[nCol].IsEmptyData())
966 : {
967 : // The entire column is empty.
968 0 : for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
969 : {
970 : SCROW nLastRow;
971 0 : if (!RowFiltered(nRow, NULL, &nLastRow))
972 : {
973 0 : rMatchedRanges.Join(ScRange(nCol, nRow, nTab, nCol, nLastRow, nTab));
974 0 : if (bReplace)
975 : {
976 0 : const OUString& rNewStr = rSearchItem.GetReplaceString();
977 0 : for (SCROW i = nRow; i <= nLastRow; ++i)
978 : {
979 0 : aCol[nCol].SetRawString(i, rNewStr);
980 0 : if (pUndoDoc)
981 : {
982 : // TODO: I'm using a string cell with empty content to
983 : // trigger deletion of cell instance on undo. Maybe I
984 : // should create a new cell type for this?
985 0 : ScSetStringParam aParam;
986 0 : aParam.setTextInput();
987 0 : pUndoDoc->SetString(ScAddress(nCol, i, nTab), EMPTY_OUSTRING);
988 : }
989 : }
990 0 : rUndoStr = OUString();
991 : }
992 : }
993 :
994 0 : nRow = nLastRow; // move to the last filtered row.
995 : }
996 0 : bFound = true;
997 0 : continue;
998 : }
999 :
1000 0 : for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
1001 : {
1002 0 : if (bSkipFiltered)
1003 0 : SkipFilteredRows(nRow, nLastNonFilteredRow, true);
1004 0 : if (nRow > rRange.aEnd.Row())
1005 0 : break;
1006 :
1007 0 : ScRefCellValue aCell = aCol[nCol].GetCellValue(nRow);
1008 0 : if (aCell.isEmpty())
1009 : {
1010 : // empty cell found
1011 0 : rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
1012 0 : bFound = true;
1013 :
1014 0 : if (bReplace)
1015 : {
1016 0 : aCol[nCol].SetRawString(nRow, rSearchItem.GetReplaceString());
1017 0 : if (pUndoDoc)
1018 : {
1019 : // TODO: I'm using a string cell with empty content to
1020 : // trigger deletion of cell instance on undo. Maybe I
1021 : // should create a new cell type for this?
1022 0 : ScSetStringParam aParam;
1023 0 : aParam.setTextInput();
1024 0 : pUndoDoc->SetString(ScAddress(nCol, nRow, nTab), EMPTY_OUSTRING);
1025 : }
1026 : }
1027 : }
1028 0 : }
1029 : }
1030 0 : return bFound;
1031 228 : }
1032 :
1033 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|