1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/i18n/TransliterationModules.hpp>
22 #include <unotools/textsearch.hxx>
23 #include <svl/srchitem.hxx>
24 #include <editeng/editobj.hxx>
25 #include <osl/diagnose.h>
28 #include "formulacell.hxx"
29 #include "document.hxx"
30 #include "stlpool.hxx"
31 #include "stlsheet.hxx"
32 #include "markdata.hxx"
33 #include "editutil.hxx"
34 #include "detfunc.hxx"
36 #include "stringutil.hxx"
38 using ::com::sun::star::util::SearchOptions
;
42 bool lcl_GetTextWithBreaks( const EditTextObject
& rData
, ScDocument
* pDoc
, OUString
& rVal
)
44 // true = more than 1 paragraph
46 EditEngine
& rEngine
= pDoc
->GetEditEngine();
47 rEngine
.SetText(rData
);
48 rVal
= rEngine
.GetText( LINEEND_LF
);
49 return ( rEngine
.GetParagraphCount() > 1 );
54 bool ScTable::SearchCell(const SvxSearchItem
& rSearchItem
, SCCOL nCol
, SCROW nRow
,
55 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
57 if (!ValidColRow( nCol
, nRow
))
61 bool bDoSearch
= true;
62 bool bDoBack
= rSearchItem
.GetBackward();
66 if (rSearchItem
.GetSelection())
67 bDoSearch
= rMark
.IsCellMarked(nCol
, nRow
);
72 aCell
= aCol
[nCol
].GetCellValue(nRow
);
76 bool bMultiLine
= false;
77 CellType eCellType
= aCell
.meType
;
78 switch (rSearchItem
.GetCellType())
80 case SvxSearchCellType::FORMULA
:
82 if ( eCellType
== CELLTYPE_FORMULA
)
83 aCell
.mpFormula
->GetFormula(aString
, pDocument
->GetGrammar());
84 else if ( eCellType
== CELLTYPE_EDIT
)
85 bMultiLine
= lcl_GetTextWithBreaks(*aCell
.mpEditText
, pDocument
, aString
);
88 aCol
[nCol
].GetInputString( nRow
, aString
);
92 case SvxSearchCellType::VALUE
:
93 if ( eCellType
== CELLTYPE_EDIT
)
94 bMultiLine
= lcl_GetTextWithBreaks(*aCell
.mpEditText
, pDocument
, aString
);
97 aCol
[nCol
].GetInputString( nRow
, aString
);
100 case SvxSearchCellType::NOTE
:
101 break; // don't search this case here
105 sal_Int32 nStart
= 0;
106 sal_Int32 nEnd
= aString
.getLength();
107 ::com::sun::star::util::SearchResult aSearchResult
;
112 sal_Int32 nTemp
=nStart
; nStart
=nEnd
; nEnd
=nTemp
;
113 bFound
= pSearchText
->SearchBackward(aString
, &nStart
, &nEnd
, &aSearchResult
);
114 // change results to definition before 614:
119 bFound
= pSearchText
->SearchForward(aString
, &nStart
, &nEnd
, &aSearchResult
);
120 // change results to definition before 614:
124 if (bFound
&& rSearchItem
.GetWordOnly())
125 bFound
= (nStart
== 0 && nEnd
== aString
.getLength() - 1);
129 OSL_FAIL("pSearchText == NULL");
133 sal_uInt8 cMatrixFlag
= MM_NONE
;
135 ( (rSearchItem
.GetCommand() == SvxSearchCmd::REPLACE
)
136 ||(rSearchItem
.GetCommand() == SvxSearchCmd::REPLACE_ALL
) ) &&
137 // Don't split the matrix, only replace Matrix formulas
138 !( (eCellType
== CELLTYPE_FORMULA
&&
139 ((cMatrixFlag
= aCell
.mpFormula
->GetMatrixFlag()) == MM_REFERENCE
))
140 // No UndoDoc => Matrix not restorable => don't replace
141 || (cMatrixFlag
!= MM_NONE
&& !pUndoDoc
) ) &&
142 IsBlockEditable(nCol
, nRow
, nCol
, nRow
)
145 if ( cMatrixFlag
== MM_NONE
&& rSearchItem
.GetCommand() == SvxSearchCmd::REPLACE
)
149 ScAddress
aAdr( nCol
, nRow
, nTab
);
150 aCell
.commit(*pUndoDoc
, aAdr
);
152 bool bRepeat
= !rSearchItem
.GetWordOnly();
155 // don't continue search if the found text is empty,
156 // otherwise it would never stop (#35410#)
160 OUString sReplStr
= rSearchItem
.GetReplaceString();
161 if (rSearchItem
.GetRegExp())
163 pSearchText
->ReplaceBackReferences( sReplStr
, aString
, aSearchResult
);
164 OUStringBuffer
aStrBuffer(aString
);
165 aStrBuffer
.remove(nStart
, nEnd
-nStart
+1);
166 aStrBuffer
.insert(nStart
, sReplStr
);
167 aString
= aStrBuffer
.makeStringAndClear();
171 OUStringBuffer
aStrBuffer(aString
);
172 aStrBuffer
.remove(nStart
, nEnd
-nStart
+1);
173 aStrBuffer
.insert(nStart
, rSearchItem
.GetReplaceString());
174 aString
= aStrBuffer
.makeStringAndClear();
185 nStart
= nStart
+ sReplStr
.getLength();
186 nEnd
= aString
.getLength();
192 if ( rSearchItem
.GetCommand() != SvxSearchCmd::REPLACE_ALL
|| nStart
>= nEnd
)
196 sal_Int32 nTemp
=nStart
; nStart
=nEnd
; nEnd
=nTemp
;
197 bRepeat
= pSearchText
->SearchBackward(aString
, &nStart
, &nEnd
, &aSearchResult
);
198 // change results to definition before 614:
203 bRepeat
= pSearchText
->SearchForward(aString
, &nStart
, &nEnd
, &aSearchResult
);
204 // change results to definition before 614:
211 if ( cMatrixFlag
!= MM_NONE
)
212 { // don't split Matrix
213 if ( aString
.getLength() > 2 )
214 { // remove {} here so that "{=" can be replaced by "{=..."
215 if ( aString
[ aString
.getLength()-1 ] == '}' )
216 aString
= aString
.copy( 0, aString
.getLength()-1 );
217 if ( aString
[0] == '{' )
218 aString
= aString
.copy( 1 );
220 ScAddress
aAdr( nCol
, nRow
, nTab
);
221 ScFormulaCell
* pFCell
= new ScFormulaCell( pDocument
, aAdr
,
222 aString
, pDocument
->GetGrammar(), cMatrixFlag
);
225 aCell
.mpFormula
->GetMatColsRows(nMatCols
, nMatRows
);
226 pFCell
->SetMatColsRows( nMatCols
, nMatRows
);
227 aCol
[nCol
].SetFormulaCell(nRow
, pFCell
);
229 else if ( bMultiLine
&& aString
.indexOf('\n') != -1 )
231 ScFieldEditEngine
& rEngine
= pDocument
->GetEditEngine();
232 rEngine
.SetText(aString
);
233 SetEditText(nCol
, nRow
, rEngine
.CreateTextObject());
236 aCol
[nCol
].SetString(nRow
, nTab
, aString
, pDocument
->GetAddressConvention());
237 // pCell is invalid now (deleted)
242 void ScTable::SkipFilteredRows(SCROW
& rRow
, SCROW
& rLastNonFilteredRow
, bool bForward
)
248 if (rRow
<= rLastNonFilteredRow
)
251 SCROW nLastRow
= rRow
;
252 if (RowFiltered(rRow
, NULL
, &nLastRow
))
253 // move to the first non-filtered row.
256 // record the last non-filtered row to avoid checking
257 // the filtered state for each and every row.
258 rLastNonFilteredRow
= nLastRow
;
264 if (rRow
>= rLastNonFilteredRow
)
267 SCROW nFirstRow
= rRow
;
268 if (RowFiltered(rRow
, &nFirstRow
, NULL
))
269 // move to the first non-filtered row.
270 rRow
= nFirstRow
- 1;
272 // record the last non-filtered row to avoid checking
273 // the filtered state for each and every row.
274 rLastNonFilteredRow
= nFirstRow
;
278 bool ScTable::Search(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
279 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
283 GetLastDataPos(nLastCol
, nLastRow
);
284 return Search(rSearchItem
, rCol
, rRow
, nLastCol
, nLastRow
, rMark
, rUndoStr
, pUndoDoc
);
287 bool ScTable::Search(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
288 const SCCOL
& nLastCol
, const SCROW
& nLastRow
,
289 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
292 bool bAll
= (rSearchItem
.GetCommand() == SvxSearchCmd::FIND_ALL
)
293 ||(rSearchItem
.GetCommand() == SvxSearchCmd::REPLACE_ALL
);
297 bool bSkipFiltered
= !rSearchItem
.IsSearchFiltered();
298 if (!bAll
&& rSearchItem
.GetBackward())
300 SCROW nLastNonFilteredRow
= MAXROW
+ 1;
301 nCol
= std::min(nCol
, (SCCOL
)(nLastCol
+ 1));
302 nRow
= std::min(nRow
, (SCROW
)(nLastRow
+ 1));
303 if (rSearchItem
.GetRowDirection())
306 while (!bFound
&& ((SCsROW
)nRow
>= 0))
309 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
311 while (!bFound
&& ((SCsCOL
)nCol
>= 0))
313 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
320 if ((SCsCOL
)nCol
>= 0)
321 bIsEmpty
= aCol
[nCol
].IsEmptyData();
325 while (((SCsCOL
)nCol
>= 0) && bIsEmpty
);
338 while (!bFound
&& ((SCsCOL
)nCol
>= 0))
340 while (!bFound
&& ((SCsROW
)nRow
>= 0))
343 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
345 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
348 if (!aCol
[nCol
].GetPrevDataPos(nRow
))
354 // Not found in this column. Move to the next column.
357 nLastNonFilteredRow
= MAXROW
+ 1;
361 if ((SCsCOL
)nCol
>= 0)
362 bIsEmpty
= aCol
[nCol
].IsEmptyData();
366 while (((SCsCOL
)nCol
>= 0) && bIsEmpty
);
373 SCROW nLastNonFilteredRow
= -1;
374 if (!bAll
&& rSearchItem
.GetRowDirection())
377 while (!bFound
&& (nRow
<= nLastRow
))
380 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
382 while (!bFound
&& (nCol
<= nLastCol
))
384 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
388 while ((nCol
<= nLastCol
) && aCol
[nCol
].IsEmptyData()) nCol
++;
401 while (!bFound
&& (nCol
<= nLastCol
))
403 while (!bFound
&& (nRow
<= nLastRow
))
406 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
408 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
411 if (!aCol
[nCol
].GetNextDataPos(nRow
))
417 // Not found in this column. Move to the next column.
419 nLastNonFilteredRow
= -1;
421 while ((nCol
<= nLastCol
) && aCol
[nCol
].IsEmptyData()) nCol
++;
434 bool ScTable::SearchAll(const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
,
435 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
440 bool bEverFound
= false;
444 GetLastDataPos(nLastCol
, nLastRow
);
448 bFound
= Search(rSearchItem
, nCol
, nRow
, nLastCol
, nLastRow
, rMark
, rUndoStr
, pUndoDoc
);
452 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
));
460 void ScTable::UpdateSearchItemAddressForReplace( const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
)
462 if (rSearchItem
.GetBackward())
464 if (rSearchItem
.GetRowDirection())
471 if (rSearchItem
.GetRowDirection())
478 bool ScTable::Replace(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
479 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
484 UpdateSearchItemAddressForReplace( rSearchItem
, nCol
, nRow
);
485 bool bFound
= Search(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
494 bool ScTable::ReplaceAll(
495 const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
, ScRangeList
& rMatchedRanges
,
496 OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
503 GetLastDataPos(nLastCol
, nLastRow
);
505 bool bEverFound
= false;
508 bool bFound
= Search(rSearchItem
, nCol
, nRow
, nLastCol
, nLastRow
, rMark
, rUndoStr
, pUndoDoc
);
513 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
));
521 bool ScTable::SearchStyle(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
522 const ScMarkData
& rMark
)
524 const ScStyleSheet
* pSearchStyle
= static_cast<const ScStyleSheet
*>(
525 pDocument
->GetStyleSheetPool()->Find(
526 rSearchItem
.GetSearchString(), SFX_STYLE_FAMILY_PARA
));
532 bool bSelect
= rSearchItem
.GetSelection();
533 bool bRows
= rSearchItem
.GetRowDirection();
534 bool bBack
= rSearchItem
.GetBackward();
535 short nAdd
= bBack
? -1 : 1;
541 SAL_WARN( "sc.core", "SearchStyle: bad column " << nCol
);
547 SCsROW nNextRow
= aCol
[nCol
].SearchStyle( nRow
, pSearchStyle
, bBack
, bSelect
, rMark
);
548 if (!ValidRow(nNextRow
))
550 nRow
= bBack
? MAXROW
: 0;
551 nCol
= sal::static_int_cast
<SCsCOL
>( nCol
+ nAdd
);
559 while (!bFound
&& ValidCol(nCol
));
563 SCsROW nNextRows
[MAXCOLCOUNT
];
565 for (i
=0; i
<=MAXCOL
; i
++)
568 if (bBack
) { if (i
>=nCol
) --nSRow
; }
569 else { if (i
<=nCol
) ++nSRow
; }
570 nNextRows
[i
] = aCol
[i
].SearchStyle( nSRow
, pSearchStyle
, bBack
, bSelect
, rMark
);
572 if (bBack
) // backwards
575 for (i
=MAXCOL
; i
>=0; i
--)
576 if (nNextRows
[i
]>nRow
)
586 for (i
=0; i
<=MAXCOL
; i
++)
587 if (nNextRows
[i
]<nRow
)
604 //TODO: return single Pattern for Undo
606 bool ScTable::ReplaceStyle(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
607 const ScMarkData
& rMark
, bool bIsUndo
)
613 bRet
= SearchStyle(rSearchItem
, rCol
, rRow
, rMark
);
616 const ScStyleSheet
* pReplaceStyle
= static_cast<const ScStyleSheet
*>(
617 pDocument
->GetStyleSheetPool()->Find(
618 rSearchItem
.GetReplaceString(), SFX_STYLE_FAMILY_PARA
));
621 ApplyStyle( rCol
, rRow
, *pReplaceStyle
);
624 OSL_FAIL("pReplaceStyle==0");
631 bool ScTable::SearchAllStyle(
632 const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
, ScRangeList
& rMatchedRanges
)
634 const ScStyleSheet
* pSearchStyle
= static_cast<const ScStyleSheet
*>(
635 pDocument
->GetStyleSheetPool()->Find(
636 rSearchItem
.GetSearchString(), SFX_STYLE_FAMILY_PARA
));
637 bool bSelect
= rSearchItem
.GetSelection();
638 bool bBack
= rSearchItem
.GetBackward();
639 bool bEverFound
= false;
641 for (SCCOL i
=0; i
<=MAXCOL
; i
++)
646 while (bFound
&& nRow
<= MAXROW
)
648 bFound
= aCol
[i
].SearchStyleRange( nRow
, nEndRow
, pSearchStyle
, bBack
, bSelect
, rMark
);
657 rMatchedRanges
.Join(ScRange(i
, nRow
, nTab
, i
, nEndRow
, nTab
));
667 bool ScTable::ReplaceAllStyle(
668 const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
, ScRangeList
& rMatchedRanges
,
669 ScDocument
* pUndoDoc
)
671 bool bRet
= SearchAllStyle(rSearchItem
, rMark
, rMatchedRanges
);
674 const ScStyleSheet
* pReplaceStyle
= static_cast<const ScStyleSheet
*>(
675 pDocument
->GetStyleSheetPool()->Find(
676 rSearchItem
.GetReplaceString(), SFX_STYLE_FAMILY_PARA
));
681 pDocument
->CopyToDocument( 0,0,nTab
, MAXCOL
,MAXROW
,nTab
,
682 IDF_ATTRIB
, true, pUndoDoc
, &rMark
);
683 ApplySelectionStyle( *pReplaceStyle
, rMark
);
687 OSL_FAIL("pReplaceStyle==0");
694 bool ScTable::SearchAndReplace(
695 const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
, const ScMarkData
& rMark
,
696 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
698 SvxSearchCmd nCommand
= rSearchItem
.GetCommand();
700 if ( ValidColRow(rCol
, rRow
) ||
701 ((nCommand
== SvxSearchCmd::FIND
|| nCommand
== SvxSearchCmd::REPLACE
) &&
702 (((rCol
== MAXCOLCOUNT
|| rCol
== -1) && ValidRow(rRow
)) ||
703 ((rRow
== MAXROWCOUNT
|| rRow
== -1) && ValidCol(rCol
))
708 bool bStyles
= rSearchItem
.GetPattern();
711 if (nCommand
== SvxSearchCmd::FIND
)
712 bFound
= SearchStyle(rSearchItem
, rCol
, rRow
, rMark
);
713 else if (nCommand
== SvxSearchCmd::REPLACE
)
714 bFound
= ReplaceStyle(rSearchItem
, rCol
, rRow
, rMark
, false);
715 else if (nCommand
== SvxSearchCmd::FIND_ALL
)
716 bFound
= SearchAllStyle(rSearchItem
, rMark
, rMatchedRanges
);
717 else if (nCommand
== SvxSearchCmd::REPLACE_ALL
)
718 bFound
= ReplaceAllStyle(rSearchItem
, rMark
, rMatchedRanges
, pUndoDoc
);
722 // SearchParam no longer needed - SearchOptions contains all settings
723 com::sun::star::util::SearchOptions aSearchOptions
= rSearchItem
.GetSearchOptions();
724 aSearchOptions
.Locale
= *ScGlobal::GetLocale();
726 if (aSearchOptions
.searchString
.isEmpty())
728 // Search for empty cells.
729 return SearchAndReplaceEmptyCells(rSearchItem
, rCol
, rRow
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
);
732 // reflect UseAsianOptions flag in SearchOptions
733 // (use only ignore case and width if asian options are disabled).
734 // This is also done in SvxSearchDialog CommandHdl, but not in API object.
735 if ( !rSearchItem
.IsUseAsianOptions() )
736 aSearchOptions
.transliterateFlags
&=
737 ( com::sun::star::i18n::TransliterationModules_IGNORE_CASE
|
738 com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH
);
740 pSearchText
= new utl::TextSearch( aSearchOptions
);
742 if (nCommand
== SvxSearchCmd::FIND
)
743 bFound
= Search(rSearchItem
, rCol
, rRow
, rMark
, rUndoStr
, pUndoDoc
);
744 else if (nCommand
== SvxSearchCmd::FIND_ALL
)
745 bFound
= SearchAll(rSearchItem
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
);
746 else if (nCommand
== SvxSearchCmd::REPLACE
)
747 bFound
= Replace(rSearchItem
, rCol
, rRow
, rMark
, rUndoStr
, pUndoDoc
);
748 else if (nCommand
== SvxSearchCmd::REPLACE_ALL
)
749 bFound
= ReplaceAll(rSearchItem
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
);
758 bool ScTable::SearchAndReplaceEmptyCells(
759 const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
, const ScMarkData
& rMark
,
760 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
762 SCCOL nColStart
, nColEnd
;
763 SCROW nRowStart
, nRowEnd
;
764 GetFirstDataPos(nColStart
, nRowStart
);
765 GetLastDataPos(nColEnd
, nRowEnd
);
768 aRanges
.Append(ScRange(nColStart
, nRowStart
, nTab
, nColEnd
, nRowEnd
, nTab
));
770 if (rSearchItem
.GetSelection())
772 // current selection only.
773 if (!rMark
.IsMarked() && !rMark
.IsMultiMarked())
774 // There is no selection. Bail out.
777 ScRangeList aMarkedRanges
, aNewRanges
;
778 rMark
.FillRangeListWithMarks(&aMarkedRanges
, true);
779 for ( size_t i
= 0, n
= aMarkedRanges
.size(); i
< n
; ++i
)
781 ScRange
* p
= aMarkedRanges
[ i
];
782 if (p
->aStart
.Col() > nColEnd
|| p
->aStart
.Row() > nRowEnd
)
783 // This range is outside the data area. Skip it.
786 // Shrink the range into data area only.
787 if (p
->aStart
.Col() < nColStart
)
788 p
->aStart
.SetCol(rCol
);
789 if (p
->aStart
.Row() < nRowStart
)
790 p
->aStart
.SetRow(rRow
);
792 if (p
->aEnd
.Col() > nColEnd
)
793 p
->aEnd
.SetCol(nColEnd
);
794 if (p
->aEnd
.Row() > nRowEnd
)
795 p
->aEnd
.SetRow(nRowEnd
);
797 aNewRanges
.Append(*p
);
799 aRanges
= aNewRanges
;
802 SvxSearchCmd nCommand
= rSearchItem
.GetCommand();
803 if (nCommand
== SvxSearchCmd::FIND
|| nCommand
== SvxSearchCmd::REPLACE
)
805 if (rSearchItem
.GetBackward())
807 for ( size_t i
= aRanges
.size(); i
> 0; --i
)
809 ScRange
* p
= aRanges
[ i
- 1 ];
810 if (SearchRangeForEmptyCell(*p
, rSearchItem
, rCol
, rRow
, rUndoStr
))
816 for ( size_t i
= 0, nListSize
= aRanges
.size(); i
< nListSize
; ++i
)
818 ScRange
* p
= aRanges
[ i
];
819 if (SearchRangeForEmptyCell(*p
, rSearchItem
, rCol
, rRow
, rUndoStr
))
824 else if (nCommand
== SvxSearchCmd::FIND_ALL
|| nCommand
== SvxSearchCmd::REPLACE_ALL
)
827 for ( size_t i
= 0, nListSize
= aRanges
.size(); i
< nListSize
; ++i
)
829 ScRange
* p
= aRanges
[ i
];
830 bFound
|= SearchRangeForAllEmptyCells(*p
, rSearchItem
, rMatchedRanges
, rUndoStr
, pUndoDoc
);
839 bool lcl_maybeReplaceCellString(
840 ScColumn
& rColObj
, SCCOL
& rCol
, SCROW
& rRow
, OUString
& rUndoStr
, SCCOL nCol
, SCROW nRow
, const SvxSearchItem
& rSearchItem
)
842 ScRefCellValue aCell
= rColObj
.GetCellValue(nRow
);
848 if (rSearchItem
.GetCommand() == SvxSearchCmd::REPLACE
&&
849 !rSearchItem
.GetReplaceString().isEmpty())
851 rColObj
.SetRawString(nRow
, rSearchItem
.GetReplaceString());
861 bool ScTable::SearchRangeForEmptyCell(
862 const ScRange
& rRange
, const SvxSearchItem
& rSearchItem
,
863 SCCOL
& rCol
, SCROW
& rRow
, OUString
& rUndoStr
)
865 SvxSearchCmd nCmd
= rSearchItem
.GetCommand();
866 bool bSkipFiltered
= rSearchItem
.IsSearchFiltered();
867 if (rSearchItem
.GetBackward())
870 if (rSearchItem
.GetRowDirection())
873 SCROW nLastNonFilteredRow
= MAXROW
+ 1;
874 SCROW nBeginRow
= rRange
.aEnd
.Row() > rRow
? rRow
: rRange
.aEnd
.Row();
875 for (SCROW nRow
= nBeginRow
; nRow
>= rRange
.aStart
.Row(); --nRow
)
878 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
879 if (nRow
< rRange
.aStart
.Row())
882 SCCOL nBeginCol
= rRange
.aEnd
.Col();
883 if (nRow
== rRow
&& nBeginCol
>= rCol
)
884 // always start from one cell before the cursor.
885 nBeginCol
= rCol
- (nCmd
== SvxSearchCmd::FIND
? 1 : 0);
887 for (SCCOL nCol
= nBeginCol
; nCol
>= rRange
.aStart
.Col(); --nCol
)
889 if (lcl_maybeReplaceCellString(aCol
[nCol
], rCol
, rRow
, rUndoStr
, nCol
, nRow
, rSearchItem
))
897 SCCOL nBeginCol
= rRange
.aEnd
.Col() > rCol
? rCol
: rRange
.aEnd
.Col();
898 for (SCCOL nCol
= nBeginCol
; nCol
>= rRange
.aStart
.Col(); --nCol
)
900 SCROW nLastNonFilteredRow
= MAXROW
+ 1;
901 SCROW nBeginRow
= rRange
.aEnd
.Row();
902 if (nCol
== rCol
&& nBeginRow
>= rRow
)
903 // always start from one cell before the cursor.
904 nBeginRow
= rRow
- (nCmd
== SvxSearchCmd::FIND
? 1 : 0);
905 for (SCROW nRow
= nBeginRow
; nRow
>= rRange
.aStart
.Row(); --nRow
)
908 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
909 if (nRow
< rRange
.aStart
.Row())
912 if (lcl_maybeReplaceCellString(aCol
[nCol
], rCol
, rRow
, rUndoStr
, nCol
, nRow
, rSearchItem
))
921 if (rSearchItem
.GetRowDirection())
924 SCROW nLastNonFilteredRow
= -1;
925 SCROW nBeginRow
= rRange
.aStart
.Row() < rRow
? rRow
: rRange
.aStart
.Row();
926 for (SCROW nRow
= nBeginRow
; nRow
<= rRange
.aEnd
.Row(); ++nRow
)
929 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
930 if (nRow
> rRange
.aEnd
.Row())
933 SCCOL nBeginCol
= rRange
.aStart
.Col();
934 if (nRow
== rRow
&& nBeginCol
<= rCol
)
935 // always start from one cell past the cursor.
936 nBeginCol
= rCol
+ (nCmd
== SvxSearchCmd::FIND
? 1 : 0);
937 for (SCCOL nCol
= nBeginCol
; nCol
<= rRange
.aEnd
.Col(); ++nCol
)
939 if (lcl_maybeReplaceCellString(aCol
[nCol
], rCol
, rRow
, rUndoStr
, nCol
, nRow
, rSearchItem
))
947 SCCOL nBeginCol
= rRange
.aStart
.Col() < rCol
? rCol
: rRange
.aStart
.Col();
948 for (SCCOL nCol
= nBeginCol
; nCol
<= rRange
.aEnd
.Col(); ++nCol
)
950 SCROW nLastNonFilteredRow
= -1;
951 SCROW nBeginRow
= rRange
.aStart
.Row();
952 if (nCol
== rCol
&& nBeginRow
<= rRow
)
953 // always start from one cell past the cursor.
954 nBeginRow
= rRow
+ (nCmd
== SvxSearchCmd::FIND
? 1 : 0);
955 for (SCROW nRow
= nBeginRow
; nRow
<= rRange
.aEnd
.Row(); ++nRow
)
958 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
959 if (nRow
> rRange
.aEnd
.Row())
962 if (lcl_maybeReplaceCellString(aCol
[nCol
], rCol
, rRow
, rUndoStr
, nCol
, nRow
, rSearchItem
))
971 bool ScTable::SearchRangeForAllEmptyCells(
972 const ScRange
& rRange
, const SvxSearchItem
& rSearchItem
,
973 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
976 bool bReplace
= (rSearchItem
.GetCommand() == SvxSearchCmd::REPLACE_ALL
) &&
977 !rSearchItem
.GetReplaceString().isEmpty();
978 bool bSkipFiltered
= rSearchItem
.IsSearchFiltered();
980 for (SCCOL nCol
= rRange
.aStart
.Col(); nCol
<= rRange
.aEnd
.Col(); ++nCol
)
982 SCROW nLastNonFilteredRow
= -1;
983 if (aCol
[nCol
].IsEmptyData())
985 // The entire column is empty.
986 for (SCROW nRow
= rRange
.aStart
.Row(); nRow
<= rRange
.aEnd
.Row(); ++nRow
)
989 if (!RowFiltered(nRow
, NULL
, &nLastRow
))
991 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
, nCol
, nLastRow
, nTab
));
994 const OUString
& rNewStr
= rSearchItem
.GetReplaceString();
995 for (SCROW i
= nRow
; i
<= nLastRow
; ++i
)
997 aCol
[nCol
].SetRawString(i
, rNewStr
);
1000 // TODO: I'm using a string cell with empty content to
1001 // trigger deletion of cell instance on undo. Maybe I
1002 // should create a new cell type for this?
1003 ScSetStringParam aParam
;
1004 aParam
.setTextInput();
1005 pUndoDoc
->SetString(ScAddress(nCol
, i
, nTab
), EMPTY_OUSTRING
);
1012 nRow
= nLastRow
; // move to the last filtered row.
1018 for (SCROW nRow
= rRange
.aStart
.Row(); nRow
<= rRange
.aEnd
.Row(); ++nRow
)
1021 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
1022 if (nRow
> rRange
.aEnd
.Row())
1025 ScRefCellValue aCell
= aCol
[nCol
].GetCellValue(nRow
);
1026 if (aCell
.isEmpty())
1029 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
));
1034 aCol
[nCol
].SetRawString(nRow
, rSearchItem
.GetReplaceString());
1037 // TODO: I'm using a string cell with empty content to
1038 // trigger deletion of cell instance on undo. Maybe I
1039 // should create a new cell type for this?
1040 ScSetStringParam aParam
;
1041 aParam
.setTextInput();
1042 pUndoDoc
->SetString(ScAddress(nCol
, nRow
, nTab
), EMPTY_OUSTRING
);
1051 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */