re-enabled user-defined numeric fields for dBase export
[LibreOffice.git] / sc / source / core / data / table6.cxx
blob17f62da32837fd9702f5c7d80d801d3fb14f0502
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
26 #include "table.hxx"
27 #include "formulacell.hxx"
28 #include "document.hxx"
29 #include "stlpool.hxx"
30 #include "markdata.hxx"
31 #include "editutil.hxx"
32 #include "detfunc.hxx"
33 #include "postit.hxx"
34 #include "stringutil.hxx"
36 //--------------------------------------------------------------------------
39 using ::com::sun::star::util::SearchOptions;
41 namespace {
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)
59 bool bFound = false;
60 bool bDoSearch = true;
61 bool bDoBack = rSearchItem.GetBackward();
63 OUString aString;
64 ScBaseCell* pCell;
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 );
80 else
82 aCol[nCol].GetInputString( nRow, aString );
85 break;
86 case SVX_SEARCHIN_VALUE:
87 if ( eCellType == CELLTYPE_EDIT )
88 bMultiLine = lcl_GetTextWithBreaks(
89 *(const ScEditCell*)pCell, pDocument, aString );
90 else
92 aCol[nCol].GetInputString( nRow, aString );
94 break;
95 case SVX_SEARCHIN_NOTE:
96 break; // don't search this case here
97 default:
98 break;
100 xub_StrLen nStart = 0;
101 xub_StrLen nEnd = aString.getLength();
102 ::com::sun::star::util::SearchResult aSearchResult;
103 if (pSearchText)
105 if ( bDoBack )
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:
110 --nEnd;
112 else
114 bFound = (bool)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd, &aSearchResult));
115 // change results to definition before 614:
116 --nEnd;
119 if (bFound && rSearchItem.GetWordOnly())
120 bFound = (nStart == 0 && nEnd == aString.getLength() - 1);
122 else
124 OSL_FAIL("pSearchText == NULL");
125 return bFound;
128 sal_uInt8 cMatrixFlag = MM_NONE;
129 if ( bFound &&
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 )
141 rUndoStr = aString;
142 else if (pUndoDoc)
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 )
154 bRepeat = false;
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();
165 else
167 OUStringBuffer aStrBuffer(aString);
168 aStrBuffer.remove(nStart, nEnd-nStart+1);
169 aStrBuffer.insert(nStart, rSearchItem.GetReplaceString());
170 aString = aStrBuffer.makeStringAndClear();
173 // Indizes anpassen
174 if (bDoBack)
176 nEnd = nStart;
177 nStart = 0;
179 else
181 nStart = sal::static_int_cast<xub_StrLen>( nStart + sReplStr.Len() );
182 nEnd = aString.getLength();
185 // weitersuchen ?
186 if (bRepeat)
188 if ( rSearchItem.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL || nStart >= nEnd )
189 bRepeat = false;
190 else if (bDoBack)
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:
195 --nEnd;
197 else
199 bRepeat = ((bool)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd, &aSearchResult)));
200 // change results to definition before 614:
201 --nEnd;
205 while (bRepeat);
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 );
219 SCCOL nMatCols;
220 SCROW nMatRows;
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());
231 else
232 aCol[nCol].SetString(nRow, nTab, aString, pDocument->GetAddressConvention());
233 // pCell is invalid now (deleted)
236 return bFound;
239 void ScTable::SkipFilteredRows(SCROW& rRow, SCROW& rLastNonFilteredRow, bool bForward)
241 if (bForward)
243 // forward search
245 if (rRow <= rLastNonFilteredRow)
246 return;
248 SCROW nLastRow = rRow;
249 if (RowFiltered(rRow, NULL, &nLastRow))
250 // move to the first non-filtered row.
251 rRow = nLastRow + 1;
252 else
253 // record the last non-filtered row to avoid checking
254 // the filtered state for each and every row.
255 rLastNonFilteredRow = nLastRow;
257 else
259 // backward search
261 if (rRow >= rLastNonFilteredRow)
262 return;
264 SCROW nFirstRow = rRow;
265 if (RowFiltered(rRow, &nFirstRow, NULL))
266 // move to the first non-filtered row.
267 rRow = nFirstRow - 1;
268 else
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)
278 bool bFound = false;
279 bool bAll = (rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL)
280 ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL);
281 SCCOL nCol = rCol;
282 SCROW nRow = rRow;
283 SCCOL nLastCol;
284 SCROW nLastRow;
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())
294 nCol--;
295 while (!bFound && ((SCsROW)nRow >= 0))
297 if (bSkipFiltered)
298 SkipFilteredRows(nRow, nLastNonFilteredRow, false);
300 while (!bFound && ((SCsCOL)nCol >= 0))
302 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
303 if (!bFound)
305 bool bIsEmpty;
308 nCol--;
309 if ((SCsCOL)nCol >= 0)
310 bIsEmpty = aCol[nCol].IsEmptyData();
311 else
312 bIsEmpty = true;
314 while (((SCsCOL)nCol >= 0) && bIsEmpty);
317 if (!bFound)
319 nCol = nLastCol;
320 nRow--;
324 else
326 nRow--;
327 while (!bFound && ((SCsCOL)nCol >= 0))
329 while (!bFound && ((SCsROW)nRow >= 0))
331 if (bSkipFiltered)
332 SkipFilteredRows(nRow, nLastNonFilteredRow, false);
334 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
335 if (!bFound)
337 if (!aCol[nCol].GetPrevDataPos(nRow))
338 nRow = -1;
341 if (!bFound)
343 // Not found in this column. Move to the next column.
344 bool bIsEmpty;
345 nRow = nLastRow;
346 nLastNonFilteredRow = MAXROW + 1;
349 nCol--;
350 if ((SCsCOL)nCol >= 0)
351 bIsEmpty = aCol[nCol].IsEmptyData();
352 else
353 bIsEmpty = true;
355 while (((SCsCOL)nCol >= 0) && bIsEmpty);
360 else
362 SCROW nLastNonFilteredRow = -1;
363 if (!bAll && rSearchItem.GetRowDirection())
365 nCol++;
366 while (!bFound && (nRow <= nLastRow))
368 if (bSkipFiltered)
369 SkipFilteredRows(nRow, nLastNonFilteredRow, true);
371 while (!bFound && (nCol <= nLastCol))
373 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
374 if (!bFound)
376 nCol++;
377 while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
380 if (!bFound)
382 nCol = 0;
383 nRow++;
387 else
389 nRow++;
390 while (!bFound && (nCol <= nLastCol))
392 while (!bFound && (nRow <= nLastRow))
394 if (bSkipFiltered)
395 SkipFilteredRows(nRow, nLastNonFilteredRow, true);
397 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
398 if (!bFound)
400 if (!aCol[nCol].GetNextDataPos(nRow))
401 nRow = MAXROW + 1;
404 if (!bFound)
406 // Not found in this column. Move to the next column.
407 nRow = 0;
408 nLastNonFilteredRow = -1;
409 nCol++;
410 while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
415 if (bFound)
417 rCol = nCol;
418 rRow = nRow;
420 return bFound;
423 bool ScTable::SearchAll(const SvxSearchItem& rSearchItem, const ScMarkData& rMark,
424 ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
426 bool bFound = true;
427 SCCOL nCol = 0;
428 SCROW nRow = -1;
429 bool bEverFound = false;
433 bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
434 if (bFound)
436 bEverFound = true;
437 rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
440 while (bFound);
442 return bEverFound;
445 void ScTable::UpdateSearchItemAddressForReplace( const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow )
447 if (rSearchItem.GetBackward())
449 if (rSearchItem.GetRowDirection())
450 rCol += 1;
451 else
452 rRow += 1;
454 else
456 if (rSearchItem.GetRowDirection())
457 rCol -= 1;
458 else
459 rRow -= 1;
463 bool ScTable::Replace(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
464 const ScMarkData& rMark, OUString& rUndoStr, ScDocument* pUndoDoc)
466 bool bFound = false;
467 SCCOL nCol = rCol;
468 SCROW nRow = rRow;
470 UpdateSearchItemAddressForReplace( rSearchItem, nCol, nRow );
471 bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
472 if (bFound)
474 rCol = nCol;
475 rRow = nRow;
477 return bFound;
480 bool ScTable::ReplaceAll(
481 const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges,
482 OUString& rUndoStr, ScDocument* pUndoDoc)
484 SCCOL nCol = 0;
485 SCROW nRow = -1;
487 bool bEverFound = false;
488 while (true)
490 bool bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
492 if (bFound)
494 bEverFound = true;
495 rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
497 else
498 break;
500 return bEverFound;
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 );
510 SCsCOL nCol = rCol;
511 SCsROW nRow = rRow;
512 bool bFound = false;
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
521 nRow += nAdd;
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 );
530 else
532 nRow = nNextRow;
533 bFound = true;
536 while (!bFound && ValidCol(nCol));
538 else // spaltenweise
540 SCsROW nNextRows[MAXCOLCOUNT];
541 SCsCOL i;
542 for (i=0; i<=MAXCOL; i++)
544 SCsROW nSRow = nRow;
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
551 nRow = -1;
552 for (i=MAXCOL; i>=0; i--)
553 if (nNextRows[i]>nRow)
555 nCol = i;
556 nRow = nNextRows[i];
557 bFound = true;
560 else // vorwaerts
562 nRow = MAXROW+1;
563 for (i=0; i<=MAXCOL; i++)
564 if (nNextRows[i]<nRow)
566 nCol = i;
567 nRow = nNextRows[i];
568 bFound = true;
573 if (bFound)
575 rCol = (SCCOL) nCol;
576 rRow = (SCROW) nRow;
578 return bFound;
581 //! einzelnes Pattern fuer Undo zurueckgeben
583 bool ScTable::ReplaceStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
584 const ScMarkData& rMark, bool bIsUndo)
586 bool bRet;
587 if (bIsUndo)
588 bRet = true;
589 else
590 bRet = SearchStyle(rSearchItem, rCol, rRow, rMark);
591 if (bRet)
593 const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
594 pDocument->GetStyleSheetPool()->Find(
595 rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
597 if (pReplaceStyle)
598 ApplyStyle( rCol, rRow, *pReplaceStyle );
599 else
601 OSL_FAIL("pReplaceStyle==0");
605 return bRet;
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++)
620 bool bFound = true;
621 SCsROW nRow = 0;
622 SCsROW nEndRow;
623 while (bFound && nRow <= MAXROW)
625 bFound = aCol[i].SearchStyleRange( nRow, nEndRow, pSearchStyle, bBack, bSelect, rMark );
626 if (bFound)
628 if (nEndRow<nRow)
630 SCsROW nTemp = nRow;
631 nRow = nEndRow;
632 nEndRow = nTemp;
634 rMatchedRanges.Join(ScRange(i, nRow, nTab, i, nEndRow, nTab));
635 nRow = nEndRow + 1;
636 bEverFound = true;
641 return bEverFound;
644 bool ScTable::ReplaceAllStyle(
645 const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges,
646 ScDocument* pUndoDoc)
648 bool bRet = SearchAllStyle(rSearchItem, rMark, rMatchedRanges);
649 if (bRet)
651 const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
652 pDocument->GetStyleSheetPool()->Find(
653 rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
655 if (pReplaceStyle)
657 if (pUndoDoc)
658 pDocument->CopyToDocument( 0,0,nTab, MAXCOL,MAXROW,nTab,
659 IDF_ATTRIB, true, pUndoDoc, &rMark );
660 ApplySelectionStyle( *pReplaceStyle, rMark );
662 else
664 OSL_FAIL("pReplaceStyle==0");
668 return bRet;
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();
676 bool bFound = false;
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();
686 if (bStyles)
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);
697 else
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);
728 delete pSearchText;
729 pSearchText = NULL;
732 return bFound;
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);
744 ScRangeList aRanges;
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.
752 return false;
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.
761 continue;
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))
788 return true;
791 else
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))
797 return true;
801 else if (nCommand == SVX_SEARCHCMD_FIND_ALL || nCommand == SVX_SEARCHCMD_REPLACE_ALL)
803 bool bFound = false;
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);
809 return bFound;
811 return false;
814 namespace {
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);
820 if (!pCell)
822 // empty cell found.
823 rCol = nCol;
824 rRow = nRow;
825 if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
826 rSearchItem.GetReplaceString().Len())
828 rColObj.Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
829 rUndoStr = OUString();
831 return true;
833 return false;
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())
846 // backward search
847 if (rSearchItem.GetRowDirection())
849 // row direction.
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)
854 if (bSkipFiltered)
855 SkipFilteredRows(nRow, nLastNonFilteredRow, false);
856 if (nRow < rRange.aStart.Row())
857 break;
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))
867 return true;
871 else
873 // column direction.
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)
884 if (bSkipFiltered)
885 SkipFilteredRows(nRow, nLastNonFilteredRow, false);
886 if (nRow < rRange.aStart.Row())
887 break;
889 if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
890 return true;
895 else
897 // forward search
898 if (rSearchItem.GetRowDirection())
900 // row direction.
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)
905 if (bSkipFiltered)
906 SkipFilteredRows(nRow, nLastNonFilteredRow, true);
907 if (nRow > rRange.aEnd.Row())
908 break;
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))
917 return true;
921 else
923 // column direction.
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)
934 if (bSkipFiltered)
935 SkipFilteredRows(nRow, nLastNonFilteredRow, true);
936 if (nRow > rRange.aEnd.Row())
937 break;
939 if (lcl_maybeReplaceCellString(aCol[nCol], rCol, rRow, rUndoStr, nCol, nRow, rSearchItem))
940 return true;
945 return false;
948 bool ScTable::SearchRangeForAllEmptyCells(
949 const ScRange& rRange, const SvxSearchItem& rSearchItem,
950 ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
952 bool bFound = false;
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)
965 SCROW nLastRow;
966 if (!RowFiltered(nRow, NULL, &nLastRow))
968 rMatchedRanges.Join(ScRange(nCol, nRow, nTab, nCol, nLastRow, nTab));
969 if (bReplace)
971 const String& rNewStr = rSearchItem.GetReplaceString();
972 for (SCROW i = nRow; i <= nLastRow; ++i)
974 aCol[nCol].Insert(i, new ScStringCell(rNewStr));
975 if (pUndoDoc)
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 = String();
989 nRow = nLastRow; // move to the last filtered row.
991 bFound = true;
992 continue;
995 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
997 if (bSkipFiltered)
998 SkipFilteredRows(nRow, nLastNonFilteredRow, true);
999 if (nRow > rRange.aEnd.Row())
1000 break;
1002 ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
1003 if (!pCell)
1005 // empty cell found
1006 rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
1007 bFound = true;
1009 if (bReplace)
1011 aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
1012 if (pUndoDoc)
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);
1025 return bFound;
1028 void ScTable::RebuildFormulaGroups()
1030 for (SCCOL i=0; i<=MAXCOL; i++)
1031 aCol[i].RebuildFormulaGroups();
1034 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */