/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
bool bRepeat = !rSearchItem.GetWordOnly(); do
{ // don't continue search if the found text is empty, // otherwise it would never stop (#35410#) if ( nEnd < nStart )
bRepeat = false;
SCROW nLastRow = rRow; if (RowFiltered(rRow, nullptr, &nLastRow)) // move to the first non-filtered row.
rRow = nLastRow + 1; else // record the last non-filtered row to avoid checking // the filtered state for each and every row.
rLastNonFilteredRow = nLastRow;
} else
{ // backward search
if (rRow >= rLastNonFilteredRow) return;
SCROW nFirstRow = rRow; if (RowFiltered(rRow, &nFirstRow)) // move to the first non-filtered row.
rRow = nFirstRow - 1; else // record the last non-filtered row to avoid checking // the filtered state for each and every row.
rLastNonFilteredRow = nFirstRow;
}
}
bool bSkipFiltered = !rSearchItem.IsSearchFiltered(); bool bSearchNotes = (rSearchItem.GetCellType() == SvxSearchCellType::NOTE); // We need to cache sc::ColumnBlockConstPosition per each column. if (static_cast<SCCOL>(blockPos.size()) != nLastCol + 1)
{
blockPos.resize( nLastCol + 1 ); for( SCCOL i = 0; i <= nLastCol; ++i )
aCol[ i ].InitBlockPosition( blockPos[ i ] );
} if (!bAll && rSearchItem.GetBackward())
{
SCROW nLastNonFilteredRow = rDocument.MaxRow() + 1; if (rSearchItem.GetRowDirection())
{
nCol--;
nCol = std::min(nCol, nLastCol);
nRow = std::min(nRow, nLastRow); while (!bFound && (nRow >= 0))
{ if (bSkipFiltered)
SkipFilteredRows(nRow, nLastNonFilteredRow, false);
while (!bFound && (nCol >= 0))
{
bFound = SearchCell(rSearchItem, nCol, blockPos[ nCol ], nRow,
rMark, rUndoStr, pUndoDoc); if (!bFound)
{ bool bIsEmpty; do
{
nCol--; if (nCol >= 0)
{ if (bSearchNotes)
bIsEmpty = !aCol[nCol].HasCellNotes(); else
bIsEmpty = aCol[nCol].IsEmptyData();
} else
bIsEmpty = true;
} while ((nCol >= 0) && bIsEmpty);
}
} if (!bFound)
{
nCol = nLastCol;
nRow--;
}
}
} else
{
nRow--;
nCol = std::min(nCol, nLastCol);
nRow = std::min(nRow, nLastRow); while (!bFound && (nCol >= 0))
{ while (!bFound && (nRow >= 0))
{ if (bSkipFiltered)
SkipFilteredRows(nRow, nLastNonFilteredRow, false);
bFound = SearchCell(rSearchItem, nCol, blockPos[ nCol ],
nRow, rMark, rUndoStr, pUndoDoc); if (!bFound)
{ if (bSearchNotes)
{ /* TODO: can we look for the previous cell note instead? */
--nRow;
} else
{ if (!aCol[nCol].GetPrevDataPos(nRow))
nRow = -1;
}
}
} if (!bFound)
{ // Not found in this column. Move to the next column. bool bIsEmpty;
nRow = nLastRow;
nLastNonFilteredRow = rDocument.MaxRow() + 1; do
{
nCol--; if (nCol >= 0)
{ if (bSearchNotes)
bIsEmpty = !aCol[nCol].HasCellNotes(); else
bIsEmpty = aCol[nCol].IsEmptyData();
} else
bIsEmpty = true;
} while ((nCol >= 0) && bIsEmpty);
}
}
}
} else
{
SCROW nLastNonFilteredRow = -1; if (rSearchItem.GetRowDirection())
{
nCol++; while (!bFound && (nRow <= nLastRow))
{ if (bSkipFiltered)
SkipFilteredRows(nRow, nLastNonFilteredRow, true);
while (!bFound && (nCol <= nLastCol))
{
bFound = SearchCell(rSearchItem, nCol, blockPos[ nCol ],
nRow, rMark, rUndoStr, pUndoDoc); if (!bFound)
{
nCol++; while ((nCol <= nLastCol) &&
(bSearchNotes ? !aCol[nCol].HasCellNotes() : aCol[nCol].IsEmptyData()))
nCol++;
}
} if (!bFound)
{
nCol = 0;
nRow++;
}
}
} else
{
nRow++; while (!bFound && (nCol <= nLastCol))
{ while (!bFound && (nRow <= nLastRow))
{ if (bSkipFiltered)
SkipFilteredRows(nRow, nLastNonFilteredRow, true);
// GetSearchAndReplaceStart sets a nCol of -1 for // ColDirection() only if rSearchItem.GetPattern() is true, // so a negative column shouldn't be possible here.
assert(nCol >= 0 && "negative nCol for ColDirection");
bFound = SearchCell(rSearchItem, nCol, blockPos[ nCol ],
nRow, rMark, rUndoStr, pUndoDoc); if (!bFound)
{ if (bSearchNotes)
{ /* TODO: can we look for the next cell note instead? */
++nRow;
} else
{ if (!aCol[nCol].GetNextDataPos(nRow))
nRow = rDocument.MaxRow() + 1;
}
}
} if (!bFound)
{ // Not found in this column. Move to the next column.
nRow = 0;
nLastNonFilteredRow = -1;
nCol++; while ((nCol <= nLastCol) &&
(bSearchNotes ? !aCol[nCol].HasCellNotes() : aCol[nCol].IsEmptyData()))
nCol++;
}
}
}
} if (bFound)
{
rCol = nCol;
rRow = nRow;
} return bFound;
}
if (bFound)
{
bEverFound = true; // The combination of this loop and the Join() algorithm is O(n^2), // so just give up if the list gets too big. if (rMatchedRanges.size() < 1000)
rMatchedRanges.Join(ScRange(nCol, nRow, nTab)); else
bMatchedRangesWereClamped = true;
} else break;
} return bEverFound;
}
// reflect UseAsianOptions flag in SearchOptions // (use only ignore case and width if asian options are disabled). // This is also done in SvxSearchDialog CommandHdl, but not in API object. if ( !rSearchItem.IsUseAsianOptions() )
aSearchOptions.transliterateFlags &=
TransliterationFlags::IGNORE_CASE |
TransliterationFlags::IGNORE_WIDTH;
pSearchText.reset( new utl::TextSearch( aSearchOptions ) );
if (rSearchItem.GetSelection())
{ // current selection only. if (!rMark.IsMarked() && !rMark.IsMultiMarked()) // There is no selection. Bail out. returnfalse;
ScRangeList aMarkedRanges, aNewRanges;
rMark.FillRangeListWithMarks(&aMarkedRanges, true); for ( size_t i = 0, n = aMarkedRanges.size(); i < n; ++i )
{
ScRange & rRange = aMarkedRanges[ i ]; if (rRange.aStart.Col() > nColEnd || rRange.aStart.Row() > nRowEnd || rRange.aEnd.Col() < nColStart || rRange.aEnd.Row() < nRowStart) // This range is outside the data area. Skip it. continue;
// Shrink the range into data area only. if (rRange.aStart.Col() < nColStart)
rRange.aStart.SetCol(nColStart); if (rRange.aStart.Row() < nRowStart)
rRange.aStart.SetRow(nRowStart);
if (rRange.aEnd.Col() > nColEnd)
rRange.aEnd.SetCol(nColEnd); if (rRange.aEnd.Row() > nRowEnd)
rRange.aEnd.SetRow(nRowEnd);
for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
{
SCROW nLastNonFilteredRow = -1; if (aCol[nCol].IsEmptyData())
{ // The entire column is empty. const SCROW nEndRow = rRange.aEnd.Row(); for (SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; ++nRow)
{
SCROW nLastRow; constbool bFiltered = RowFiltered(nRow, nullptr, &nLastRow); if (nLastRow > nEndRow)
nLastRow = nEndRow; if (!bFiltered)
{
rMatchedRanges.Join(ScRange(nCol, nRow, nTab, nCol, nLastRow, nTab)); if (bReplace)
{ const OUString& rNewStr = rSearchItem.GetReplaceString(); for (SCROW i = nRow; i <= nLastRow; ++i)
{
aCol[nCol].SetRawString(i, rNewStr); if (pUndoDoc)
{ // TODO: I'm using a string cell with empty content to // trigger deletion of cell instance on undo. Maybe I // should create a new cell type for this?
pUndoDoc->SetString(ScAddress(nCol, i, nTab), OUString());
}
}
rUndoStr.clear();
}
}
nRow = nLastRow; // move to the last filtered row.
}
bFound = true; continue;
}
for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
{ if (bSkipFiltered)
SkipFilteredRows(nRow, nLastNonFilteredRow, true); if (nRow > rRange.aEnd.Row()) break;
ScRefCellValue aCell = aCol[nCol].GetCellValue(nRow); if (aCell.isEmpty())
{ // empty cell found
rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
bFound = true;
if (bReplace)
{
aCol[nCol].SetRawString(nRow, rSearchItem.GetReplaceString()); if (pUndoDoc)
{ // TODO: I'm using a string cell with empty content to // trigger deletion of cell instance on undo. Maybe I // should create a new cell type for this?
pUndoDoc->SetString(ScAddress(nCol, nRow, nTab), OUString());
}
}
}
}
} return bFound;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.