/* -*- 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/.
*/
sc::MultiDataCellState ScDocument::HasMultipleDataCells( const ScRange& rRange ) const
{ if (rRange.aStart.Tab() != rRange.aEnd.Tab()) // Currently we only support a single-sheet range. return sc::MultiDataCellState();
const ScTable* pTab = FetchTable(rRange.aStart.Tab()); if (!pTab) return sc::MultiDataCellState(sc::MultiDataCellState::Empty);
const ScAddress& s = rRange.aStart; const ScAddress& e = rRange.aEnd; return pTab->HasMultipleDataCells(s.Col(), s.Row(), e.Col(), e.Row());
}
bool ScDocument::CopyOneCellFromClip(
sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
{
ScDocument* pClipDoc = rCxt.getClipDoc(); if (pClipDoc->GetClipParam().mbCutMode) // We don't handle cut and paste or moving of cells here. returnfalse;
ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange(); if (aClipRange.aStart.Row() != aClipRange.aEnd.Row()) // The source is not really a single row. Bail out. returnfalse;
if ((rCxt.getInsertFlag() & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)) != InsertDeleteFlags::NONE)
rCxt.setSingleCellNote(nColOffset, pClipDoc->GetNote(aSrcPos));
if ((rCxt.getInsertFlag() & InsertDeleteFlags::SPARKLINES) != InsertDeleteFlags::NONE)
rCxt.setSingleSparkline(nColOffset, pClipDoc->GetSparkline(aSrcPos));
ScColumn* pSrcCol = pSrcTab->FetchColumn(aSrcPos.Col());
assert(pSrcCol); // Determine the script type of the copied single cell.
pSrcCol->UpdateScriptTypes(aSrcPos.Row(), aSrcPos.Row());
rCxt.setSingleCell(aSrcPos, *pSrcCol);
}
// All good. Proceed with the pasting.
SCTAB nTabEnd = rCxt.getTabEnd(); for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < GetTableCount(); ++i)
{
maTabs[i]->CopyOneCellFromClip(rCxt, nCol1, nRow1, nCol2, nRow2, aClipRange.aStart.Row(), pSrcTab);
}
void ScDocument::PreprocessAllRangeNamesUpdate( const std::map<OUString, ScRangeName>& rRangeMap )
{ // Update all existing names with new names. // The prerequisites are that the name dialog preserves ScRangeData index // for changes and does not reuse free index slots for new names. // ScDocument::SetAllRangeNames() hereafter then will replace the // ScRangeName containers of ScRangeData instances with empty // ScRangeData::maNewName.
std::map<OUString, ScRangeName*> aRangeNameMap;
GetRangeNameMap( aRangeNameMap); for (constauto& itTab : aRangeNameMap)
{
ScRangeName* pOldRangeNames = itTab.second; if (!pOldRangeNames) continue;
constauto itNewTab( rRangeMap.find( itTab.first)); if (itNewTab == rRangeMap.end()) continue;
if (rIndexes.isNameUpdated( nTokenTab, nTokenIndex)) returntrue;
ScRangeData* pData = FindRangeNameBySheetAndIndex( nTokenTab, nTokenIndex); if (!pData) returnfalse;
ScTokenArray* pCode = pData->GetCode(); if (!pCode) returnfalse;
bool bRef = !bSameDoc; // include every name used when copying to other doc if (nRecursion < 126) // whatever... 42*3
{
formula::FormulaTokenArrayPlainIterator aIter(*pCode); for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
{ if (p->GetOpCode() == ocName)
{
bRef |= FindRangeNamesReferencingSheet( rIndexes, p->GetSheet(), p->GetIndex(),
nGlobalRefTab, nLocalRefTab, nOldTokenTab, nOldTokenTabReplacement, bSameDoc, nRecursion+1);
}
}
}
if (!bRef)
{
SCTAB nPosTab = pData->GetPos().Tab(); if (nPosTab == nOldTokenTab)
nPosTab = nOldTokenTabReplacement;
bRef = pCode->ReferencesSheet( nRefTab, nPosTab);
} if (bRef)
rIndexes.setUpdatedName( nTokenTab, nTokenIndex);
return bRef;
}
namespace {
enum MightReferenceSheet
{
UNKNOWN,
NONE,
CODE,
NAME
};
formula::FormulaTokenArrayPlainIterator aIter(*pCode); for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
{ if (p->GetOpCode() == ocName) return MightReferenceSheet::NAME;
}
SheetIndex( SCTAB nSheet, sal_uInt16 nIndex ) : mnSheet(nSheet < -1 ? -1 : nSheet), mnIndex(nIndex) {} booloperator<( const SheetIndex& r ) const
{ // Ascending order sheet, index if (mnSheet < r.mnSheet) returntrue; if (mnSheet == r.mnSheet) return mnIndex < r.mnIndex; returnfalse;
}
}; typedef std::map< SheetIndex, SheetIndex > SheetIndexMap;
ScRangeData* copyRangeNames( SheetIndexMap& rSheetIndexMap, std::vector<ScRangeData*>& rRangeDataVec, const sc::UpdatedRangeNames& rReferencingNames, SCTAB nTab, const ScRangeData* pOldRangeData, ScDocument& rNewDoc, const ScDocument& rOldDoc, const ScAddress& rNewPos, const ScAddress& rOldPos, bool bGlobalNamesToLocal, const SCTAB nOldSheet, const SCTAB nNewSheet, bool bSameDoc)
{
ScRangeData* pRangeData = nullptr; const ScRangeName* pOldRangeName = (nTab < 0 ? rOldDoc.GetRangeName() : rOldDoc.GetRangeName(nTab)); if (pOldRangeName)
{ const ScRangeName* pNewRangeName = (nNewSheet < 0 ? rNewDoc.GetRangeName() : rNewDoc.GetRangeName(nNewSheet));
sc::UpdatedRangeNames::NameIndicesType aSet( rReferencingNames.getUpdatedNames(nTab)); for (autoconst & rIndex : aSet)
{ const ScRangeData* pCopyData = pOldRangeName->findByIndex(rIndex); if (pCopyData)
{ // Match the original pOldRangeData to adapt the current // token's values later. For that no check for an already // copied name is needed as we only enter here if there was // none. if (pCopyData == pOldRangeData)
{
pRangeData = copyRangeName( pCopyData, rNewDoc, rOldDoc, rNewPos, rOldPos,
bGlobalNamesToLocal, nOldSheet, nNewSheet, bSameDoc); if (pRangeData)
{
rRangeDataVec.push_back(pRangeData);
rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()),
SheetIndex( nNewSheet, pRangeData->GetIndex())));
}
} else
{ // First check if the name is already available as copy. const ScRangeData* pFoundData = pNewRangeName->findByUpperName( pCopyData->GetUpperName()); if (pFoundData)
{ // Just add the resulting sheet/index mapping.
rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()),
SheetIndex( nNewSheet, pFoundData->GetIndex())));
} else
{
ScRangeData* pTmpData = copyRangeName( pCopyData, rNewDoc, rOldDoc, rNewPos, rOldPos,
bGlobalNamesToLocal, nOldSheet, nNewSheet, bSameDoc); if (pTmpData)
{
rRangeDataVec.push_back(pTmpData);
rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()),
SheetIndex( nNewSheet, pTmpData->GetIndex())));
}
}
}
}
}
} return pRangeData;
}
} // namespace
bool ScDocument::CopyAdjustRangeName( SCTAB& rSheet, sal_uInt16& rIndex, ScRangeData*& rpRangeData,
ScDocument& rNewDoc, const ScAddress& rNewPos, const ScAddress& rOldPos, constbool bGlobalNamesToLocal, constbool bUsedByFormula ) const
{
ScDocument* pThis = const_cast<ScDocument*>(this); constbool bSameDoc = (rNewDoc.GetPool() == pThis->GetPool()); if (bSameDoc && ((rSheet < 0 && !bGlobalNamesToLocal) || (rSheet >= 0
&& (rSheet != rOldPos.Tab() || (IsClipboard() && pThis->IsCutMode()))))) // Same doc and global name, if not copied to local name, or // sheet-local name on other sheet stays the same. Sheet-local on // same sheet also in a clipboard cut&paste / move operation. returnfalse;
// Ensure we don't fiddle with the references until exit. const SCTAB nOldSheet = rSheet; const sal_uInt16 nOldIndex = rIndex;
SAL_WARN_IF( !bSameDoc && nOldSheet >= 0 && nOldSheet != rOldPos.Tab(), "sc.core", "adjustCopyRangeName - sheet-local name was on other sheet in other document"); /* TODO: can we do something about that? e.g. loop over sheets? */
// XXX bGlobalNamesToLocal is also a synonym for copied sheet. bool bInsertingBefore = (bGlobalNamesToLocal && bSameDoc && rNewPos.Tab() <= rOldPos.Tab());
// The Tab where an old local name is to be found or that a global name // references. May differ below from nOldSheet if a sheet was inserted // before the old position. Global names and local names other than on the // old sheet or new sheet are already updated, local names on the old sheet // or inserted sheet will be updated later. Confusing stuff. Watch out.
SCTAB nOldTab = (nOldSheet < 0 ? rOldPos.Tab() : nOldSheet); if (bInsertingBefore) // Sheet was already inserted before old position.
++nOldTab;
// Search the name of the RangeName. if (nOldSheet >= 0)
{ const ScRangeName* pNames = GetRangeName(nOldTab);
pOldRangeData = pNames ? pNames->findByIndex(nOldIndex) : nullptr; if (!pOldRangeData) returnfalse; // might be an error in the formula array
aRangeName = pOldRangeData->GetUpperName();
} else
{
pOldRangeData = GetRangeName()->findByIndex(nOldIndex); if (!pOldRangeData) returnfalse; // might be an error in the formula array
aRangeName = pOldRangeData->GetUpperName();
}
// Find corresponding range name in new document. // First search for local range name then global range names.
SCTAB nNewSheet = rNewPos.Tab();
ScRangeName* pNewNames = rNewDoc.GetRangeName(nNewSheet); // Search local range names. if (pNewNames)
{
rpRangeData = pNewNames->findByUpperName(aRangeName);
} // Search global range names. if (!rpRangeData && !bGlobalNamesToLocal)
{
nNewSheet = -1;
pNewNames = rNewDoc.GetRangeName(); if (pNewNames)
rpRangeData = pNewNames->findByUpperName(aRangeName);
} // If no range name was found copy it. if (!rpRangeData)
{ // Do not copy global name if it doesn't reference sheet or is not used // by a formula copied to another document. bool bEarlyBailOut = (nOldSheet < 0 && (bSameDoc || !bUsedByFormula));
MightReferenceSheet eMightReference = mightRangeNameReferenceSheet( pOldRangeData, nOldTab); if (bEarlyBailOut && eMightReference == MightReferenceSheet::NONE) returnfalse;
if (eMightReference == MightReferenceSheet::NAME)
{ // Name these to clarify what is passed where. const SCTAB nGlobalRefTab = nOldTab; const SCTAB nLocalRefTab = (bInsertingBefore ? nOldTab-1 : nOldTab); const SCTAB nOldTokenTab = (nOldSheet < 0 ? (bInsertingBefore ? nOldTab-1 : nOldTab) : nOldSheet); const SCTAB nOldTokenTabReplacement = nOldTab;
sc::UpdatedRangeNames aReferencingNames;
FindRangeNamesReferencingSheet( aReferencingNames, nOldSheet, nOldIndex,
nGlobalRefTab, nLocalRefTab, nOldTokenTab, nOldTokenTabReplacement, bSameDoc, 0); if (bEarlyBailOut && aReferencingNames.isEmpty(-1) && aReferencingNames.isEmpty(nOldTokenTabReplacement)) returnfalse;
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.