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