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>
27 #include "formulacell.hxx"
28 #include "document.hxx"
29 #include "stlpool.hxx"
30 #include "markdata.hxx"
31 #include "editutil.hxx"
32 #include "detfunc.hxx"
34 #include "stringutil.hxx"
36 //--------------------------------------------------------------------------
39 using ::com::sun::star::util::SearchOptions
;
43 bool lcl_GetTextWithBreaks( const EditTextObject
& rData
, ScDocument
* pDoc
, OUString
& rVal
)
45 // true = more than 1 paragraph
47 EditEngine
& rEngine
= pDoc
->GetEditEngine();
48 rEngine
.SetText(rData
);
49 rVal
= rEngine
.GetText( LINEEND_LF
);
50 return ( rEngine
.GetParagraphCount() > 1 );
55 bool ScTable::SearchCell(const SvxSearchItem
& rSearchItem
, SCCOL nCol
, SCROW nRow
,
56 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
59 bool bDoSearch
= true;
60 bool bDoBack
= rSearchItem
.GetBackward();
64 if (rSearchItem
.GetSelection())
65 bDoSearch
= rMark
.IsCellMarked(nCol
, nRow
);
70 aCell
= aCol
[nCol
].GetCellValue(nRow
);
74 bool bMultiLine
= false;
75 CellType eCellType
= aCell
.meType
;
76 switch (rSearchItem
.GetCellType())
78 case SVX_SEARCHIN_FORMULA
:
80 if ( eCellType
== CELLTYPE_FORMULA
)
81 aCell
.mpFormula
->GetFormula(aString
, pDocument
->GetGrammar());
82 else if ( eCellType
== CELLTYPE_EDIT
)
83 bMultiLine
= lcl_GetTextWithBreaks(*aCell
.mpEditText
, pDocument
, aString
);
86 aCol
[nCol
].GetInputString( nRow
, aString
);
90 case SVX_SEARCHIN_VALUE
:
91 if ( eCellType
== CELLTYPE_EDIT
)
92 bMultiLine
= lcl_GetTextWithBreaks(*aCell
.mpEditText
, pDocument
, aString
);
95 aCol
[nCol
].GetInputString( nRow
, aString
);
98 case SVX_SEARCHIN_NOTE
:
99 break; // don't search this case here
103 sal_Int32 nStart
= 0;
104 sal_Int32 nEnd
= aString
.getLength();
105 ::com::sun::star::util::SearchResult aSearchResult
;
110 sal_Int32 nTemp
=nStart
; nStart
=nEnd
; nEnd
=nTemp
;
111 bFound
= pSearchText
->SearchBackward(aString
, &nStart
, &nEnd
, &aSearchResult
);
112 // change results to definition before 614:
117 bFound
= pSearchText
->SearchForward(aString
, &nStart
, &nEnd
, &aSearchResult
);
118 // change results to definition before 614:
122 if (bFound
&& rSearchItem
.GetWordOnly())
123 bFound
= (nStart
== 0 && nEnd
== aString
.getLength() - 1);
127 OSL_FAIL("pSearchText == NULL");
131 sal_uInt8 cMatrixFlag
= MM_NONE
;
133 ( (rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE
)
134 ||(rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL
) ) &&
135 // Matrix nicht zerreissen, nur Matrixformel ersetzen
136 !( (eCellType
== CELLTYPE_FORMULA
&&
137 ((cMatrixFlag
= aCell
.mpFormula
->GetMatrixFlag()) == MM_REFERENCE
))
138 // kein UndoDoc => Matrix nicht wiederherstellbar => nicht ersetzen
139 || (cMatrixFlag
!= MM_NONE
&& !pUndoDoc
) ) &&
140 IsBlockEditable(nCol
, nRow
, nCol
, nRow
)
143 if ( cMatrixFlag
== MM_NONE
&& rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE
)
147 ScAddress
aAdr( nCol
, nRow
, nTab
);
148 aCell
.commit(*pUndoDoc
, aAdr
);
150 bool bRepeat
= !rSearchItem
.GetWordOnly();
153 // wenn der gefundene Text leer ist, nicht weitersuchen,
154 // sonst wuerde man nie mehr aufhoeren (#35410#)
158 OUString sReplStr
= rSearchItem
.GetReplaceString();
159 if (rSearchItem
.GetRegExp())
161 pSearchText
->ReplaceBackReferences( sReplStr
, aString
, aSearchResult
);
162 OUStringBuffer
aStrBuffer(aString
);
163 aStrBuffer
.remove(nStart
, nEnd
-nStart
+1);
164 aStrBuffer
.insert(nStart
, sReplStr
);
165 aString
= aStrBuffer
.makeStringAndClear();
169 OUStringBuffer
aStrBuffer(aString
);
170 aStrBuffer
.remove(nStart
, nEnd
-nStart
+1);
171 aStrBuffer
.insert(nStart
, rSearchItem
.GetReplaceString());
172 aString
= aStrBuffer
.makeStringAndClear();
183 nStart
= nStart
+ sReplStr
.getLength();
184 nEnd
= aString
.getLength();
190 if ( rSearchItem
.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL
|| nStart
>= nEnd
)
194 sal_Int32 nTemp
=nStart
; nStart
=nEnd
; nEnd
=nTemp
;
195 bRepeat
= pSearchText
->SearchBackward(aString
, &nStart
, &nEnd
, &aSearchResult
);
196 // change results to definition before 614:
201 bRepeat
= pSearchText
->SearchForward(aString
, &nStart
, &nEnd
, &aSearchResult
);
202 // change results to definition before 614:
209 if ( cMatrixFlag
!= MM_NONE
)
210 { // Matrix nicht zerreissen
211 if ( aString
.getLength() > 2 )
212 { // {} raus, erst hier damit auch "{=" durch "{=..." ersetzt werden kann
213 if ( aString
[ aString
.getLength()-1 ] == '}' )
214 aString
= aString
.copy( 0, aString
.getLength()-1 );
215 if ( aString
[0] == '{' )
216 aString
= aString
.copy( 1 );
218 ScAddress
aAdr( nCol
, nRow
, nTab
);
219 ScFormulaCell
* pFCell
= new ScFormulaCell( pDocument
, aAdr
,
220 aString
, pDocument
->GetGrammar(), cMatrixFlag
);
223 aCell
.mpFormula
->GetMatColsRows(nMatCols
, nMatRows
);
224 pFCell
->SetMatColsRows( nMatCols
, nMatRows
);
225 aCol
[nCol
].SetFormulaCell(nRow
, pFCell
);
227 else if ( bMultiLine
&& aString
.indexOf('\n') != -1 )
229 ScFieldEditEngine
& rEngine
= pDocument
->GetEditEngine();
230 rEngine
.SetText(aString
);
231 SetEditText(nCol
, nRow
, rEngine
.CreateTextObject());
234 aCol
[nCol
].SetString(nRow
, nTab
, aString
, pDocument
->GetAddressConvention());
235 // pCell is invalid now (deleted)
240 void ScTable::SkipFilteredRows(SCROW
& rRow
, SCROW
& rLastNonFilteredRow
, bool bForward
)
246 if (rRow
<= rLastNonFilteredRow
)
249 SCROW nLastRow
= rRow
;
250 if (RowFiltered(rRow
, NULL
, &nLastRow
))
251 // move to the first non-filtered row.
254 // record the last non-filtered row to avoid checking
255 // the filtered state for each and every row.
256 rLastNonFilteredRow
= nLastRow
;
262 if (rRow
>= rLastNonFilteredRow
)
265 SCROW nFirstRow
= rRow
;
266 if (RowFiltered(rRow
, &nFirstRow
, NULL
))
267 // move to the first non-filtered row.
268 rRow
= nFirstRow
- 1;
270 // record the last non-filtered row to avoid checking
271 // the filtered state for each and every row.
272 rLastNonFilteredRow
= nFirstRow
;
276 bool ScTable::Search(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
277 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
280 bool bAll
= (rSearchItem
.GetCommand() == SVX_SEARCHCMD_FIND_ALL
)
281 ||(rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL
);
286 GetLastDataPos(nLastCol
, nLastRow
);
287 bool bSkipFiltered
= !rSearchItem
.IsSearchFiltered();
288 if (!bAll
&& rSearchItem
.GetBackward())
290 SCROW nLastNonFilteredRow
= MAXROW
+ 1;
291 nCol
= std::min(nCol
, (SCCOL
)(nLastCol
+ 1));
292 nRow
= std::min(nRow
, (SCROW
)(nLastRow
+ 1));
293 if (rSearchItem
.GetRowDirection())
296 while (!bFound
&& ((SCsROW
)nRow
>= 0))
299 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
301 while (!bFound
&& ((SCsCOL
)nCol
>= 0))
303 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
310 if ((SCsCOL
)nCol
>= 0)
311 bIsEmpty
= aCol
[nCol
].IsEmptyData();
315 while (((SCsCOL
)nCol
>= 0) && bIsEmpty
);
328 while (!bFound
&& ((SCsCOL
)nCol
>= 0))
330 while (!bFound
&& ((SCsROW
)nRow
>= 0))
333 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
335 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
338 if (!aCol
[nCol
].GetPrevDataPos(nRow
))
344 // Not found in this column. Move to the next column.
347 nLastNonFilteredRow
= MAXROW
+ 1;
351 if ((SCsCOL
)nCol
>= 0)
352 bIsEmpty
= aCol
[nCol
].IsEmptyData();
356 while (((SCsCOL
)nCol
>= 0) && bIsEmpty
);
363 SCROW nLastNonFilteredRow
= -1;
364 if (!bAll
&& rSearchItem
.GetRowDirection())
367 while (!bFound
&& (nRow
<= nLastRow
))
370 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
372 while (!bFound
&& (nCol
<= nLastCol
))
374 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
378 while ((nCol
<= nLastCol
) && aCol
[nCol
].IsEmptyData()) nCol
++;
391 while (!bFound
&& (nCol
<= nLastCol
))
393 while (!bFound
&& (nRow
<= nLastRow
))
396 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
398 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
401 if (!aCol
[nCol
].GetNextDataPos(nRow
))
407 // Not found in this column. Move to the next column.
409 nLastNonFilteredRow
= -1;
411 while ((nCol
<= nLastCol
) && aCol
[nCol
].IsEmptyData()) nCol
++;
424 bool ScTable::SearchAll(const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
,
425 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
430 bool bEverFound
= false;
434 bFound
= Search(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
438 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
));
446 void ScTable::UpdateSearchItemAddressForReplace( const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
)
448 if (rSearchItem
.GetBackward())
450 if (rSearchItem
.GetRowDirection())
457 if (rSearchItem
.GetRowDirection())
464 bool ScTable::Replace(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
465 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
470 UpdateSearchItemAddressForReplace( rSearchItem
, nCol
, nRow
);
471 bool bFound
= Search(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
480 bool ScTable::ReplaceAll(
481 const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
, ScRangeList
& rMatchedRanges
,
482 OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
487 bool bEverFound
= false;
490 bool bFound
= Search(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
495 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
));
503 bool ScTable::SearchStyle(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
504 const ScMarkData
& rMark
)
506 const ScStyleSheet
* pSearchStyle
= (const ScStyleSheet
*)
507 pDocument
->GetStyleSheetPool()->Find(
508 rSearchItem
.GetSearchString(), SFX_STYLE_FAMILY_PARA
);
514 bool bSelect
= rSearchItem
.GetSelection();
515 bool bRows
= rSearchItem
.GetRowDirection();
516 bool bBack
= rSearchItem
.GetBackward();
517 short nAdd
= bBack
? -1 : 1;
519 if (bRows
) // zeilenweise
524 SCsROW nNextRow
= aCol
[nCol
].SearchStyle( nRow
, pSearchStyle
, bBack
, bSelect
, rMark
);
525 if (!ValidRow(nNextRow
))
527 nRow
= bBack
? MAXROW
: 0;
528 nCol
= sal::static_int_cast
<SCsCOL
>( nCol
+ nAdd
);
536 while (!bFound
&& ValidCol(nCol
));
540 SCsROW nNextRows
[MAXCOLCOUNT
];
542 for (i
=0; i
<=MAXCOL
; i
++)
545 if (bBack
) { if (i
>=nCol
) --nSRow
; }
546 else { if (i
<=nCol
) ++nSRow
; }
547 nNextRows
[i
] = aCol
[i
].SearchStyle( nSRow
, pSearchStyle
, bBack
, bSelect
, rMark
);
549 if (bBack
) // rueckwaerts
552 for (i
=MAXCOL
; i
>=0; i
--)
553 if (nNextRows
[i
]>nRow
)
563 for (i
=0; i
<=MAXCOL
; i
++)
564 if (nNextRows
[i
]<nRow
)
581 //! einzelnes Pattern fuer Undo zurueckgeben
583 bool ScTable::ReplaceStyle(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
584 const ScMarkData
& rMark
, bool bIsUndo
)
590 bRet
= SearchStyle(rSearchItem
, rCol
, rRow
, rMark
);
593 const ScStyleSheet
* pReplaceStyle
= (const ScStyleSheet
*)
594 pDocument
->GetStyleSheetPool()->Find(
595 rSearchItem
.GetReplaceString(), SFX_STYLE_FAMILY_PARA
);
598 ApplyStyle( rCol
, rRow
, *pReplaceStyle
);
601 OSL_FAIL("pReplaceStyle==0");
608 bool ScTable::SearchAllStyle(
609 const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
, ScRangeList
& rMatchedRanges
)
611 const ScStyleSheet
* pSearchStyle
= (const ScStyleSheet
*)
612 pDocument
->GetStyleSheetPool()->Find(
613 rSearchItem
.GetSearchString(), SFX_STYLE_FAMILY_PARA
);
614 bool bSelect
= rSearchItem
.GetSelection();
615 bool bBack
= rSearchItem
.GetBackward();
616 bool bEverFound
= false;
618 for (SCCOL i
=0; i
<=MAXCOL
; i
++)
623 while (bFound
&& nRow
<= MAXROW
)
625 bFound
= aCol
[i
].SearchStyleRange( nRow
, nEndRow
, pSearchStyle
, bBack
, bSelect
, rMark
);
634 rMatchedRanges
.Join(ScRange(i
, nRow
, nTab
, i
, nEndRow
, nTab
));
644 bool ScTable::ReplaceAllStyle(
645 const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
, ScRangeList
& rMatchedRanges
,
646 ScDocument
* pUndoDoc
)
648 bool bRet
= SearchAllStyle(rSearchItem
, rMark
, rMatchedRanges
);
651 const ScStyleSheet
* pReplaceStyle
= (const ScStyleSheet
*)
652 pDocument
->GetStyleSheetPool()->Find(
653 rSearchItem
.GetReplaceString(), SFX_STYLE_FAMILY_PARA
);
658 pDocument
->CopyToDocument( 0,0,nTab
, MAXCOL
,MAXROW
,nTab
,
659 IDF_ATTRIB
, true, pUndoDoc
, &rMark
);
660 ApplySelectionStyle( *pReplaceStyle
, rMark
);
664 OSL_FAIL("pReplaceStyle==0");
671 bool ScTable::SearchAndReplace(
672 const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
, const ScMarkData
& rMark
,
673 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
675 sal_uInt16 nCommand
= rSearchItem
.GetCommand();
677 if ( ValidColRow(rCol
, rRow
) ||
678 ((nCommand
== SVX_SEARCHCMD_FIND
|| nCommand
== SVX_SEARCHCMD_REPLACE
) &&
679 (((rCol
== MAXCOLCOUNT
|| rCol
== -1) && ValidRow(rRow
)) ||
680 ((rRow
== MAXROWCOUNT
|| rRow
== -1) && ValidCol(rCol
))
685 bool bStyles
= rSearchItem
.GetPattern();
688 if (nCommand
== SVX_SEARCHCMD_FIND
)
689 bFound
= SearchStyle(rSearchItem
, rCol
, rRow
, rMark
);
690 else if (nCommand
== SVX_SEARCHCMD_REPLACE
)
691 bFound
= ReplaceStyle(rSearchItem
, rCol
, rRow
, rMark
, false);
692 else if (nCommand
== SVX_SEARCHCMD_FIND_ALL
)
693 bFound
= SearchAllStyle(rSearchItem
, rMark
, rMatchedRanges
);
694 else if (nCommand
== SVX_SEARCHCMD_REPLACE_ALL
)
695 bFound
= ReplaceAllStyle(rSearchItem
, rMark
, rMatchedRanges
, pUndoDoc
);
699 // SearchParam no longer needed - SearchOptions contains all settings
700 com::sun::star::util::SearchOptions aSearchOptions
= rSearchItem
.GetSearchOptions();
701 aSearchOptions
.Locale
= *ScGlobal::GetLocale();
703 if (aSearchOptions
.searchString
.isEmpty())
705 // Search for empty cells.
706 return SearchAndReplaceEmptyCells(rSearchItem
, rCol
, rRow
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
);
709 // reflect UseAsianOptions flag in SearchOptions
710 // (use only ignore case and width if asian options are disabled).
711 // This is also done in SvxSearchDialog CommandHdl, but not in API object.
712 if ( !rSearchItem
.IsUseAsianOptions() )
713 aSearchOptions
.transliterateFlags
&=
714 ( com::sun::star::i18n::TransliterationModules_IGNORE_CASE
|
715 com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH
);
717 pSearchText
= new utl::TextSearch( aSearchOptions
);
719 if (nCommand
== SVX_SEARCHCMD_FIND
)
720 bFound
= Search(rSearchItem
, rCol
, rRow
, rMark
, rUndoStr
, pUndoDoc
);
721 else if (nCommand
== SVX_SEARCHCMD_FIND_ALL
)
722 bFound
= SearchAll(rSearchItem
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
);
723 else if (nCommand
== SVX_SEARCHCMD_REPLACE
)
724 bFound
= Replace(rSearchItem
, rCol
, rRow
, rMark
, rUndoStr
, pUndoDoc
);
725 else if (nCommand
== SVX_SEARCHCMD_REPLACE_ALL
)
726 bFound
= ReplaceAll(rSearchItem
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
);
735 bool ScTable::SearchAndReplaceEmptyCells(
736 const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
, const ScMarkData
& rMark
,
737 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
739 SCCOL nColStart
, nColEnd
;
740 SCROW nRowStart
, nRowEnd
;
741 GetFirstDataPos(nColStart
, nRowStart
);
742 GetLastDataPos(nColEnd
, nRowEnd
);
745 aRanges
.Append(ScRange(nColStart
, nRowStart
, nTab
, nColEnd
, nRowEnd
, nTab
));
747 if (rSearchItem
.GetSelection())
749 // current selection only.
750 if (!rMark
.IsMarked() && !rMark
.IsMultiMarked())
751 // There is no selection. Bail out.
754 ScRangeList aMarkedRanges
, aNewRanges
;
755 rMark
.FillRangeListWithMarks(&aMarkedRanges
, true);
756 for ( size_t i
= 0, n
= aMarkedRanges
.size(); i
< n
; ++i
)
758 ScRange
* p
= aMarkedRanges
[ i
];
759 if (p
->aStart
.Col() > nColEnd
|| p
->aStart
.Row() > nRowEnd
)
760 // This range is outside the data area. Skip it.
763 // Shrink the range into data area only.
764 if (p
->aStart
.Col() < nColStart
)
765 p
->aStart
.SetCol(rCol
);
766 if (p
->aStart
.Row() < nRowStart
)
767 p
->aStart
.SetRow(rRow
);
769 if (p
->aEnd
.Col() > nColEnd
)
770 p
->aEnd
.SetCol(nColEnd
);
771 if (p
->aEnd
.Row() > nRowEnd
)
772 p
->aEnd
.SetRow(nRowEnd
);
774 aNewRanges
.Append(*p
);
776 aRanges
= aNewRanges
;
779 sal_uInt16 nCommand
= rSearchItem
.GetCommand();
780 if (nCommand
== SVX_SEARCHCMD_FIND
|| nCommand
== SVX_SEARCHCMD_REPLACE
)
782 if (rSearchItem
.GetBackward())
784 for ( size_t i
= aRanges
.size(); i
> 0; --i
)
786 ScRange
* p
= aRanges
[ i
- 1 ];
787 if (SearchRangeForEmptyCell(*p
, rSearchItem
, rCol
, rRow
, rUndoStr
))
793 for ( size_t i
= 0, nListSize
= aRanges
.size(); i
< nListSize
; ++i
)
795 ScRange
* p
= aRanges
[ i
];
796 if (SearchRangeForEmptyCell(*p
, rSearchItem
, rCol
, rRow
, rUndoStr
))
801 else if (nCommand
== SVX_SEARCHCMD_FIND_ALL
|| nCommand
== SVX_SEARCHCMD_REPLACE_ALL
)
804 for ( size_t i
= 0, nListSize
= aRanges
.size(); i
< nListSize
; ++i
)
806 ScRange
* p
= aRanges
[ i
];
807 bFound
|= SearchRangeForAllEmptyCells(*p
, rSearchItem
, rMatchedRanges
, rUndoStr
, pUndoDoc
);
816 bool lcl_maybeReplaceCellString(
817 ScColumn
& rColObj
, SCCOL
& rCol
, SCROW
& rRow
, OUString
& rUndoStr
, SCCOL nCol
, SCROW nRow
, const SvxSearchItem
& rSearchItem
)
819 ScRefCellValue aCell
= rColObj
.GetCellValue(nRow
);
825 if (rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE
&&
826 !rSearchItem
.GetReplaceString().isEmpty())
828 rColObj
.SetRawString(nRow
, rSearchItem
.GetReplaceString());
829 rUndoStr
= OUString();
838 bool ScTable::SearchRangeForEmptyCell(
839 const ScRange
& rRange
, const SvxSearchItem
& rSearchItem
,
840 SCCOL
& rCol
, SCROW
& rRow
, OUString
& rUndoStr
)
842 sal_uInt16 nCmd
= rSearchItem
.GetCommand();
843 bool bSkipFiltered
= rSearchItem
.IsSearchFiltered();
844 if (rSearchItem
.GetBackward())
847 if (rSearchItem
.GetRowDirection())
850 SCROW nLastNonFilteredRow
= MAXROW
+ 1;
851 SCROW nBeginRow
= rRange
.aEnd
.Row() > rRow
? rRow
: rRange
.aEnd
.Row();
852 for (SCROW nRow
= nBeginRow
; nRow
>= rRange
.aStart
.Row(); --nRow
)
855 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
856 if (nRow
< rRange
.aStart
.Row())
859 SCCOL nBeginCol
= rRange
.aEnd
.Col();
860 if (nRow
== rRow
&& nBeginCol
>= rCol
)
861 // always start from one cell before the cursor.
862 nBeginCol
= rCol
- (nCmd
== SVX_SEARCHCMD_FIND
? 1 : 0);
864 for (SCCOL nCol
= nBeginCol
; nCol
>= rRange
.aStart
.Col(); --nCol
)
866 if (lcl_maybeReplaceCellString(aCol
[nCol
], rCol
, rRow
, rUndoStr
, nCol
, nRow
, rSearchItem
))
874 SCCOL nBeginCol
= rRange
.aEnd
.Col() > rCol
? rCol
: rRange
.aEnd
.Col();
875 for (SCCOL nCol
= nBeginCol
; nCol
>= rRange
.aStart
.Col(); --nCol
)
877 SCROW nLastNonFilteredRow
= MAXROW
+ 1;
878 SCROW nBeginRow
= rRange
.aEnd
.Row();
879 if (nCol
== rCol
&& nBeginRow
>= rRow
)
880 // always start from one cell before the cursor.
881 nBeginRow
= rRow
- (nCmd
== SVX_SEARCHCMD_FIND
? 1 : 0);
882 for (SCROW nRow
= nBeginRow
; nRow
>= rRange
.aStart
.Row(); --nRow
)
885 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
886 if (nRow
< rRange
.aStart
.Row())
889 if (lcl_maybeReplaceCellString(aCol
[nCol
], rCol
, rRow
, rUndoStr
, nCol
, nRow
, rSearchItem
))
898 if (rSearchItem
.GetRowDirection())
901 SCROW nLastNonFilteredRow
= -1;
902 SCROW nBeginRow
= rRange
.aStart
.Row() < rRow
? rRow
: rRange
.aStart
.Row();
903 for (SCROW nRow
= nBeginRow
; nRow
<= rRange
.aEnd
.Row(); ++nRow
)
906 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
907 if (nRow
> rRange
.aEnd
.Row())
910 SCCOL nBeginCol
= rRange
.aStart
.Col();
911 if (nRow
== rRow
&& nBeginCol
<= rCol
)
912 // always start from one cell past the cursor.
913 nBeginCol
= rCol
+ (nCmd
== SVX_SEARCHCMD_FIND
? 1 : 0);
914 for (SCCOL nCol
= nBeginCol
; nCol
<= rRange
.aEnd
.Col(); ++nCol
)
916 if (lcl_maybeReplaceCellString(aCol
[nCol
], rCol
, rRow
, rUndoStr
, nCol
, nRow
, rSearchItem
))
924 SCCOL nBeginCol
= rRange
.aStart
.Col() < rCol
? rCol
: rRange
.aStart
.Col();
925 for (SCCOL nCol
= nBeginCol
; nCol
<= rRange
.aEnd
.Col(); ++nCol
)
927 SCROW nLastNonFilteredRow
= -1;
928 SCROW nBeginRow
= rRange
.aStart
.Row();
929 if (nCol
== rCol
&& nBeginRow
<= rRow
)
930 // always start from one cell past the cursor.
931 nBeginRow
= rRow
+ (nCmd
== SVX_SEARCHCMD_FIND
? 1 : 0);
932 for (SCROW nRow
= nBeginRow
; nRow
<= rRange
.aEnd
.Row(); ++nRow
)
935 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
936 if (nRow
> rRange
.aEnd
.Row())
939 if (lcl_maybeReplaceCellString(aCol
[nCol
], rCol
, rRow
, rUndoStr
, nCol
, nRow
, rSearchItem
))
948 bool ScTable::SearchRangeForAllEmptyCells(
949 const ScRange
& rRange
, const SvxSearchItem
& rSearchItem
,
950 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
953 bool bReplace
= (rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL
) &&
954 !rSearchItem
.GetReplaceString().isEmpty();
955 bool bSkipFiltered
= rSearchItem
.IsSearchFiltered();
957 for (SCCOL nCol
= rRange
.aStart
.Col(); nCol
<= rRange
.aEnd
.Col(); ++nCol
)
959 SCROW nLastNonFilteredRow
= -1;
960 if (aCol
[nCol
].IsEmptyData())
962 // The entire column is empty.
963 for (SCROW nRow
= rRange
.aStart
.Row(); nRow
<= rRange
.aEnd
.Row(); ++nRow
)
966 if (!RowFiltered(nRow
, NULL
, &nLastRow
))
968 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
, nCol
, nLastRow
, nTab
));
971 const OUString
& rNewStr
= rSearchItem
.GetReplaceString();
972 for (SCROW i
= nRow
; i
<= nLastRow
; ++i
)
974 aCol
[nCol
].SetRawString(i
, rNewStr
);
977 // TODO: I'm using a string cell with empty content to
978 // trigger deletion of cell instance on undo. Maybe I
979 // should create a new cell type for this?
980 ScSetStringParam aParam
;
981 aParam
.setTextInput();
982 pUndoDoc
->SetString(ScAddress(nCol
, i
, nTab
), EMPTY_OUSTRING
);
985 rUndoStr
= OUString();
989 nRow
= nLastRow
; // move to the last filtered row.
995 for (SCROW nRow
= rRange
.aStart
.Row(); nRow
<= rRange
.aEnd
.Row(); ++nRow
)
998 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
999 if (nRow
> rRange
.aEnd
.Row())
1002 ScRefCellValue aCell
= aCol
[nCol
].GetCellValue(nRow
);
1003 if (aCell
.isEmpty())
1006 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
));
1011 aCol
[nCol
].SetRawString(nRow
, rSearchItem
.GetReplaceString());
1014 // TODO: I'm using a string cell with empty content to
1015 // trigger deletion of cell instance on undo. Maybe I
1016 // should create a new cell type for this?
1017 ScSetStringParam aParam
;
1018 aParam
.setTextInput();
1019 pUndoDoc
->SetString(ScAddress(nCol
, nRow
, nTab
), EMPTY_OUSTRING
);
1028 void ScTable::RebuildFormulaGroups()
1030 for (SCCOL i
=0; i
<=MAXCOL
; i
++)
1031 aCol
[i
].RegroupFormulaCells();
1034 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */