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