update dev300-m57
[ooovba.git] / sc / source / core / data / table6.cxx
blob8d5ec0f3f1bfc3b8cb2b6a430abc7b21695e73af
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: table6.cxx,v $
10 * $Revision: 1.18.128.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include <com/sun/star/i18n/TransliterationModules.hpp>
38 #include <unotools/textsearch.hxx>
39 #include <svx/srchitem.hxx>
40 #include <svx/editobj.hxx>
42 #include "table.hxx"
43 #include "collect.hxx"
44 #include "cell.hxx"
45 #include "document.hxx"
46 #include "stlpool.hxx"
47 #include "markdata.hxx"
48 #include "editutil.hxx"
49 #include "detfunc.hxx"
50 #include "postit.hxx"
52 //--------------------------------------------------------------------------
55 using ::com::sun::star::util::SearchOptions;
57 BOOL lcl_GetTextWithBreaks( const ScEditCell& rCell, ScDocument* pDoc, String& rVal )
59 // TRUE = more than 1 paragraph
61 const EditTextObject* pData = NULL;
62 rCell.GetData( pData );
63 EditEngine& rEngine = pDoc->GetEditEngine();
64 rEngine.SetText( *pData );
65 rVal = rEngine.GetText( LINEEND_LF );
66 return ( rEngine.GetParagraphCount() > 1 );
69 BOOL ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, SCROW nRow,
70 const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
72 BOOL bFound = FALSE;
73 BOOL bDoSearch = TRUE;
74 BOOL bDoBack = rSearchItem.GetBackward();
76 String aString;
77 ScBaseCell* pCell;
78 if (rSearchItem.GetSelection())
79 bDoSearch = rMark.IsCellMarked(nCol, nRow);
80 if ( bDoSearch && ((pCell = aCol[nCol].GetCell( nRow )) != NULL) )
82 BOOL bMultiLine = FALSE;
83 CellType eCellType = pCell->GetCellType();
84 switch (rSearchItem.GetCellType())
86 case SVX_SEARCHIN_FORMULA:
88 if ( eCellType == CELLTYPE_FORMULA )
89 ((ScFormulaCell*)pCell)->GetFormula( aString,
90 formula::FormulaGrammar::GRAM_NATIVE_UI);
91 else if ( eCellType == CELLTYPE_EDIT )
92 bMultiLine = lcl_GetTextWithBreaks(
93 *(const ScEditCell*)pCell, pDocument, aString );
94 else
95 aCol[nCol].GetInputString( nRow, aString );
97 break;
98 case SVX_SEARCHIN_VALUE:
99 if ( eCellType == CELLTYPE_EDIT )
100 bMultiLine = lcl_GetTextWithBreaks(
101 *(const ScEditCell*)pCell, pDocument, aString );
102 else
103 aCol[nCol].GetInputString( nRow, aString );
104 break;
105 case SVX_SEARCHIN_NOTE:
107 if(const ScPostIt* pNote = pCell->GetNote())
109 aString = pNote->GetText();
110 bMultiLine = pNote->HasMultiLineText();
113 break;
114 default:
115 break;
117 xub_StrLen nStart = 0;
118 xub_StrLen nEnd = aString.Len();
119 ::com::sun::star::util::SearchResult aSearchResult;
120 if (pSearchText)
122 if ( bDoBack )
124 xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
125 bFound = (BOOL)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd, &aSearchResult));
126 // change results to definition before 614:
127 --nEnd;
129 else
131 bFound = (BOOL)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd, &aSearchResult));
132 // change results to definition before 614:
133 --nEnd;
136 if (bFound && rSearchItem.GetWordOnly())
137 bFound = (nStart == 0 && nEnd == aString.Len() - 1);
139 else
141 DBG_ERROR("pSearchText == NULL");
142 return bFound;
145 BYTE cMatrixFlag = MM_NONE;
146 if ( bFound &&
147 ( (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE)
148 ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) ) &&
149 // #60558# Matrix nicht zerreissen, nur Matrixformel ersetzen
150 !( (eCellType == CELLTYPE_FORMULA &&
151 ((cMatrixFlag = ((ScFormulaCell*)pCell)->GetMatrixFlag()) == MM_REFERENCE))
152 // kein UndoDoc => Matrix nicht wiederherstellbar => nicht ersetzen
153 || (cMatrixFlag != MM_NONE && !pUndoDoc) )
156 if ( cMatrixFlag == MM_NONE && rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE )
157 rUndoStr = aString;
158 else if (pUndoDoc)
160 ScAddress aAdr( nCol, nRow, nTab );
161 ScBaseCell* pUndoCell = pCell->CloneWithoutNote( *pUndoDoc );
162 pUndoDoc->PutCell( aAdr, pUndoCell);
164 BOOL bRepeat = !rSearchItem.GetWordOnly();
167 // wenn der gefundene Text leer ist, nicht weitersuchen,
168 // sonst wuerde man nie mehr aufhoeren (#35410#)
169 if ( nEnd < nStart || nEnd == STRING_MAXLEN )
170 bRepeat = FALSE;
172 String sReplStr = rSearchItem.GetReplaceString();
173 if (rSearchItem.GetRegExp())
175 String sFndStr = aString.Copy(nStart, nEnd-nStart+1);
176 pSearchText->ReplaceBackReferences( sReplStr, aString, aSearchResult );
177 aString.Erase(nStart, nEnd-nStart+1);
178 aString.Insert(sReplStr, nStart);
180 else
182 aString.Erase(nStart, nEnd - nStart + 1);
183 aString.Insert(rSearchItem.GetReplaceString(), nStart);
186 // Indizes anpassen
187 if (bDoBack)
189 nEnd = nStart;
190 nStart = 0;
192 else
194 nStart = sal::static_int_cast<xub_StrLen>( nStart + sReplStr.Len() );
195 nEnd = aString.Len();
198 // weitersuchen ?
199 if (bRepeat)
201 if ( rSearchItem.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL || nStart >= nEnd )
202 bRepeat = FALSE;
203 else if (bDoBack)
205 xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
206 bRepeat = ((BOOL)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd)));
207 // change results to definition before 614:
208 --nEnd;
210 else
212 bRepeat = ((BOOL)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd)));
213 // change results to definition before 614:
214 --nEnd;
218 while (bRepeat);
219 if (rSearchItem.GetCellType() == SVX_SEARCHIN_NOTE)
221 // NB: rich text format is lost.
222 // This is also true of Cells.
223 if( ScPostIt* pNote = pCell->GetNote() )
224 pNote->SetText( ScAddress( nCol, nRow, nTab ), aString );
226 else if ( cMatrixFlag != MM_NONE )
227 { // #60558# Matrix nicht zerreissen
228 if ( aString.Len() > 2 )
229 { // {} raus, erst hier damit auch "{=" durch "{=..." ersetzt werden kann
230 if ( aString.GetChar( aString.Len()-1 ) == '}' )
231 aString.Erase( aString.Len()-1, 1 );
232 if ( aString.GetChar(0) == '{' )
233 aString.Erase( 0, 1 );
235 ScAddress aAdr( nCol, nRow, nTab );
236 ScFormulaCell* pFCell = new ScFormulaCell( pDocument, aAdr,
237 aString,formula::FormulaGrammar::GRAM_NATIVE_UI, cMatrixFlag );
238 SCCOL nMatCols;
239 SCROW nMatRows;
240 ((ScFormulaCell*)pCell)->GetMatColsRows( nMatCols, nMatRows );
241 pFCell->SetMatColsRows( nMatCols, nMatRows );
242 aCol[nCol].Insert( nRow, pFCell );
244 else if ( bMultiLine && aString.Search('\n') != STRING_NOTFOUND )
245 PutCell( nCol, nRow, new ScEditCell( aString, pDocument ) );
246 else
247 aCol[nCol].SetString(nRow, nTab, aString);
248 // pCell is invalid now (deleted)
251 return bFound;
254 BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
255 const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
257 BOOL bFound = FALSE;
258 BOOL bAll = (rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL)
259 ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL);
260 SCCOL nCol = rCol;
261 SCROW nRow = rRow;
262 SCCOL nLastCol;
263 SCROW nLastRow;
264 GetLastDataPos(nLastCol, nLastRow);
265 if (!bAll && rSearchItem.GetBackward())
267 nCol = Min(nCol, (SCCOL)(nLastCol + 1));
268 nRow = Min(nRow, (SCROW)(nLastRow + 1));
269 if (rSearchItem.GetRowDirection())
271 nCol--;
272 while (!bFound && ((SCsROW)nRow >= 0))
274 while (!bFound && ((SCsCOL)nCol >= 0))
276 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
277 if (!bFound)
279 BOOL bIsEmpty;
282 nCol--;
283 if ((SCsCOL)nCol >= 0)
284 bIsEmpty = aCol[nCol].IsEmptyData();
285 else
286 bIsEmpty = TRUE;
288 while (((SCsCOL)nCol >= 0) && bIsEmpty);
291 if (!bFound)
293 nCol = nLastCol;
294 nRow--;
298 else
300 nRow--;
301 while (!bFound && ((SCsCOL)nCol >= 0))
303 while (!bFound && ((SCsROW)nRow >= 0))
305 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
306 if (!bFound)
308 if (!aCol[nCol].GetPrevDataPos(nRow))
309 nRow = -1;
312 if (!bFound)
314 BOOL bIsEmpty;
315 nRow = nLastRow;
318 nCol--;
319 if ((SCsCOL)nCol >= 0)
320 bIsEmpty = aCol[nCol].IsEmptyData();
321 else
322 bIsEmpty = TRUE;
324 while (((SCsCOL)nCol >= 0) && bIsEmpty);
329 else
331 if (!bAll && rSearchItem.GetRowDirection())
333 nCol++;
334 while (!bFound && (nRow <= nLastRow))
336 while (!bFound && (nCol <= nLastCol))
338 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
339 if (!bFound)
341 nCol++;
342 while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
345 if (!bFound)
347 nCol = 0;
348 nRow++;
352 else
354 nRow++;
355 while (!bFound && (nCol <= nLastCol))
357 while (!bFound && (nRow <= nLastRow))
359 bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
360 if (!bFound)
362 if (!aCol[nCol].GetNextDataPos(nRow))
363 nRow = MAXROW + 1;
366 if (!bFound)
368 nRow = 0;
369 nCol++;
370 while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
375 if (bFound)
377 rCol = nCol;
378 rRow = nRow;
380 return bFound;
383 BOOL ScTable::SearchAll(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
384 String& rUndoStr, ScDocument* pUndoDoc)
386 BOOL bFound = TRUE;
387 SCCOL nCol = 0;
388 SCROW nRow = -1;
390 ScMarkData aNewMark( rMark ); // Tabellen-Markierungen kopieren
391 aNewMark.ResetMark();
394 bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
395 if (bFound)
396 aNewMark.SetMultiMarkArea( ScRange( nCol, nRow, nTab ) );
398 while (bFound);
400 rMark = aNewMark; // Markierung kopieren
401 //! pro Tabelle
403 return (aNewMark.IsMultiMarked());
406 BOOL ScTable::Replace(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
407 const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
409 BOOL bFound = FALSE;
410 SCCOL nCol = rCol;
411 SCROW nRow = rRow;
412 if (rSearchItem.GetBackward())
414 if (rSearchItem.GetRowDirection())
415 nCol += 1;
416 else
417 nRow += 1;
419 else
421 if (rSearchItem.GetRowDirection())
422 nCol -= 1;
423 else
424 nRow -= 1;
426 bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
427 if (bFound)
429 rCol = nCol;
430 rRow = nRow;
432 return bFound;
435 BOOL ScTable::ReplaceAll(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
436 String& rUndoStr, ScDocument* pUndoDoc)
438 BOOL bOldDouble = ScColumn::bDoubleAlloc; // sollte immer FALSE sein?
439 DBG_ASSERT(!bOldDouble,"bDoubleAlloc ???");
440 ScColumn::bDoubleAlloc = TRUE; // fuer Undo-Doc
442 BOOL bFound = TRUE;
443 SCCOL nCol = 0;
444 SCROW nRow = -1;
446 ScMarkData aNewMark( rMark ); // Tabellen-Markierungen kopieren
447 aNewMark.ResetMark();
450 bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
451 if (bFound)
452 aNewMark.SetMultiMarkArea( ScRange( nCol, nRow, nTab ) );
454 while (bFound);
456 ScColumn::bDoubleAlloc = bOldDouble;
458 rMark = aNewMark; // Markierung kopieren
459 //! pro Tabelle
461 return (aNewMark.IsMultiMarked());
464 BOOL ScTable::SearchStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
465 ScMarkData& rMark)
467 const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
468 pDocument->GetStyleSheetPool()->Find(
469 rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
471 SCsCOL nCol = rCol;
472 SCsROW nRow = rRow;
473 BOOL bFound = FALSE;
475 BOOL bSelect = rSearchItem.GetSelection();
476 BOOL bRows = rSearchItem.GetRowDirection();
477 BOOL bBack = rSearchItem.GetBackward();
478 short nAdd = bBack ? -1 : 1;
480 if (bRows) // zeilenweise
482 nRow += nAdd;
485 SCsROW nNextRow = aCol[nCol].SearchStyle( nRow, pSearchStyle, bBack, bSelect, rMark );
486 if (!ValidRow(nNextRow))
488 nRow = bBack ? MAXROW : 0;
489 nCol = sal::static_int_cast<SCsCOL>( nCol + nAdd );
491 else
493 nRow = nNextRow;
494 bFound = TRUE;
497 while (!bFound && ValidCol(nCol));
499 else // spaltenweise
501 SCsROW nNextRows[MAXCOLCOUNT];
502 SCsCOL i;
503 for (i=0; i<=MAXCOL; i++)
505 SCsROW nSRow = nRow;
506 if (bBack) { if (i>=nCol) --nSRow; }
507 else { if (i<=nCol) ++nSRow; }
508 nNextRows[i] = aCol[i].SearchStyle( nSRow, pSearchStyle, bBack, bSelect, rMark );
510 if (bBack) // rueckwaerts
512 nRow = -1;
513 for (i=MAXCOL; i>=0; i--)
514 if (nNextRows[i]>nRow)
516 nCol = i;
517 nRow = nNextRows[i];
518 bFound = TRUE;
521 else // vorwaerts
523 nRow = MAXROW+1;
524 for (i=0; i<=MAXCOL; i++)
525 if (nNextRows[i]<nRow)
527 nCol = i;
528 nRow = nNextRows[i];
529 bFound = TRUE;
534 if (bFound)
536 rCol = (SCCOL) nCol;
537 rRow = (SCROW) nRow;
539 return bFound;
542 //! einzelnes Pattern fuer Undo zurueckgeben
544 BOOL ScTable::ReplaceStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
545 ScMarkData& rMark, BOOL bIsUndo)
547 BOOL bRet;
548 if (bIsUndo)
549 bRet = TRUE;
550 else
551 bRet = SearchStyle(rSearchItem, rCol, rRow, rMark);
552 if (bRet)
554 const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
555 pDocument->GetStyleSheetPool()->Find(
556 rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
558 if (pReplaceStyle)
559 ApplyStyle( rCol, rRow, *pReplaceStyle );
560 else
562 DBG_ERROR("pReplaceStyle==0");
566 return bRet;
569 BOOL ScTable::SearchAllStyle(const SvxSearchItem& rSearchItem, ScMarkData& rMark)
571 const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
572 pDocument->GetStyleSheetPool()->Find(
573 rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
574 BOOL bSelect = rSearchItem.GetSelection();
575 BOOL bBack = rSearchItem.GetBackward();
577 ScMarkData aNewMark( rMark ); // Tabellen-Markierungen kopieren
578 aNewMark.ResetMark();
579 for (SCCOL i=0; i<=MAXCOL; i++)
581 BOOL bFound = TRUE;
582 SCsROW nRow = 0;
583 SCsROW nEndRow;
584 while (bFound && nRow <= MAXROW)
586 bFound = aCol[i].SearchStyleRange( nRow, nEndRow, pSearchStyle, bBack, bSelect, rMark );
587 if (bFound)
589 if (nEndRow<nRow)
591 SCsROW nTemp = nRow;
592 nRow = nEndRow;
593 nEndRow = nTemp;
595 aNewMark.SetMultiMarkArea( ScRange( i,nRow,nTab, i,nEndRow,nTab ) );
596 nRow = nEndRow + 1;
601 rMark = aNewMark; // Markierung kopieren
602 //! pro Tabelle
604 return (aNewMark.IsMultiMarked());
607 BOOL ScTable::ReplaceAllStyle(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
608 ScDocument* pUndoDoc)
610 BOOL bRet = SearchAllStyle(rSearchItem, rMark);
611 if (bRet)
613 const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
614 pDocument->GetStyleSheetPool()->Find(
615 rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
617 if (pReplaceStyle)
619 if (pUndoDoc)
620 pDocument->CopyToDocument( 0,0,nTab, MAXCOL,MAXROW,nTab,
621 IDF_ATTRIB, TRUE, pUndoDoc, &rMark );
622 ApplySelectionStyle( *pReplaceStyle, rMark );
624 else
626 DBG_ERROR("pReplaceStyle==0");
630 return bRet;
633 BOOL ScTable::SearchAndReplace(const SvxSearchItem& rSearchItem,
634 SCCOL& rCol, SCROW& rRow, ScMarkData& rMark,
635 String& rUndoStr, ScDocument* pUndoDoc)
637 USHORT nCommand = rSearchItem.GetCommand();
638 BOOL bFound = FALSE;
639 if ( ValidColRow(rCol, rRow) ||
640 ((nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE) &&
641 (((rCol == MAXCOLCOUNT || rCol == -1) && VALIDROW(rRow)) ||
642 ((rRow == MAXROWCOUNT || rRow == -1) && VALIDCOL(rCol))
647 BOOL bStyles = rSearchItem.GetPattern();
648 if (bStyles)
650 if (nCommand == SVX_SEARCHCMD_FIND)
651 bFound = SearchStyle(rSearchItem, rCol, rRow, rMark);
652 else if (nCommand == SVX_SEARCHCMD_REPLACE)
653 bFound = ReplaceStyle(rSearchItem, rCol, rRow, rMark, FALSE);
654 else if (nCommand == SVX_SEARCHCMD_FIND_ALL)
655 bFound = SearchAllStyle(rSearchItem, rMark);
656 else if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
657 bFound = ReplaceAllStyle(rSearchItem, rMark, pUndoDoc);
659 else
661 // SearchParam no longer needed - SearchOptions contains all settings
662 com::sun::star::util::SearchOptions aSearchOptions = rSearchItem.GetSearchOptions();
663 aSearchOptions.Locale = *ScGlobal::pLocale;
665 if (!aSearchOptions.searchString.getLength())
667 // Search for empty cells.
668 return SearchAndReplaceEmptyCells(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
671 // #107259# reflect UseAsianOptions flag in SearchOptions
672 // (use only ignore case and width if asian options are disabled).
673 // This is also done in SvxSearchDialog CommandHdl, but not in API object.
674 if ( !rSearchItem.IsUseAsianOptions() )
675 aSearchOptions.transliterateFlags &=
676 ( com::sun::star::i18n::TransliterationModules_IGNORE_CASE |
677 com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
679 pSearchText = new utl::TextSearch( aSearchOptions );
681 if (nCommand == SVX_SEARCHCMD_FIND)
682 bFound = Search(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
683 else if (nCommand == SVX_SEARCHCMD_FIND_ALL)
684 bFound = SearchAll(rSearchItem, rMark, rUndoStr, pUndoDoc);
685 else if (nCommand == SVX_SEARCHCMD_REPLACE)
686 bFound = Replace(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
687 else if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
688 bFound = ReplaceAll(rSearchItem, rMark, rUndoStr, pUndoDoc);
690 delete pSearchText;
691 pSearchText = NULL;
694 return bFound;
697 bool ScTable::SearchAndReplaceEmptyCells(
698 const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, ScMarkData& rMark,
699 String& rUndoStr, ScDocument* pUndoDoc)
701 SCCOL nColStart, nColEnd;
702 SCROW nRowStart, nRowEnd;
703 GetFirstDataPos(nColStart, nRowStart);
704 GetLastDataPos(nColEnd, nRowEnd);
706 ScRangeList aRanges;
707 aRanges.Append(ScRange(nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab));
709 if (rSearchItem.GetSelection())
711 // current selection only.
712 if (!rMark.IsMarked() && !rMark.IsMultiMarked())
713 // There is no selection. Bail out.
714 return false;
716 ScRangeList aMarkedRanges, aNewRanges;
717 rMark.FillRangeListWithMarks(&aMarkedRanges, true);
718 for (ScRangePtr p = aMarkedRanges.First(); p; p = aMarkedRanges.Next())
720 if (p->aStart.Col() > nColEnd || p->aStart.Row() > nRowEnd)
721 // This range is outside the data area. Skip it.
722 continue;
724 // Shrink the range into data area only.
725 if (p->aStart.Col() < nColStart)
726 p->aStart.SetCol(rCol);
727 if (p->aStart.Row() < nRowStart)
728 p->aStart.SetRow(rRow);
730 if (p->aEnd.Col() > nColEnd)
731 p->aEnd.SetCol(nColEnd);
732 if (p->aEnd.Row() > nRowEnd)
733 p->aEnd.SetRow(nRowEnd);
735 aNewRanges.Append(*p);
737 aRanges = aNewRanges;
740 sal_uInt16 nCommand = rSearchItem.GetCommand();
741 if (nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE)
743 if (rSearchItem.GetBackward())
745 for (ScRangePtr p = aRanges.Last(); p; p = aRanges.Prev())
747 if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr, pUndoDoc))
748 return true;
751 else
753 for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next())
755 if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr, pUndoDoc))
756 return true;
760 else if (nCommand == SVX_SEARCHCMD_FIND_ALL || nCommand == SVX_SEARCHCMD_REPLACE_ALL)
762 bool bFound = false;
763 ScMarkData aNewMark(rMark);
764 aNewMark.ResetMark();
765 for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next())
766 bFound |= SearchRangeForAllEmptyCells(*p, rSearchItem, aNewMark, rUndoStr, pUndoDoc);
767 rMark = aNewMark;
768 return bFound;
770 return false;
773 bool ScTable::SearchRangeForEmptyCell(
774 const ScRange& rRange, const SvxSearchItem& rSearchItem,
775 SCCOL& rCol, SCROW& rRow, String& rUndoStr, ScDocument* /*pUndoDoc*/)
777 sal_uInt16 nCmd = rSearchItem.GetCommand();
778 if (rSearchItem.GetBackward())
780 // backward search
781 if (rSearchItem.GetRowDirection())
783 // row direction.
784 SCROW nBeginRow = rRange.aEnd.Row() > rRow ? rRow : rRange.aEnd.Row();
785 for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
787 SCCOL nBeginCol = rRange.aEnd.Col();
788 if (nRow == rRow && nBeginCol >= rCol)
789 // always start from one cell before the cursor.
790 nBeginCol = rCol - (nCmd == SVX_SEARCHCMD_FIND) ? 1 : 0;
792 for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
794 ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
795 if (!pCell)
797 // empty cell found.
798 rCol = nCol;
799 rRow = nRow;
800 if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
801 rSearchItem.GetReplaceString().Len())
803 aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
804 rUndoStr = String();
806 return true;
811 else
813 // column direction.
814 SCCOL nBeginCol = rRange.aEnd.Col() > rCol ? rCol : rRange.aEnd.Col();
815 for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol)
817 SCROW nBeginRow = rRange.aEnd.Row();
818 if (nCol == rCol && nBeginRow >= rRow)
819 // always start from one cell before the cursor.
820 nBeginRow = rRow - (nCmd == SVX_SEARCHCMD_FIND) ? 1 : 0;
821 for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow)
823 ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
824 if (!pCell)
826 // empty cell found.
827 rCol = nCol;
828 rRow = nRow;
829 if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
830 rSearchItem.GetReplaceString().Len())
832 aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
833 rUndoStr = String();
835 return true;
841 else
843 // forward search
844 if (rSearchItem.GetRowDirection())
846 // row direction.
847 SCROW nBeginRow = rRange.aStart.Row() < rRow ? rRow : rRange.aStart.Row();
848 for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
850 SCCOL nBeginCol = rRange.aStart.Col();
851 if (nRow == rRow && nBeginCol <= rCol)
852 // always start from one cell past the cursor.
853 nBeginCol = rCol + (nCmd == SVX_SEARCHCMD_FIND) ? 1 : 0;
854 for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
856 ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
857 if (!pCell)
859 // empty cell found.
860 rCol = nCol;
861 rRow = nRow;
862 if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
863 rSearchItem.GetReplaceString().Len())
865 aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
866 rUndoStr = String();
868 return true;
873 else
875 // column direction.
876 SCCOL nBeginCol = rRange.aStart.Col() < rCol ? rCol : rRange.aStart.Col();
877 for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol)
879 SCROW nBeginRow = rRange.aStart.Row();
880 if (nCol == rCol && nBeginRow <= rRow)
881 // always start from one cell past the cursor.
882 nBeginRow = rRow + (nCmd == SVX_SEARCHCMD_FIND) ? 1 : 0;
883 for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow)
885 ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
886 if (!pCell)
888 // empty cell found.
889 rCol = nCol;
890 rRow = nRow;
891 if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
892 rSearchItem.GetReplaceString().Len())
894 aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
895 rUndoStr = String();
897 return true;
903 return false;
906 bool ScTable::SearchRangeForAllEmptyCells(
907 const ScRange& rRange, const SvxSearchItem& rSearchItem, ScMarkData& rMark,
908 String& rUndoStr, ScDocument* pUndoDoc)
910 bool bFound = false;
911 bool bReplace = (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) &&
912 (rSearchItem.GetReplaceString().Len() > 0);
914 for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
916 if (aCol[nCol].IsEmptyData())
918 // The entire column is empty. Add the whole column and move on.
919 rMark.SetMultiMarkArea(
920 ScRange(nCol, rRange.aStart.Row(), nTab, nCol, rRange.aEnd.Row(), nTab));
921 bFound = true;
923 if (bReplace)
925 const String& rNewStr = rSearchItem.GetReplaceString();
926 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
928 aCol[nCol].Insert(nRow, new ScStringCell(rNewStr));
929 if (pUndoDoc)
930 // TODO: I'm using a string cell with empty content to
931 // trigger deletion of cell instance on undo. Maybe I
932 // should create a new cell type for this?
933 pUndoDoc->PutCell(nCol, nRow, nTab, new ScStringCell(String()));
935 rUndoStr = String();
937 continue;
940 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
942 ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
943 if (!pCell)
945 // empty cell found
946 rMark.SetMultiMarkArea(ScRange(nCol, nRow, nTab));
947 bFound = true;
949 if (bReplace)
951 aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
952 if (pUndoDoc)
953 // TODO: I'm using a string cell with empty content to
954 // trigger deletion of cell instance on undo. Maybe I
955 // should create a new cell type for this?
956 pUndoDoc->PutCell(nCol, nRow, nTab, new ScStringCell(String()));
961 return bFound;