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 ScEditCell
& rCell
, ScDocument
* pDoc
, OUString
& rVal
)
45 // true = more than 1 paragraph
47 const EditTextObject
* pData
= rCell
.GetData();
48 EditEngine
& rEngine
= pDoc
->GetEditEngine();
49 rEngine
.SetText( *pData
);
50 rVal
= rEngine
.GetText( LINEEND_LF
);
51 return ( rEngine
.GetParagraphCount() > 1 );
56 bool ScTable::SearchCell(const SvxSearchItem
& rSearchItem
, SCCOL nCol
, SCROW nRow
,
57 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
60 bool bDoSearch
= true;
61 bool bDoBack
= rSearchItem
.GetBackward();
65 if (rSearchItem
.GetSelection())
66 bDoSearch
= rMark
.IsCellMarked(nCol
, nRow
);
67 if ( bDoSearch
&& ((pCell
= aCol
[nCol
].GetCell( nRow
)) != NULL
) )
69 bool bMultiLine
= false;
70 CellType eCellType
= pCell
->GetCellType();
71 switch (rSearchItem
.GetCellType())
73 case SVX_SEARCHIN_FORMULA
:
75 if ( eCellType
== CELLTYPE_FORMULA
)
76 static_cast<ScFormulaCell
*>(pCell
)->GetFormula(aString
, pDocument
->GetGrammar());
77 else if ( eCellType
== CELLTYPE_EDIT
)
78 bMultiLine
= lcl_GetTextWithBreaks(
79 *(const ScEditCell
*)pCell
, pDocument
, aString
);
82 aCol
[nCol
].GetInputString( nRow
, aString
);
86 case SVX_SEARCHIN_VALUE
:
87 if ( eCellType
== CELLTYPE_EDIT
)
88 bMultiLine
= lcl_GetTextWithBreaks(
89 *(const ScEditCell
*)pCell
, pDocument
, aString
);
92 aCol
[nCol
].GetInputString( nRow
, aString
);
95 case SVX_SEARCHIN_NOTE
:
96 break; // don't search this case here
100 xub_StrLen nStart
= 0;
101 xub_StrLen nEnd
= aString
.getLength();
102 ::com::sun::star::util::SearchResult aSearchResult
;
107 xub_StrLen nTemp
=nStart
; nStart
=nEnd
; nEnd
=nTemp
;
108 bFound
= (bool)(pSearchText
->SearchBkwrd(aString
, &nStart
, &nEnd
, &aSearchResult
));
109 // change results to definition before 614:
114 bFound
= (bool)(pSearchText
->SearchFrwrd(aString
, &nStart
, &nEnd
, &aSearchResult
));
115 // change results to definition before 614:
119 if (bFound
&& rSearchItem
.GetWordOnly())
120 bFound
= (nStart
== 0 && nEnd
== aString
.getLength() - 1);
124 OSL_FAIL("pSearchText == NULL");
128 sal_uInt8 cMatrixFlag
= MM_NONE
;
130 ( (rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE
)
131 ||(rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL
) ) &&
132 // Matrix nicht zerreissen, nur Matrixformel ersetzen
133 !( (eCellType
== CELLTYPE_FORMULA
&&
134 ((cMatrixFlag
= ((ScFormulaCell
*)pCell
)->GetMatrixFlag()) == MM_REFERENCE
))
135 // kein UndoDoc => Matrix nicht wiederherstellbar => nicht ersetzen
136 || (cMatrixFlag
!= MM_NONE
&& !pUndoDoc
) ) &&
137 IsBlockEditable(nCol
, nRow
, nCol
, nRow
)
140 if ( cMatrixFlag
== MM_NONE
&& rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE
)
144 ScAddress
aAdr( nCol
, nRow
, nTab
);
145 ScBaseCell
* pUndoCell
= pCell
->Clone( *pUndoDoc
);
146 pUndoDoc
->PutCell( aAdr
, pUndoCell
);
148 bool bRepeat
= !rSearchItem
.GetWordOnly();
151 // wenn der gefundene Text leer ist, nicht weitersuchen,
152 // sonst wuerde man nie mehr aufhoeren (#35410#)
153 if ( nEnd
< nStart
|| nEnd
== STRING_MAXLEN
)
156 String sReplStr
= rSearchItem
.GetReplaceString();
157 if (rSearchItem
.GetRegExp())
159 pSearchText
->ReplaceBackReferences( sReplStr
, aString
, aSearchResult
);
160 OUStringBuffer
aStrBuffer(aString
);
161 aStrBuffer
.remove(nStart
, nEnd
-nStart
+1);
162 aStrBuffer
.insert(nStart
, sReplStr
);
163 aString
= aStrBuffer
.makeStringAndClear();
167 OUStringBuffer
aStrBuffer(aString
);
168 aStrBuffer
.remove(nStart
, nEnd
-nStart
+1);
169 aStrBuffer
.insert(nStart
, rSearchItem
.GetReplaceString());
170 aString
= aStrBuffer
.makeStringAndClear();
181 nStart
= sal::static_int_cast
<xub_StrLen
>( nStart
+ sReplStr
.Len() );
182 nEnd
= aString
.getLength();
188 if ( rSearchItem
.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL
|| nStart
>= nEnd
)
192 xub_StrLen nTemp
=nStart
; nStart
=nEnd
; nEnd
=nTemp
;
193 bRepeat
= ((bool)(pSearchText
->SearchBkwrd(aString
, &nStart
, &nEnd
, &aSearchResult
)));
194 // change results to definition before 614:
199 bRepeat
= ((bool)(pSearchText
->SearchFrwrd(aString
, &nStart
, &nEnd
, &aSearchResult
)));
200 // change results to definition before 614:
207 if ( cMatrixFlag
!= MM_NONE
)
208 { // Matrix nicht zerreissen
209 if ( aString
.getLength() > 2 )
210 { // {} raus, erst hier damit auch "{=" durch "{=..." ersetzt werden kann
211 if ( aString
[ aString
.getLength()-1 ] == '}' )
212 aString
= aString
.copy( 0, aString
.getLength()-1 );
213 if ( aString
[0] == '{' )
214 aString
= aString
.copy( 1 );
216 ScAddress
aAdr( nCol
, nRow
, nTab
);
217 ScFormulaCell
* pFCell
= new ScFormulaCell( pDocument
, aAdr
,
218 aString
, pDocument
->GetGrammar(), cMatrixFlag
);
221 ((ScFormulaCell
*)pCell
)->GetMatColsRows( nMatCols
, nMatRows
);
222 pFCell
->SetMatColsRows( nMatCols
, nMatRows
);
223 aCol
[nCol
].Insert( nRow
, pFCell
);
225 else if ( bMultiLine
&& aString
.indexOf('\n') != -1 )
227 ScFieldEditEngine
& rEngine
= pDocument
->GetEditEngine();
228 rEngine
.SetText(aString
);
229 SetEditText(nCol
, nRow
, rEngine
.CreateTextObject());
232 aCol
[nCol
].SetString(nRow
, nTab
, aString
, pDocument
->GetAddressConvention());
233 // pCell is invalid now (deleted)
239 void ScTable::SkipFilteredRows(SCROW
& rRow
, SCROW
& rLastNonFilteredRow
, bool bForward
)
245 if (rRow
<= rLastNonFilteredRow
)
248 SCROW nLastRow
= rRow
;
249 if (RowFiltered(rRow
, NULL
, &nLastRow
))
250 // move to the first non-filtered row.
253 // record the last non-filtered row to avoid checking
254 // the filtered state for each and every row.
255 rLastNonFilteredRow
= nLastRow
;
261 if (rRow
>= rLastNonFilteredRow
)
264 SCROW nFirstRow
= rRow
;
265 if (RowFiltered(rRow
, &nFirstRow
, NULL
))
266 // move to the first non-filtered row.
267 rRow
= nFirstRow
- 1;
269 // record the last non-filtered row to avoid checking
270 // the filtered state for each and every row.
271 rLastNonFilteredRow
= nFirstRow
;
275 bool ScTable::Search(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
276 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
279 bool bAll
= (rSearchItem
.GetCommand() == SVX_SEARCHCMD_FIND_ALL
)
280 ||(rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL
);
285 GetLastDataPos(nLastCol
, nLastRow
);
286 bool bSkipFiltered
= !rSearchItem
.IsSearchFiltered();
287 if (!bAll
&& rSearchItem
.GetBackward())
289 SCROW nLastNonFilteredRow
= MAXROW
+ 1;
290 nCol
= std::min(nCol
, (SCCOL
)(nLastCol
+ 1));
291 nRow
= std::min(nRow
, (SCROW
)(nLastRow
+ 1));
292 if (rSearchItem
.GetRowDirection())
295 while (!bFound
&& ((SCsROW
)nRow
>= 0))
298 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
300 while (!bFound
&& ((SCsCOL
)nCol
>= 0))
302 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
309 if ((SCsCOL
)nCol
>= 0)
310 bIsEmpty
= aCol
[nCol
].IsEmptyData();
314 while (((SCsCOL
)nCol
>= 0) && bIsEmpty
);
327 while (!bFound
&& ((SCsCOL
)nCol
>= 0))
329 while (!bFound
&& ((SCsROW
)nRow
>= 0))
332 SkipFilteredRows(nRow
, nLastNonFilteredRow
, false);
334 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
337 if (!aCol
[nCol
].GetPrevDataPos(nRow
))
343 // Not found in this column. Move to the next column.
346 nLastNonFilteredRow
= MAXROW
+ 1;
350 if ((SCsCOL
)nCol
>= 0)
351 bIsEmpty
= aCol
[nCol
].IsEmptyData();
355 while (((SCsCOL
)nCol
>= 0) && bIsEmpty
);
362 SCROW nLastNonFilteredRow
= -1;
363 if (!bAll
&& rSearchItem
.GetRowDirection())
366 while (!bFound
&& (nRow
<= nLastRow
))
369 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
371 while (!bFound
&& (nCol
<= nLastCol
))
373 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
377 while ((nCol
<= nLastCol
) && aCol
[nCol
].IsEmptyData()) nCol
++;
390 while (!bFound
&& (nCol
<= nLastCol
))
392 while (!bFound
&& (nRow
<= nLastRow
))
395 SkipFilteredRows(nRow
, nLastNonFilteredRow
, true);
397 bFound
= SearchCell(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
400 if (!aCol
[nCol
].GetNextDataPos(nRow
))
406 // Not found in this column. Move to the next column.
408 nLastNonFilteredRow
= -1;
410 while ((nCol
<= nLastCol
) && aCol
[nCol
].IsEmptyData()) nCol
++;
423 bool ScTable::SearchAll(const SvxSearchItem
& rSearchItem
, const ScMarkData
& rMark
,
424 ScRangeList
& rMatchedRanges
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
429 bool bEverFound
= false;
433 bFound
= Search(rSearchItem
, nCol
, nRow
, rMark
, rUndoStr
, pUndoDoc
);
437 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
));
445 void ScTable::UpdateSearchItemAddressForReplace( const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
)
447 if (rSearchItem
.GetBackward())
449 if (rSearchItem
.GetRowDirection())
456 if (rSearchItem
.GetRowDirection())
463 bool ScTable::Replace(const SvxSearchItem
& rSearchItem
, SCCOL
& rCol
, SCROW
& rRow
,
464 const ScMarkData
& rMark
, OUString
& rUndoStr
, ScDocument
* pUndoDoc
)
470 UpdateSearchItemAddressForReplace( rSearchItem
, nCol
, nRow
);
471 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 ScBaseCell
* pCell
= rColObj
.GetCell(nRow
);
825 if (rSearchItem
.GetCommand() == SVX_SEARCHCMD_REPLACE
&&
826 rSearchItem
.GetReplaceString().Len())
828 rColObj
.Insert(nRow
, new ScStringCell(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().Len() > 0);
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 String
& rNewStr
= rSearchItem
.GetReplaceString();
972 for (SCROW i
= nRow
; i
<= nLastRow
; ++i
)
974 aCol
[nCol
].Insert(i
, new ScStringCell(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
);
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 ScBaseCell
* pCell
= aCol
[nCol
].GetCell(nRow
);
1006 rMatchedRanges
.Join(ScRange(nCol
, nRow
, nTab
));
1011 aCol
[nCol
].Insert(nRow
, new ScStringCell(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
].RebuildFormulaGroups();
1034 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */